:: commit dc54ee97ebc3d10ad11cd4ea1f7ee6c3134b04f5

mintsuki <mintsuki@protonmail.com> — 2020-11-16 22:31

parents: 970b4e3fc9

config: Add initial support for config directory entries

diff --git a/Makefile b/Makefile
index 5f8afdd3..1ffdf5cc 100644
--- a/Makefile
+++ b/Makefile
@@ -49,8 +49,9 @@ echfs-test: limine-install test.img
 	sed "s/@GUID@/`cat part_guid`/g" < test/limine.cfg > limine.cfg.tmp
 	echfs-utils -m -p0 test.img import limine.cfg.tmp limine.cfg
 	rm -f limine.cfg.tmp part_guid
+	echfs-utils -m -p0 test.img import stage2.map boot/stage2.map
 	echfs-utils -m -p0 test.img import test/test.elf boot/test.elf
-	echfs-utils -m -p0 test.img import test/bg.bmp bg.bmp
+	echfs-utils -m -p0 test.img import test/bg.bmp boot/bg.bmp
 	./limine-install limine.bin test.img
 	qemu-system-x86_64 -net none -smp 4 -enable-kvm -cpu host -hda test.img -debugcon stdio
 
diff --git a/limine-pxe.bin b/limine-pxe.bin
index ff180440..396e2d4c 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index b04497a2..fc6c3d94 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2.map b/stage2.map
index 6b046cfd..b5f4804a 100644
Binary files a/stage2.map and b/stage2.map differ
diff --git a/stage2/drivers/vbe.c b/stage2/drivers/vbe.c
index 7142e76c..b1956e8b 100644
--- a/stage2/drivers/vbe.c
+++ b/stage2/drivers/vbe.c
@@ -322,7 +322,7 @@ bool vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _
 
     int req_width = 0, req_height = 0, req_bpp = 0;
 
-    if (config_get_value(buf, 0, 32, "MENU_RESOLUTION"))
+    if (config_get_value(NULL, buf, 0, 32, "MENU_RESOLUTION"))
         parse_resolution(&req_width, &req_height, &req_bpp, buf);
 
     // We force bpp to 32
diff --git a/stage2/lib/config.c b/stage2/lib/config.c
index 871f076c..4fc70c92 100644
--- a/stage2/lib/config.c
+++ b/stage2/lib/config.c
@@ -8,6 +8,8 @@
 #include <lib/print.h>
 #include <pxe/tftp.h>
 
+#include <sys/cpu.h>
+
 #define SEPARATOR '\n'
 
 bool config_ready = false;
@@ -44,6 +46,81 @@ int init_config_pxe(void) {
     return init_config(cfg.file_size);
 }
 
+#define NOT_CHILD      (-1)
+#define DIRECT_CHILD   0
+#define INDIRECT_CHILD 1
+
+static int is_child(char *buf, size_t limit,
+                    size_t current_depth, size_t index) {
+    if (!config_get_entry_name(buf, index, limit))
+        return NOT_CHILD;
+    if (strlen(buf) < current_depth + 1)
+        return NOT_CHILD;
+    for (size_t j = 0; j < current_depth; j++)
+        if (buf[j] != ':')
+            return NOT_CHILD;
+    if (buf[current_depth] == ':')
+        return INDIRECT_CHILD;
+    return DIRECT_CHILD;
+}
+
+static bool is_directory(char *buf, size_t limit,
+                         size_t current_depth, size_t index) {
+    switch (is_child(buf, limit, current_depth + 1, index + 1)) {
+        default:
+        case NOT_CHILD:
+            return false;
+        case INDIRECT_CHILD:
+            panic("config: Malformed config file. Parentless child.");
+        case DIRECT_CHILD:
+            return true;
+    }
+}
+
+static struct menu_entry *create_menu_tree(struct menu_entry *parent,
+                                           size_t current_depth, size_t index) {
+    struct menu_entry *root = NULL, *prev = NULL;
+
+    for (size_t i = index; ; i++) {
+        static char name[64];
+
+        switch (is_child(name, 64, current_depth, i)) {
+            case NOT_CHILD:
+                return root;
+            case INDIRECT_CHILD:
+                continue;
+            case DIRECT_CHILD:
+                break;
+        }
+
+        struct menu_entry *entry = conv_mem_alloc(sizeof(struct menu_entry));
+
+        if (root == NULL)
+            root = entry;
+
+        config_get_entry_name(name, i, 64);
+
+        strcpy(entry->name, name + current_depth);
+        entry->parent = parent;
+
+        if (is_directory(name, 64, current_depth, i)) {
+            entry->sub = create_menu_tree(entry, current_depth + 1, i + 1);
+        } else {
+            size_t entry_size;
+            char *config_entry = config_get_entry(&entry_size, i);
+            entry->body = conv_mem_alloc(entry_size + 1);
+            memcpy(entry->body, config_entry, entry_size);
+            entry->body[entry_size] = 0;
+        }
+
+        if (prev != NULL)
+            prev->next = entry;
+        prev = entry;
+    }
+}
+
+struct menu_entry *menu_tree = NULL;
+
 int init_config(size_t config_size) {
     // remove windows carriage returns, if any
     for (size_t i = 0; i < config_size; i++) {
@@ -54,18 +131,20 @@ int init_config(size_t config_size) {
         }
     }
 
+    menu_tree = create_menu_tree(NULL, 1, 0);
+
     config_ready = true;
 
     return 0;
 }
 
-int config_get_entry_name(char *ret, size_t index, size_t limit) {
+bool config_get_entry_name(char *ret, size_t index, size_t limit) {
     char *p = config_addr;
 
     for (size_t i = 0; i <= index; i++) {
         while (*p != ':') {
             if (!*p)
-                return -1;
+                return false;
             p++;
         }
         p++;
@@ -73,6 +152,8 @@ int config_get_entry_name(char *ret, size_t index, size_t limit) {
             i--;
     }
 
+    p--;
+
     size_t i;
     for (i = 0; i < (limit - 1); i++) {
         if (p[i] == SEPARATOR)
@@ -81,16 +162,17 @@ int config_get_entry_name(char *ret, size_t index, size_t limit) {
     }
 
     ret[i] = 0;
-    return 0;
+    return true;
 }
 
-int config_set_entry(size_t index) {
+char *config_get_entry(size_t *size, size_t index) {
+    char *ret;
     char *p = config_addr;
 
     for (size_t i = 0; i <= index; i++) {
         while (*p != ':') {
             if (!*p)
-                return -1;
+                return NULL;
             p++;
         }
         p++;
@@ -98,7 +180,11 @@ int config_set_entry(size_t index) {
             i--;
     }
 
-    config_addr = p;
+    do {
+        p++;
+    } while (*p != '\n');
+
+    ret = p;
 
 cont:
     while (*p != ':' && *p)
@@ -109,29 +195,33 @@ cont:
         goto cont;
     }
 
-    *p = 0;
+    *size = p - ret;
 
-    return 0;
+    return ret;
 }
 
-char *config_get_value(char *buf, size_t index, size_t limit, const char *key) {
+char *config_get_value(const char *config,
+                       char *buf, size_t index, size_t limit, const char *key) {
     if (!limit || !buf || !key)
         return NULL;
 
+    if (config == NULL)
+        config = config_addr;
+
     size_t key_len = strlen(key);
 
-    for (size_t i = 0; config_addr[i]; i++) {
-        if (!strncmp(&config_addr[i], key, key_len) && config_addr[i + key_len] == '=') {
-            if (i && config_addr[i - 1] != SEPARATOR)
+    for (size_t i = 0; config[i]; i++) {
+        if (!strncmp(&config[i], key, key_len) && config[i + key_len] == '=') {
+            if (i && config[i - 1] != SEPARATOR)
                 continue;
             if (index--)
                 continue;
             i += key_len + 1;
             size_t j;
-            for (j = 0; config_addr[i + j] != SEPARATOR && config_addr[i + j]; j++) {
+            for (j = 0; config[i + j] != SEPARATOR && config[i + j]; j++) {
                 if (j == limit - 1)
                     break;
-                buf[j] = config_addr[i + j];
+                buf[j] = config[i + j];
             }
             buf[j] = 0;
             return buf;
diff --git a/stage2/lib/config.h b/stage2/lib/config.h
index 26fd561e..49eb2036 100644
--- a/stage2/lib/config.h
+++ b/stage2/lib/config.h
@@ -7,11 +7,23 @@
 
 extern bool config_ready;
 
+struct menu_entry {
+    char name[64];
+    struct menu_entry *parent;
+    struct menu_entry *sub;
+    bool expanded;
+    char *body;
+    struct menu_entry *next;
+};
+
+extern struct menu_entry *menu_tree;
+
 int init_config_disk(struct part *part);
 int init_config_pxe(void);
 int init_config(size_t config_size);
-int config_get_entry_name(char *ret, size_t index, size_t limit);
-int config_set_entry(size_t index);
-char *config_get_value(char *buf, size_t index, size_t limit, const char *key);
+bool config_get_entry_name(char *ret, size_t index, size_t limit);
+char *config_get_entry(size_t *size, size_t index);
+char *config_get_value(const char *config,
+                       char *buf, size_t index, size_t limit, const char *key);
 
 #endif
diff --git a/stage2/lib/print.c b/stage2/lib/print.c
index e4b1a91c..0c4bf844 100644
--- a/stage2/lib/print.c
+++ b/stage2/lib/print.c
@@ -119,7 +119,7 @@ static char print_buf[PRINT_BUF_MAX];
 
 void vprint(const char *fmt, va_list args) {
     if (config_ready && e9_output == -1) {
-        e9_output = config_get_value(print_buf, 0, PRINT_BUF_MAX, "E9_OUTPUT") &&
+        e9_output = config_get_value(NULL, print_buf, 0, PRINT_BUF_MAX, "E9_OUTPUT") &&
                     !strcmp(print_buf, "yes");
     }
 
diff --git a/stage2/lib/trace.c b/stage2/lib/trace.c
index 1e392678..5ecfe369 100644
--- a/stage2/lib/trace.c
+++ b/stage2/lib/trace.c
@@ -12,7 +12,7 @@ static char *stage2_map = NULL;
 
 void trace_init(void) {
     char map_filename[80];
-    if (!config_get_value(map_filename, 0, 80, "STAGE2_MAP"))
+    if (!config_get_value(NULL, map_filename, 0, 80, "STAGE2_MAP"))
         return;
 
     struct file_handle stage2_map_file;
diff --git a/stage2/main.c b/stage2/main.c
index a2f2bb1f..c2757af2 100644
--- a/stage2/main.c
+++ b/stage2/main.c
@@ -70,21 +70,22 @@ void entry(uint8_t _boot_drive, int pxe_boot) {
 
     trace_init();
 
-    char *cmdline = menu();
+    char *cmdline;
+    char *config = menu(&cmdline);
 
     char proto[32];
-    if (!config_get_value(proto, 0, 32, "PROTOCOL")) {
+    if (!config_get_value(config, proto, 0, 32, "PROTOCOL")) {
         panic("PROTOCOL not specified");
     }
 
     if (!strcmp(proto, "stivale")) {
-        stivale_load(cmdline);
+        stivale_load(config, cmdline);
     } else if (!strcmp(proto, "stivale2")) {
-        stivale2_load(cmdline);
+        stivale2_load(config, cmdline);
     } else if (!strcmp(proto, "linux")) {
-        linux_load(cmdline);
+        linux_load(config, cmdline);
     } else if (!strcmp(proto, "chainload")) {
-        chainload();
+        chainload(config);
     } else {
         panic("Invalid protocol specified");
     }
diff --git a/stage2/menu.c b/stage2/menu.c
index cc31c4bb..b39520b8 100644
--- a/stage2/menu.c
+++ b/stage2/menu.c
@@ -16,20 +16,50 @@
 static char *cmdline;
 #define CMDLINE_MAX 1024
 
-static char config_entry_name[1024];
+static int print_tree(int level, int base_index, int selected_entry,
+                         struct menu_entry *current_entry,
+                         struct menu_entry **selected_menu_entry) {
+    int max_entries = 0;
+    for (;;) {
+        if (current_entry == NULL)
+            break;
+        for (int i = 0; i < level; i++)
+            print("  ");
+        if (current_entry->sub)
+            print(current_entry->expanded ? "[-] " : "[+] ");
+        else
+            print("    ");
+        if (base_index + max_entries == selected_entry) {
+            *selected_menu_entry = current_entry;
+            print("\e[47m\e[30m");
+        }
+        print(" %s \e[0m\n", current_entry->name);
+        if (current_entry->sub && current_entry->expanded) {
+            max_entries += print_tree(level + 1, base_index + max_entries + 1,
+                                      selected_entry,
+                                      current_entry->sub,
+                                      selected_menu_entry);
+        }
+        max_entries++;
+        current_entry = current_entry->next;
+    }
+    return max_entries;
+}
 
-char *menu(void) {
+char *menu(char **cmdline_ret) {
     cmdline = conv_mem_alloc(CMDLINE_MAX);
 
     char *buf = conv_mem_alloc(256);
 
+    struct menu_entry *selected_menu_entry;
+
     int selected_entry = 0;
-    if (config_get_value(buf, 0, 16, "DEFAULT_ENTRY")) {
+    if (config_get_value(NULL, buf, 0, 16, "DEFAULT_ENTRY")) {
         selected_entry = (int)strtoui(buf, NULL, 10);
     }
 
     int timeout = 5;
-    if (config_get_value(buf, 0, 16, "TIMEOUT")) {
+    if (config_get_value(NULL, buf, 0, 16, "TIMEOUT")) {
         timeout = (int)strtoui(buf, NULL, 10);
     }
 
@@ -37,7 +67,7 @@ char *menu(void) {
         goto autoboot;
 
     // If there is GRAPHICS config key and the value is "yes", enable graphics
-    if (config_get_value(buf, 0, 16, "GRAPHICS") && !strcmp(buf, "yes")) {
+    if (config_get_value(NULL, buf, 0, 16, "GRAPHICS") && !strcmp(buf, "yes")) {
         // default scheme
         int margin = 64;
         int margin_gradient = 20;
@@ -52,8 +82,8 @@ char *menu(void) {
             0x00aaaaaa  // grey
         };
 
-        if (config_get_value(buf, 0, 256, "THEME_COLOURS")
-         || config_get_value(buf, 0, 256, "THEME_COLORS")) {
+        if (config_get_value(NULL, buf, 0, 256, "THEME_COLOURS")
+         || config_get_value(NULL, buf, 0, 256, "THEME_COLORS")) {
             const char *first = buf;
             for (int i = 0; i < 8; i++) {
                 const char *last;
@@ -67,15 +97,15 @@ char *menu(void) {
             }
         }
 
-        if (config_get_value(buf, 0, 16, "THEME_MARGIN")) {
+        if (config_get_value(NULL, buf, 0, 16, "THEME_MARGIN")) {
             margin = (int)strtoui(buf, NULL, 10);
         }
 
-        if (config_get_value(buf, 0, 16, "THEME_MARGIN_GRADIENT")) {
+        if (config_get_value(NULL, buf, 0, 16, "THEME_MARGIN_GRADIENT")) {
             margin_gradient = (int)strtoui(buf, NULL, 10);
         }
 
-        if (!config_get_value(cmdline, 0, CMDLINE_MAX, "BACKGROUND_PATH"))
+        if (!config_get_value(NULL, cmdline, 0, CMDLINE_MAX, "BACKGROUND_PATH"))
             goto nobg;
 
         struct file_handle *bg_file = conv_mem_alloc(sizeof(struct file_handle));
@@ -98,24 +128,17 @@ char *menu(void) {
     disable_cursor();
     bool skip_timeout = false;
 
+    if (menu_tree == NULL)
+        panic("Config contains no entries.");
+
 refresh:
     clear(true);
     print("\n\n  \e[36m Limine " LIMINE_VERSION " \e[37m\n\n\n");
 
     print("Select an entry:\n\n");
 
-    int max_entries;
-    for (max_entries = 0; ; max_entries++) {
-        if (config_get_entry_name(config_entry_name, max_entries, 1024) == -1)
-            break;
-        if (max_entries == selected_entry)
-            print("  \e[47m\e[30m %s \e[40m\e[37m\n", config_entry_name);
-        else
-            print("   %s\n", config_entry_name);
-    }
-
-    if (max_entries == 0)
-        panic("Config contains no entries.");
+    int max_entries = print_tree(0, 0, selected_entry, menu_tree,
+                                 &selected_menu_entry);
 
     print("\nArrows to choose, enter to select, 'e' to edit command line.");
 
@@ -148,27 +171,34 @@ timeout_aborted:
                 goto refresh;
             case '\r':
             autoboot:
-                config_set_entry(selected_entry);
+                if (selected_menu_entry->sub != NULL) {
+                    skip_timeout = true;
+                    selected_menu_entry->expanded = !selected_menu_entry->expanded;
+                    goto refresh;
+                }
                 enable_cursor();
-                if (!config_get_value(cmdline, 0, CMDLINE_MAX, "KERNEL_CMDLINE")) {
-                    if (!config_get_value(cmdline, 0, CMDLINE_MAX, "CMDLINE")) {
+                if (!config_get_value(selected_menu_entry->body, cmdline, 0, CMDLINE_MAX, "KERNEL_CMDLINE")) {
+                    if (!config_get_value(selected_menu_entry->body, cmdline, 0, CMDLINE_MAX, "CMDLINE")) {
                         cmdline[0] = '\0';
                     }
                 }
                 clear(true);
-                return cmdline;
+                *cmdline_ret = cmdline;
+                return selected_menu_entry->body;
             case 'e':
-                config_set_entry(selected_entry);
+                if (selected_menu_entry->sub != NULL)
+                    goto refresh;
                 enable_cursor();
-                if (!config_get_value(cmdline, 0, CMDLINE_MAX, "KERNEL_CMDLINE")) {
-                    if (!config_get_value(cmdline, 0, CMDLINE_MAX, "CMDLINE")) {
+                if (!config_get_value(selected_menu_entry->body, cmdline, 0, CMDLINE_MAX, "KERNEL_CMDLINE")) {
+                    if (!config_get_value(selected_menu_entry->body, cmdline, 0, CMDLINE_MAX, "CMDLINE")) {
                         cmdline[0] = '\0';
                     }
                 }
                 print("\n\n> ");
                 readline(cmdline, cmdline, CMDLINE_MAX);
                 clear(true);
-                return cmdline;
+                *cmdline_ret = cmdline;
+                return selected_menu_entry->body;
         }
     }
 }
diff --git a/stage2/menu.h b/stage2/menu.h
index 8d04432f..5c93301b 100644
--- a/stage2/menu.h
+++ b/stage2/menu.h
@@ -1,6 +1,6 @@
 #ifndef __MENU_H__
 #define __MENU_H__
 
-char *menu(void);
+char *menu(char **cmdline_ret);
 
 #endif
diff --git a/stage2/protos/chainload.c b/stage2/protos/chainload.c
index 5281080f..a97a0580 100644
--- a/stage2/protos/chainload.c
+++ b/stage2/protos/chainload.c
@@ -46,12 +46,12 @@ static void spinup(uint8_t drive) {
     );
 }
 
-void chainload(void) {
+void chainload(char *config) {
     uint64_t val;
 
     int part; {
         char buf[32];
-        if (!config_get_value(buf, 0, 32, "PARTITION")) {
+        if (!config_get_value(config, buf, 0, 32, "PARTITION")) {
             part = -1;
         } else {
             val = strtoui(buf, NULL, 10);
@@ -63,7 +63,7 @@ void chainload(void) {
     }
     int drive; {
         char buf[32];
-        if (!config_get_value(buf, 0, 32, "DRIVE")) {
+        if (!config_get_value(config, buf, 0, 32, "DRIVE")) {
             panic("DRIVE not specified");
         }
         val = strtoui(buf, NULL, 10);
diff --git a/stage2/protos/chainload.h b/stage2/protos/chainload.h
index 43621937..13e2d9e6 100644
--- a/stage2/protos/chainload.h
+++ b/stage2/protos/chainload.h
@@ -1,6 +1,6 @@
 #ifndef __PROTOS__CHAINLOAD_H__
 #define __PROTOS__CHAINLOAD_H__
 
-void chainload(void);
+void chainload(char *config);
 
 #endif
diff --git a/stage2/protos/linux.c b/stage2/protos/linux.c
index dedb4777..8a7cf6fd 100644
--- a/stage2/protos/linux.c
+++ b/stage2/protos/linux.c
@@ -52,11 +52,11 @@ static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
     );
 }
 
-void linux_load(char *cmdline) {
+void linux_load(char *config, char *cmdline) {
     char buf[128];
     struct file_handle *kernel = conv_mem_alloc(sizeof(struct file_handle));
 
-    if (!config_get_value(buf, 0, 128, "KERNEL_PATH"))
+    if (!config_get_value(config, buf, 0, 128, "KERNEL_PATH"))
         panic("KERNEL_PATH not specified");
 
     if (!uri_open(kernel, buf))
@@ -130,7 +130,7 @@ void linux_load(char *cmdline) {
     size_t modules_mem_base = INITRD_LOAD_ADDR;
     for (size_t i = 0; ; i++) {
         char module_path[64];
-        if (!config_get_value(module_path, i, 64, "MODULE_PATH"))
+        if (!config_get_value(config, module_path, i, 64, "MODULE_PATH"))
             break;
 
         struct file_handle module;
diff --git a/stage2/protos/linux.h b/stage2/protos/linux.h
index 6ddec45d..395fd3b7 100644
--- a/stage2/protos/linux.h
+++ b/stage2/protos/linux.h
@@ -1,8 +1,6 @@
 #ifndef __PROTOS__LINUX_H__
 #define __PROTOS__LINUX_H__
 
-#include <fs/file.h>
-
-void linux_load(char *cmdline);
+void linux_load(char *config, char *cmdline);
 
 #endif
diff --git a/stage2/protos/stivale.c b/stage2/protos/stivale.c
index a5f96dfc..6c390dd6 100644
--- a/stage2/protos/stivale.c
+++ b/stage2/protos/stivale.c
@@ -25,14 +25,14 @@
 
 struct stivale_struct stivale_struct = {0};
 
-void stivale_load(char *cmdline) {
+void stivale_load(char *config, char *cmdline) {
     char buf[128];
 
     stivale_struct.flags |= (1 << 0);  // set bit 0 since we are BIOS and not UEFI
 
     struct file_handle *kernel = conv_mem_alloc(sizeof(struct file_handle));
 
-    if (!config_get_value(buf, 0, 128, "KERNEL_PATH"))
+    if (!config_get_value(config, buf, 0, 128, "KERNEL_PATH"))
         panic("KERNEL_PATH not specified");
 
     if (!uri_open(kernel, buf))
@@ -117,14 +117,14 @@ void stivale_load(char *cmdline) {
     uint64_t *prev_mod_ptr = &stivale_struct.modules;
     for (int i = 0; ; i++) {
         char module_file[64];
-        if (!config_get_value(module_file, i, 64, "MODULE_PATH"))
+        if (!config_get_value(config, module_file, i, 64, "MODULE_PATH"))
             break;
 
         stivale_struct.module_count++;
 
         struct stivale_module *m = conv_mem_alloc(sizeof(struct stivale_module));
 
-        if (!config_get_value(m->string, i, 128, "MODULE_STRING")) {
+        if (!config_get_value(config, m->string, i, 128, "MODULE_STRING")) {
             m->string[0] = '\0';
         }
 
@@ -171,7 +171,7 @@ void stivale_load(char *cmdline) {
         int req_height = stivale_hdr.framebuffer_height;
         int req_bpp    = stivale_hdr.framebuffer_bpp;
 
-        if (config_get_value(buf, 0, 128, "RESOLUTION"))
+        if (config_get_value(config, buf, 0, 128, "RESOLUTION"))
             parse_resolution(&req_width, &req_height, &req_bpp, buf);
 
         struct vbe_framebuffer_info fbinfo;
diff --git a/stage2/protos/stivale.h b/stage2/protos/stivale.h
index 21822011..0f73be36 100644
--- a/stage2/protos/stivale.h
+++ b/stage2/protos/stivale.h
@@ -6,7 +6,7 @@
 #include <sys/e820.h>
 #include <mm/vmm.h>
 
-void stivale_load(char *cmdline);
+void stivale_load(char *config, char *cmdline);
 
 pagemap_t stivale_build_pagemap(bool level5pg);
 __attribute__((noreturn)) void stivale_spinup(
diff --git a/stage2/protos/stivale2.c b/stage2/protos/stivale2.c
index 9addfabe..9d77aae6 100644
--- a/stage2/protos/stivale2.c
+++ b/stage2/protos/stivale2.c
@@ -50,12 +50,12 @@ static void append_tag(struct stivale2_struct *s, struct stivale2_tag *tag) {
     s->tags   = (uint64_t)(size_t)tag;
 }
 
-void stivale2_load(char *cmdline) {
+void stivale2_load(char *config, char *cmdline) {
     char buf[128];
 
     struct file_handle *kernel = conv_mem_alloc(sizeof(struct file_handle));
 
-    if (!config_get_value(buf, 0, 128, "KERNEL_PATH"))
+    if (!config_get_value(config, buf, 0, 128, "KERNEL_PATH"))
         panic("KERNEL_PATH not specified");
 
     if (!uri_open(kernel, buf))
@@ -158,7 +158,7 @@ void stivale2_load(char *cmdline) {
     size_t module_count;
     for (module_count = 0; ; module_count++) {
         char module_file[64];
-        if (!config_get_value(module_file, module_count, 64, "MODULE_PATH"))
+        if (!config_get_value(config, module_file, module_count, 64, "MODULE_PATH"))
             break;
     }
 
@@ -171,12 +171,12 @@ void stivale2_load(char *cmdline) {
 
     for (int i = 0; ; i++) {
         char module_file[64];
-        if (!config_get_value(module_file, i, 64, "MODULE_PATH"))
+        if (!config_get_value(config, module_file, i, 64, "MODULE_PATH"))
             break;
 
         struct stivale2_module *m = &tag->modules[i];
 
-        if (!config_get_value(m->string, i, 128, "MODULE_STRING")) {
+        if (!config_get_value(config, m->string, i, 128, "MODULE_STRING")) {
             m->string[0] = '\0';
         }
 
@@ -258,7 +258,7 @@ void stivale2_load(char *cmdline) {
         int req_height = hdrtag->framebuffer_height;
         int req_bpp    = hdrtag->framebuffer_bpp;
 
-        if (config_get_value(buf, 0, 128, "RESOLUTION"))
+        if (config_get_value(config, buf, 0, 128, "RESOLUTION"))
             parse_resolution(&req_width, &req_height, &req_bpp, buf);
 
         struct vbe_framebuffer_info fbinfo;
diff --git a/stage2/protos/stivale2.h b/stage2/protos/stivale2.h
index 68f66066..bc1b519d 100644
--- a/stage2/protos/stivale2.h
+++ b/stage2/protos/stivale2.h
@@ -1,6 +1,6 @@
 #ifndef __PROTOS__STIVALE2_H__
 #define __PROTOS__STIVALE2_H__
 
-void stivale2_load(char *cmdline);
+void stivale2_load(char *config, char *cmdline);
 
 #endif
diff --git a/test/limine.cfg b/test/limine.cfg
index da6cfcd1..c1cd3dd5 100644
--- a/test/limine.cfg
+++ b/test/limine.cfg
@@ -10,7 +10,69 @@ THEME_MARGIN=64
 
 BACKGROUND_PATH=bios://:1/boot/bg.bmp
 
-:Stivale Test
+:Legacy
+
+::12345
+PROTOCOL=stivale
+KERNEL_PATH=guid://@GUID@/boot/test.elf
+KERNEL_CMDLINE=Hi! This is an example!
+
+MODULE_PATH=bios://:1/boot/test.elf
+MODULE_STRING=yooooo
+
+::Stivale Test
+
+PROTOCOL=stivale
+KERNEL_PATH=bios://:1/boot/test.elf
+KERNEL_CMDLINE=Hi! This is an example!
+
+MODULE_PATH=bios://:1/boot/test.elf
+MODULE_STRING=yooooo
+
+MODULE_PATH=bios://:1/boot/bg.bmp
+MODULE_STRING=yooooo
+
+::123456
+
+:::Stivale Test
+
+PROTOCOL=stivale
+KERNEL_PATH=bios://:1/boot/test.elf
+KERNEL_CMDLINE=Hi! This is an example!
+
+MODULE_PATH=bios://:1/boot/test.elf
+MODULE_STRING=yooooo
+
+MODULE_PATH=bios://:1/boot/bg.bmp
+MODULE_STRING=yooooo
+
+:::123123123
+
+PROTOCOL=stivale
+KERNEL_PATH=bios://:1/boot/test.elf
+KERNEL_CMDLINE=Hi! This is an example!
+
+MODULE_PATH=bios://:1/boot/test.elf
+MODULE_STRING=yooooo
+
+MODULE_PATH=bios://:1/boot/bg.bmp
+MODULE_STRING=yooooo
+
+:::foo
+
+::::bar
+
+PROTOCOL=stivale
+KERNEL_PATH=bios://:1/boot/test.elf
+KERNEL_CMDLINE=Hi! This is an example!
+
+MODULE_PATH=bios://:1/boot/test.elf
+MODULE_STRING=yooooo
+
+MODULE_PATH=bios://:1/boot/bg.bmp
+MODULE_STRING=yooooo
+
+::Stivale Test
 
 PROTOCOL=stivale
 KERNEL_PATH=bios://:1/boot/test.elf
tab: 248 wrap: offon