:: commit 41bc3ffae28e512c452f1f58b5d789b85a98a693

Mintsuki <mintsuki@protonmail.com> — 2026-05-24 14:32

parents: dfcc72d218

protos/linux: Load kernel at pref_address to match its post-relocation footprint

diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index 1bec1f3b..a38c04ff 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -407,13 +407,30 @@ noreturn void linux_load(char *config, char *cmdline) {
     if (setup_header->version >= 0x205 && setup_header->kernel_alignment > kernel_align) {
         kernel_align = setup_header->kernel_alignment;
     }
-    uintptr_t kernel_load_addr = ALIGN_UP(0x100000, kernel_align, panic(true, "linux: Alignment overflow"));
+    // Start at pref_address: the decompressor relocates itself up to
+    // LOAD_PHYSICAL_ADDR (= pref_address) and scribbles init_size bytes from
+    // there, so loading below it would leave that range unreserved.
+    uintptr_t kernel_search_start = 0x100000;
+    if (setup_header->version >= 0x20a
+     && setup_header->pref_address >= 0x100000
+     && setup_header->pref_address + (uint64_t)kernel_alloc_size <= UINTPTR_MAX) {
+        kernel_search_start = (uintptr_t)setup_header->pref_address;
+    }
+    // Non-relocatable kernels must be loaded at their required address; do
+    // not step up on failure.
+    bool relocatable_kernel = setup_header->version >= 0x205
+                           && setup_header->relocatable_kernel != 0;
+    uintptr_t kernel_load_addr = ALIGN_UP(kernel_search_start, kernel_align, panic(true, "linux: Alignment overflow"));
     for (;;) {
         if (memmap_alloc_range(kernel_load_addr,
                 ALIGN_UP(kernel_alloc_size, 4096, panic(true, "linux: Alignment overflow")),
                 MEMMAP_BOOTLOADER_RECLAIMABLE, MEMMAP_USABLE, false, false, false))
             break;
 
+        if (!relocatable_kernel) {
+            panic(true, "linux: Non-relocatable kernel could not be loaded at required address %X", (uint64_t)kernel_load_addr);
+        }
+
         if (kernel_load_addr >= 0xfff00000) {
             panic(true, "linux: Failed to allocate memory for kernel");
         }
tab: 248 wrap: offon