:: commit 0527dac6f87cd5a221f692afea833f90347d8fb1

mintsuki <mintsuki@protonmail.com> — 2021-12-11 14:34

parents: 3bb754e627

menu: Move protocol logic from entry.s3.c to menu.c

diff --git a/Makefile b/Makefile
index 18f546c0..3eb9d8a1 100644
--- a/Makefile
+++ b/Makefile
@@ -375,7 +375,7 @@ full-hybrid-test:
 	sudo cp -rv test/* test_image/boot/
 	xorriso -as mkisofs -b boot/limine-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot boot/limine-eltorito-efi.bin -efi-boot-part --efi-boot-image --protective-msdos-label test_image/ -o test.iso
 	$(BINDIR)/limine-install test.iso
-	qemu-system-x86_64 -M q35 -bios ovmf-x64/OVMF.fd -net none -smp 4   -cdrom test.iso -debugcon stdio
+	qemu-system-x86_64 -m 512M -M q35 -bios ovmf-x64/OVMF.fd -net none -smp 4   -cdrom test.iso -debugcon stdio
 	qemu-system-x86_64 -m 512M -M q35 -bios ovmf-x64/OVMF.fd -net none -smp 4   -hda test.iso -debugcon stdio
 	qemu-system-x86_64 -m 512M -M q35 -bios ovmf-ia32/OVMF.fd -net none -smp 4   -cdrom test.iso -debugcon stdio
 	qemu-system-x86_64 -m 512M -M q35 -bios ovmf-ia32/OVMF.fd -net none -smp 4   -hda test.iso -debugcon stdio
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 637ef8f1..d9544695 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -13,12 +13,6 @@
 #include <fs/file.h>
 #include <lib/elf.h>
 #include <mm/pmm.h>
-#include <protos/stivale.h>
-#include <protos/stivale2.h>
-#include <protos/linux.h>
-#include <protos/chainload.h>
-#include <protos/multiboot1.h>
-#include <protos/multiboot2.h>
 #include <menu.h>
 #include <pxe/pxe.h>
 #include <pxe/tftp.h>
@@ -163,53 +157,5 @@ void stage3_common(void) {
         print("Boot partition: %d\n", boot_volume->partition);
     }
 
-    bool disable_timeout = false;
-
-menu_again:;
-    char *cmdline;
-    char *config = menu(&cmdline, disable_timeout);
-
-    char *proto = config_get_value(config, 0, "PROTOCOL");
-    if (proto == NULL) {
-        printv("PROTOCOL not specified, using autodetection...\n");
-autodetect:
-        stivale2_load(config, cmdline);
-        stivale_load(config, cmdline);
-        multiboot2_load(config, cmdline);
-        multiboot1_load(config, cmdline);
-        linux_load(config, cmdline);
-        panic("Kernel protocol autodetection failed");
-    }
-
-    bool ret = true;
-
-    if (!strcmp(proto, "stivale1") || !strcmp(proto, "stivale")) {
-        ret = stivale_load(config, cmdline);
-    } else if (!strcmp(proto, "stivale2")) {
-        ret = stivale2_load(config, cmdline);
-    } else if (!strcmp(proto, "linux")) {
-        ret = linux_load(config, cmdline);
-    } else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
-        ret = multiboot1_load(config, cmdline);
-    } else if (!strcmp(proto, "multiboot2")) {
-        ret = multiboot2_load(config, cmdline);
-    } else if (!strcmp(proto, "chainload")) {
-        chainload(config);
-    }
-
-    if (ret) {
-        print("WARNING: Unsupported protocol specified: %s.\n", proto);
-    } else {
-        print("WARNING: Incorrect protocol specified for kernel.\n");
-    }
-
-    print("         Press A to attempt autodetection or any other key to return to menu.\n");
-
-    int c = getchar();
-    if (c == 'a' || c == 'A') {
-        goto autodetect;
-    } else {
-        disable_timeout = true;
-        goto menu_again;
-    }
+    menu(true);
 }
diff --git a/stage23/menu.c b/stage23/menu.c
index 80111d64..0444389b 100644
--- a/stage23/menu.c
+++ b/stage23/menu.c
@@ -13,6 +13,12 @@
 #include <mm/pmm.h>
 #include <drivers/vbe.h>
 #include <console.h>
+#include <protos/stivale.h>
+#include <protos/stivale2.h>
+#include <protos/linux.h>
+#include <protos/chainload.h>
+#include <protos/multiboot1.h>
+#include <protos/multiboot2.h>
 
 static char *menu_branding = NULL;
 static char *menu_branding_colour = NULL;
@@ -518,7 +524,47 @@ static size_t print_tree(const char *shift, size_t level, size_t base_index, siz
     return max_entries;
 }
 
-char *menu(char **cmdline, bool disable_timeout) {
+#if defined (__x86_64__)
+__attribute__((used))
+static uintptr_t stack_at_first_entry = 0;
+#endif
+
+__attribute__((noreturn, naked))
+void menu(__attribute__((unused)) bool timeout_enabled) {
+#if defined (__i386__)
+    asm volatile (
+        "call 1f\n\t"
+        "1:\n\t"
+        "pop %eax\n\t"
+        "add $(2f - 1b), %eax\n\t"
+        "cmpl $0, (%eax)\n\t"
+        "jne 1f\n\t"
+        "mov %esp, (%eax)\n\t"
+        "jmp _menu\n\t"
+        "1:\n\t"
+        "mov 4(%esp), %edi\n\t"
+        "mov (%eax), %esp\n\t"
+        "push %edi\n\t"
+        "call _menu\n\t"
+        "2:\n\t"
+        ".long 0"
+    );
+#elif defined (__x86_64__)
+    asm volatile (
+        "xor %eax, %eax\n\t"
+        "cmp %rax, stack_at_first_entry(%rip)\n\t"
+        "jne 1f\n\t"
+        "mov %rsp, stack_at_first_entry(%rip)\n\t"
+        "jmp _menu\n\t"
+        "1:\n\t"
+        "mov stack_at_first_entry(%rip), %rsp\n\t"
+        "jmp _menu"
+    );
+#endif
+}
+
+__attribute__((noreturn, used))
+static void _menu(bool timeout_enabled) {
     menu_branding = config_get_value(NULL, 0, "MENU_BRANDING");
     if (menu_branding == NULL)
         menu_branding = "Limine " LIMINE_VERSION;
@@ -549,7 +595,7 @@ char *menu(char **cmdline, bool disable_timeout) {
             timeout = strtoui(timeout_config, NULL, 10);
     }
 
-    if (disable_timeout) {
+    if (!timeout_enabled) {
         skip_timeout = true;
     }
 
@@ -703,6 +749,8 @@ refresh:
 
     term_double_buffer_flush();
 
+    char *cmdline = NULL;
+
     for (;;) {
         c = getchar();
 timeout_aborted:
@@ -724,12 +772,12 @@ timeout_aborted:
                     selected_menu_entry->expanded = !selected_menu_entry->expanded;
                     goto refresh;
                 }
-                *cmdline = config_get_value(selected_menu_entry->body, 0, "KERNEL_CMDLINE");
-                if (!*cmdline) {
-                    *cmdline = config_get_value(selected_menu_entry->body, 0, "CMDLINE");
+                cmdline = config_get_value(selected_menu_entry->body, 0, "KERNEL_CMDLINE");
+                if (!cmdline) {
+                    cmdline = config_get_value(selected_menu_entry->body, 0, "CMDLINE");
                 }
-                if (!*cmdline) {
-                    *cmdline = "";
+                if (!cmdline) {
+                    cmdline = "";
                 }
                 if (term_backend == NOT_READY) {
 #if bios == 1
@@ -740,7 +788,7 @@ timeout_aborted:
                 } else {
                     reset_term();
                 }
-                return selected_menu_entry->body;
+                goto post_menu;
             case 'e': {
                 if (editor_enabled) {
                     if (selected_menu_entry->sub != NULL)
@@ -761,4 +809,50 @@ timeout_aborted:
             }
         }
     }
+
+post_menu:
+    char *config = selected_menu_entry->body;
+
+    char *proto = config_get_value(config, 0, "PROTOCOL");
+    if (proto == NULL) {
+        printv("PROTOCOL not specified, using autodetection...\n");
+autodetect:
+        stivale2_load(config, cmdline);
+        stivale_load(config, cmdline);
+        multiboot2_load(config, cmdline);
+        multiboot1_load(config, cmdline);
+        linux_load(config, cmdline);
+        panic("Kernel protocol autodetection failed");
+    }
+
+    bool ret = true;
+
+    if (!strcmp(proto, "stivale1") || !strcmp(proto, "stivale")) {
+        ret = stivale_load(config, cmdline);
+    } else if (!strcmp(proto, "stivale2")) {
+        ret = stivale2_load(config, cmdline);
+    } else if (!strcmp(proto, "linux")) {
+        ret = linux_load(config, cmdline);
+    } else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
+        ret = multiboot1_load(config, cmdline);
+    } else if (!strcmp(proto, "multiboot2")) {
+        ret = multiboot2_load(config, cmdline);
+    } else if (!strcmp(proto, "chainload")) {
+        chainload(config);
+    }
+
+    if (ret) {
+        print("WARNING: Unsupported protocol specified: %s.\n", proto);
+    } else {
+        print("WARNING: Incorrect protocol specified for kernel.\n");
+    }
+
+    print("         Press A to attempt autodetection or any other key to return to menu.\n");
+
+    c = getchar();
+    if (c == 'a' || c == 'A') {
+        goto autodetect;
+    } else {
+        menu(false);
+    }
 }
diff --git a/stage23/menu.h b/stage23/menu.h
index 4d6b1376..ef25682b 100644
--- a/stage23/menu.h
+++ b/stage23/menu.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 
-char *menu(char **cmdline_ret, bool disable_timeout);
+__attribute__((noreturn))
+void menu(bool timeout_enabled);
 
 #endif
tab: 248 wrap: offon