:: commit 1fad25cec13347e9360aac43ff650c206287c6ca

Mintsuki <mintsuki@protonmail.com> — 2025-05-06 22:59

parents: 91f64df97f

protos/linux: Add optional support for 64-bit boot protocol

diff --git a/common/lib/uri.c b/common/lib/uri.c
index 2d0296d9..bcc05d00 100644
--- a/common/lib/uri.c
+++ b/common/lib/uri.c
@@ -206,6 +206,10 @@ static struct file_handle *uri_boot_dispatch(char *s_part, char *path) {
     return fopen(volume, path);
 }
 
+#if defined (UEFI) && defined (__x86_64__)
+bool uri_open_allow_high = false;
+#endif
+
 struct file_handle *uri_open(char *uri) {
     struct file_handle *ret;
 
@@ -238,7 +242,12 @@ struct file_handle *uri_open(char *uri) {
 
     if (hash != NULL && ret != NULL) {
         uint8_t out_buf[BLAKE2B_OUT_BYTES];
+#if defined (UEFI) && defined (__x86_64__)
+        void *file_buf = freadall_mode(ret, MEMMAP_BOOTLOADER_RECLAIMABLE, uri_open_allow_high);
+        uri_open_allow_high = false;
+#else
         void *file_buf = freadall(ret, MEMMAP_BOOTLOADER_RECLAIMABLE);
+#endif
         blake2b(out_buf, file_buf, ret->size);
         uint8_t hash_buf[BLAKE2B_OUT_BYTES];
 
diff --git a/common/lib/uri.h b/common/lib/uri.h
index d15a5494..8691df91 100644
--- a/common/lib/uri.h
+++ b/common/lib/uri.h
@@ -4,6 +4,10 @@
 #include <stdbool.h>
 #include <fs/file.h>
 
+#if defined (UEFI) && defined (__x86_64__)
+extern bool uri_open_allow_high;
+#endif
+
 bool uri_resolve(char *uri, char **resource, char **root, char **path, char **hash);
 struct file_handle *uri_open(char *uri);
 
diff --git a/common/protos/linux.c b/common/protos/linux.c
index b5c01bb5..1eee9a9b 100644
--- a/common/protos/linux.c
+++ b/common/protos/linux.c
@@ -21,6 +21,9 @@
 #include <drivers/gop.h>
 
 noreturn void linux_spinup(void *entry, void *boot_params);
+#if defined (UEFI) && defined (__x86_64__)
+    noreturn void linux_spinup64(void *entry, void *boot_params);
+#endif
 
 // The following definitions and struct were copied and adapted from Linux
 // kernel headers released under GPL-2.0 WITH Linux-syscall-note
@@ -382,14 +385,6 @@ noreturn void linux_load(char *config, char *cmdline) {
     ///////////////////////////////////////
     // Modules
     ///////////////////////////////////////
-
-    uint32_t modules_mem_base;
-    if (setup_header->version <= 0x202 || setup_header->initrd_addr_max == 0) {
-        modules_mem_base = 0x38000000;
-    } else {
-        modules_mem_base = setup_header->initrd_addr_max + 1;
-    }
-
     size_t size_of_all_modules = 0;
 
     for (size_t i = 0; ; i++) {
@@ -398,6 +393,9 @@ noreturn void linux_load(char *config, char *cmdline) {
             break;
 
         struct file_handle *module;
+#if defined (UEFI) && defined (__x86_64__)
+        uri_open_allow_high = true;
+#endif
         if ((module = uri_open(module_path)) == NULL)
             panic(true, "linux: Failed to open module with path `%s`. Is the path correct?", module_path);
 
@@ -406,6 +404,24 @@ noreturn void linux_load(char *config, char *cmdline) {
         fclose(module);
     }
 
+    uintptr_t modules_mem_base;
+
+#if defined (UEFI) && defined (__x86_64__)
+    if ((setup_header->xloadflags & 3) == 3) {
+        modules_mem_base = (uintptr_t)ext_mem_alloc_type_aligned_mode(
+            size_of_all_modules,
+            MEMMAP_BOOTLOADER_RECLAIMABLE,
+            0x100000,
+            true
+        );
+    } else {
+#endif
+    if (setup_header->version <= 0x202 || setup_header->initrd_addr_max == 0) {
+        modules_mem_base = 0x38000000;
+    } else {
+        modules_mem_base = setup_header->initrd_addr_max + 1;
+    }
+
     modules_mem_base -= size_of_all_modules;
     modules_mem_base = ALIGN_DOWN(modules_mem_base, 0x100000);
 
@@ -420,8 +436,11 @@ noreturn void linux_load(char *config, char *cmdline) {
 
         modules_mem_base -= 0x100000;
     }
+#if defined (UEFI) && defined (__x86_64__)
+    }
+#endif
 
-    size_t _modules_mem_base = modules_mem_base;
+    uintptr_t _modules_mem_base = modules_mem_base;
     for (size_t i = 0; ; i++) {
         char *module_path = config_get_value(config, i, "MODULE_PATH");
         if (module_path == NULL)
@@ -430,17 +449,29 @@ noreturn void linux_load(char *config, char *cmdline) {
         print("linux: Loading module `%#`...\n", module_path);
 
         struct file_handle *module;
+
+#if defined (UEFI) && defined (__x86_64__)
+        uri_open_allow_high = true;
+#endif
         if ((module = uri_open(module_path)) == NULL)
             panic(true, "linux: Could not open `%#`", module_path);
 
         fread(module, (void *)_modules_mem_base, 0, module->size);
 
         _modules_mem_base += module->size;
+
+        fclose(module);
     }
 
     if (size_of_all_modules != 0) {
         setup_header->ramdisk_image = (uint32_t)modules_mem_base;
-        setup_header->ramdisk_size  = (uint32_t)size_of_all_modules;
+#if defined (UEFI) && defined (__x86_64__)
+        boot_params->ext_ramdisk_image = (uint32_t)(modules_mem_base >> 32);
+#endif
+        setup_header->ramdisk_size = (uint32_t)size_of_all_modules;
+#if defined (UEFI) && defined (__x86_64__)
+        boot_params->ext_ramdisk_size = (uint32_t)(size_of_all_modules >> 32);
+#endif
     }
 
     ///////////////////////////////////////
@@ -572,6 +603,13 @@ no_fb:;
 
     irq_flush_type = IRQ_PIC_ONLY_FLUSH;
 
+#if defined (UEFI) && defined (__x86_64__)
+    if ((setup_header->xloadflags & 3) == 3) {
+        flush_irqs();
+        linux_spinup64((void *)kernel_load_addr + 0x200, boot_params);
+    }
+#endif
+
     common_spinup(linux_spinup, 2, (uint32_t)kernel_load_addr,
                                    (uint32_t)(uintptr_t)boot_params);
 }
diff --git a/common/protos/linux_64.asm_uefi_x86_64 b/common/protos/linux_64.asm_uefi_x86_64
new file mode 100644
index 00000000..bca9b46b
--- /dev/null
+++ b/common/protos/linux_64.asm_uefi_x86_64
@@ -0,0 +1,62 @@
+section .data
+
+align 16
+linux_gdt64:
+    dq 0
+
+    dq 0
+
+    dw 0xffff
+    dw 0x0000
+    db 0x00
+    db 10011011b
+    db 10101111b
+    db 0x00
+
+    dw 0xffff
+    dw 0x0000
+    db 0x00
+    db 10010011b
+    db 10001111b
+    db 0x00
+
+  .end:
+
+align 16
+linux_gdt64_ptr:
+    dw (linux_gdt64.end - linux_gdt64) - 1
+    dq linux_gdt64
+
+section .text
+
+bits 64
+
+global linux_spinup64
+linux_spinup64:
+    cli
+    cld
+
+    lgdt [rel linux_gdt64_ptr]
+
+    lea rbx, [rel .fj]
+    push 0x10
+    push rbx
+    retfq
+
+  .fj:
+    mov eax, 0x18
+    mov ds, eax
+    mov es, eax
+    mov fs, eax
+    mov gs, eax
+    mov ss, eax
+
+    mov rax, rdi
+
+    xor ebp, ebp
+    xor edi, edi
+    xor ebx, ebx
+
+    jmp rax
+
+section .note.GNU-stack noalloc noexec nowrite progbits
tab: 248 wrap: offon