:: commit a5ad68b18144982c8a9f619dda0417462037f4a6

mintsuki <mintsuki@protonmail.com> — 2022-06-29 08:27

parents: a24bf3b424

misc: Bring mb2 up to par to mb1 wrt everywhere ranges and bug fixes

diff --git a/common/lib/elf.c b/common/lib/elf.c
index 6a76ddef..03948527 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -514,7 +514,6 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
     size_t max_simulated_tries = 0x100000;
 
     uint64_t entry = hdr.entry;
-    bool entry_adjusted = false;
 
     uint64_t max_align = elf64_max_align(elf);
 
@@ -768,7 +767,7 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t *top, uint32_t allo
 
 bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
                           struct elsewhere_range **ranges,
-                          size_t *ranges_count) {
+                          uint64_t *ranges_count) {
     struct elf32_hdr *hdr = (void *)elf;
 
     if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
@@ -786,7 +785,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
         return false;
     }
 
-    *entry_point = hdr.entry;
+    *entry_point = hdr->entry;
     bool entry_adjusted = false;
 
     if (hdr->phdr_size < sizeof(struct elf32_phdr)) {
@@ -795,7 +794,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
 
     *ranges_count = 0;
     for (uint16_t i = 0; i < hdr->ph_num; i++) {
-        struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
+        struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
         if (phdr->p_type != PT_LOAD)
             continue;
@@ -808,31 +807,31 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
     size_t cur_entry = 0;
 
     for (uint16_t i = 0; i < hdr->ph_num; i++) {
-        struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
+        struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
         if (phdr->p_type != PT_LOAD)
             continue;
 
         // Sanity checks
-        if (phdr->p_filesz > phdr.p_memsz) {
+        if (phdr->p_filesz > phdr->p_memsz) {
             panic(true, "elf: p_filesz > p_memsz");
         }
 
-        void *elsewhere = ext_mem_alloc(phdr.p_memsz);
+        void *elsewhere = ext_mem_alloc(phdr->p_memsz);
 
-        memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
+        memcpy(elsewhere, elf + phdr->p_offset, phdr->p_filesz);
 
         if (!entry_adjusted
-         && *entry_point >= phdr.p_vaddr
-         && *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
-            *entry_point -= phdr.p_vaddr;
-            *entry_point += phdr.p_paddr;
+         && *entry_point >= phdr->p_vaddr
+         && *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
+            *entry_point -= phdr->p_vaddr;
+            *entry_point += phdr->p_paddr;
             entry_adjusted = true;
         }
 
-        *entry[cur_entry].elsewhere = elsewhere;
-        *entry[cur_entry].target = phdr.p_paddr;
-        *entry[cur_entry].length = phdr.p_memsz;
+        (*ranges[cur_entry]).elsewhere = (uintptr_t)elsewhere;
+        (*ranges[cur_entry]).target = phdr->p_paddr;
+        (*ranges[cur_entry]).length = phdr->p_memsz;
 
         cur_entry++;
     }
@@ -842,7 +841,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
 
 bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
                           struct elsewhere_range **ranges,
-                          size_t *ranges_count) {
+                          uint64_t *ranges_count) {
     struct elf64_hdr *hdr = (void *)elf;
 
     if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
@@ -860,7 +859,7 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
         return false;
     }
 
-    *entry_point = hdr.entry;
+    *entry_point = hdr->entry;
     bool entry_adjusted = false;
 
     if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
@@ -869,7 +868,7 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
 
     *ranges_count = 0;
     for (uint16_t i = 0; i < hdr->ph_num; i++) {
-        struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
+        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
         if (phdr->p_type != PT_LOAD)
             continue;
@@ -882,31 +881,31 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
     size_t cur_entry = 0;
 
     for (uint16_t i = 0; i < hdr->ph_num; i++) {
-        struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
+        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
         if (phdr->p_type != PT_LOAD)
             continue;
 
         // Sanity checks
-        if (phdr->p_filesz > phdr.p_memsz) {
+        if (phdr->p_filesz > phdr->p_memsz) {
             panic(true, "elf: p_filesz > p_memsz");
         }
 
-        void *elsewhere = ext_mem_alloc(phdr.p_memsz);
+        void *elsewhere = ext_mem_alloc(phdr->p_memsz);
 
-        memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
+        memcpy(elsewhere, elf + phdr->p_offset, phdr->p_filesz);
 
         if (!entry_adjusted
-         && *entry_point >= phdr.p_vaddr
-         && *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
-            *entry_point -= phdr.p_vaddr;
-            *entry_point += phdr.p_paddr;
+         && *entry_point >= phdr->p_vaddr
+         && *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
+            *entry_point -= phdr->p_vaddr;
+            *entry_point += phdr->p_paddr;
             entry_adjusted = true;
         }
 
-        *entry[cur_entry].elsewhere = elsewhere;
-        *entry[cur_entry].target = phdr.p_paddr;
-        *entry[cur_entry].length = phdr.p_memsz;
+        (*ranges[cur_entry]).elsewhere = (uintptr_t)elsewhere;
+        (*ranges[cur_entry]).target = phdr->p_paddr;
+        (*ranges[cur_entry]).length = phdr->p_memsz;
 
         cur_entry++;
     }
diff --git a/common/lib/elf.h b/common/lib/elf.h
index 93855568..d611de20 100644
--- a/common/lib/elf.h
+++ b/common/lib/elf.h
@@ -36,10 +36,10 @@ struct elf_section_hdr_info* elf32_section_hdr_info(uint8_t *elf);
 
 bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
                           struct elsewhere_range **ranges,
-                          size_t *ranges_count);
+                          uint64_t *ranges_count);
 bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
                           struct elsewhere_range **ranges,
-                          size_t *ranges_count);
+                          uint64_t *ranges_count);
 
 struct elf64_hdr {
     uint8_t  ident[16];
diff --git a/common/lib/elsewhere.c b/common/lib/elsewhere.c
index 50babe05..8b2509ab 100644
--- a/common/lib/elsewhere.c
+++ b/common/lib/elsewhere.c
@@ -3,6 +3,7 @@
 #include <stdbool.h>
 #include <lib/elsewhere.h>
 #include <lib/blib.h>
+#include <mm/pmm.h>
 
 static bool elsewhere_overlap_check(uint64_t base1, uint64_t top1,
                               uint64_t base2, uint64_t top2) {
@@ -12,7 +13,7 @@ static bool elsewhere_overlap_check(uint64_t base1, uint64_t top1,
 
 bool elsewhere_append(
         bool flexible_target,
-        struct elsewhere_range *ranges, size_t *ranges_count,
+        struct elsewhere_range *ranges, uint64_t *ranges_count,
         void *elsewhere, uint64_t *target, size_t t_length) {
     // original target of -1 means "allocate after top of all ranges"
     // flexible target is ignored
@@ -80,7 +81,7 @@ retry:
     }
 
     // Add the elsewhere range
-    ranges[*ranges_count].elsewhere = elsewhere;
+    ranges[*ranges_count].elsewhere = (uintptr_t)elsewhere;
     ranges[*ranges_count].target = *target;
     ranges[*ranges_count].length = t_length;
     *ranges_count += 1;
diff --git a/common/lib/elsewhere.h b/common/lib/elsewhere.h
index 575d8e1e..c61f1bfb 100644
--- a/common/lib/elsewhere.h
+++ b/common/lib/elsewhere.h
@@ -13,7 +13,7 @@ struct elsewhere_range {
 
 bool elsewhere_append(
         bool flexible_target,
-        struct elsewhere_range *ranges, size_t *ranges_count,
+        struct elsewhere_range *ranges, uint64_t *ranges_count,
         void *elsewhere, uint64_t *target, size_t t_length);
 
 #endif
diff --git a/common/protos/limine.c b/common/protos/limine.c
index b66d614c..8f1f9e14 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -162,7 +162,7 @@ bool limine_load(char *config, char *cmdline) {
     bool is_reloc;
 
     if (elf64_load(kernel, &entry_point, NULL, &slide,
-                   MEMMAP_KERNEL_AND_MODULES, kaslr, false,
+                   MEMMAP_KERNEL_AND_MODULES, kaslr,
                    &ranges, &ranges_count,
                    true, &physical_base, &virtual_base, &image_size,
                    &is_reloc)) {
diff --git a/common/protos/multiboot.32.c b/common/protos/multiboot.32.c
new file mode 100644
index 00000000..c5f8b9f1
--- /dev/null
+++ b/common/protos/multiboot.32.c
@@ -0,0 +1,36 @@
+#include <stdint.h>
+#include <stdnoreturn.h>
+#if bios == 1
+#  include <sys/idt.h>
+#endif
+
+noreturn void multiboot_spinup_32(
+                  uint32_t reloc_stub,
+                  uint32_t magic, uint32_t protocol_info,
+                  uint32_t entry_point,
+                  uint32_t elf_ranges, uint32_t elf_ranges_count) {
+#if bios == 1
+    struct idtr idtr;
+
+    idtr.limit = 0x3ff;
+    idtr.ptr = 0;
+
+    asm volatile (
+        "lidt %0"
+        :
+        : "m" (idtr)
+        : "memory"
+    );
+#endif
+
+    asm volatile (
+        "jmp *%%ebx"
+        :
+        : "b"(reloc_stub), "S"(magic),
+          "a"(elf_ranges), "d"(elf_ranges_count),
+          "D"(protocol_info), "c"(entry_point)
+        : "memory"
+    );
+
+    __builtin_unreachable();
+}
diff --git a/common/protos/multiboot.h b/common/protos/multiboot.h
index d1aaeff6..b2683c83 100644
--- a/common/protos/multiboot.h
+++ b/common/protos/multiboot.h
@@ -2,6 +2,7 @@
 #define __PROTOS__MULTIBOOT_H__
 
 #include <stdint.h>
+#include <lib/blib.h>
 
 struct mb_reloc_stub {
     char jmp[4];
@@ -10,4 +11,7 @@ struct mb_reloc_stub {
     uint32_t mb_info_target;
 };
 
+extern symbol multiboot_spinup_32;
+extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
+
 #endif
diff --git a/common/protos/multiboot1.32.c b/common/protos/multiboot1.32.c
deleted file mode 100644
index b67eb3b0..00000000
--- a/common/protos/multiboot1.32.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdnoreturn.h>
-#include <mm/vmm.h>
-#if bios == 1
-#  include <sys/idt.h>
-#endif
-#include <protos/multiboot.h>
-
-noreturn void multiboot1_spinup_32(uint32_t entry_point,
-                                   uint32_t multiboot1_info, uint32_t mb_info_target,
-                                   uint32_t mb_info_size,
-                                   uint32_t elf_ranges, uint32_t elf_ranges_count,
-                                   uint32_t slide,
-                                   struct mb_reloc_stub *reloc_stub) {
-#if bios == 1
-    struct idtr idtr;
-
-    idtr.limit = 0x3ff;
-    idtr.ptr = 0;
-
-    asm volatile (
-        "lidt %0"
-        :
-        : "m" (idtr)
-        : "memory"
-    );
-#endif
-
-    reloc_stub->magic = 0x2badb002;
-    reloc_stub->entry_point = entry_point;
-    reloc_stub->mb_info_target = mb_info_target;
-
-    asm volatile (
-        "jmp *%%ebx"
-        :
-        : "b"(reloc_stub), "S"(multiboot1_info),
-          "c"(mb_info_size), "a"(elf_ranges), "d"(elf_ranges_count),
-          "D"(slide)
-        : "memory"
-    );
-
-    __builtin_unreachable();
-}
diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index b8c2a737..853e375d 100644
--- a/common/protos/multiboot1.c
+++ b/common/protos/multiboot1.c
@@ -1,8 +1,8 @@
 #include <stdint.h>
 #include <stddef.h>
-#include <stdnoreturn.h>
-#include <config.h>
 #include <protos/multiboot1.h>
+#include <protos/multiboot.h>
+#include <config.h>
 #include <lib/libc.h>
 #include <lib/elf.h>
 #include <lib/blib.h>
@@ -20,10 +20,6 @@
 #include <mm/pmm.h>
 #include <drivers/vga_textmode.h>
 
-extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
-
-noreturn void multiboot1_spinup_32(uint32_t entry_point, uint32_t multiboot1_info);
-
 #define LIMINE_BRAND "Limine " LIMINE_VERSION
 
 // Returns the size required to store the multiboot info.
@@ -122,7 +118,7 @@ bool multiboot1_load(char *config, char *cmdline) {
         ranges_count = 1;
         ranges = ext_mem_alloc(sizeof(struct elsewhere_range));
 
-        ranges->elsewhere = elsewhere;
+        ranges->elsewhere = (uintptr_t)elsewhere;
         ranges->target = header.load_addr;
         ranges->length = full_size;
     } else {
@@ -171,8 +167,8 @@ bool multiboot1_load(char *config, char *cmdline) {
     struct elsewhere_range *new_ranges = ext_mem_alloc(sizeof(struct elsewhere_range) *
         (ranges_count
        + 1 /* mb1 info range */
-       + n_modules,
-       + section_hdr_info ? section_hdr_info->num : 0));
+       + n_modules
+       + (section_hdr_info ? section_hdr_info->num : 0)));
 
     memcpy(new_ranges, ranges, sizeof(struct elsewhere_range) * ranges_count);
     pmm_free(ranges, sizeof(struct elsewhere_range) * ranges_count);
@@ -256,7 +252,7 @@ bool multiboot1_load(char *config, char *cmdline) {
             char *lowmem_modstr = mb1_info_alloc(&mb1_info_raw, strlen(module_cmdline) + 1);
             strcpy(lowmem_modstr, module_cmdline);
 
-            void *module_addr = freadall(f);
+            void *module_addr = freadall(f, MEMMAP_BOOTLOADER_RECLAIMABLE);
             uint64_t module_target = (uint64_t)-1; /* no target preference, use top */
 
             elsewhere_append(true /* flexible target */,
@@ -390,7 +386,8 @@ nofb:;
 
     irq_flush_type = IRQ_PIC_ONLY_FLUSH;
 
-    common_spinup(multiboot_spinup_32, 4,
-                  0x2badb002, entry_point,
+    common_spinup(multiboot_spinup_32, 6,
+                  (uint32_t)(uintptr_t)reloc_stub, (uint32_t)0x2badb002,
+                  (uint32_t)mb1_info_final_loc, (uint32_t)entry_point,
                   (uint32_t)(uintptr_t)ranges, (uint32_t)ranges_count);
 }
diff --git a/common/protos/multiboot2.32.c b/common/protos/multiboot2.32.c
deleted file mode 100644
index c73ee8b4..00000000
--- a/common/protos/multiboot2.32.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdnoreturn.h>
-#include <mm/vmm.h>
-#if bios == 1
-#  include <sys/idt.h>
-#endif
-#include <protos/multiboot.h>
-
-noreturn void multiboot2_spinup_32(uint32_t entry_point,
-                                   uint32_t multiboot2_info, uint32_t mb_info_target,
-                                   uint32_t mb_info_size,
-                                   uint32_t elf_ranges, uint32_t elf_ranges_count,
-                                   uint32_t slide,
-                                   struct mb_reloc_stub *reloc_stub) {
-#if bios == 1
-    struct idtr idtr;
-
-    idtr.limit = 0x3ff;
-    idtr.ptr = 0;
-
-    asm volatile (
-        "lidt %0"
-        :
-        : "m" (idtr)
-        : "memory"
-    );
-#endif
-
-    reloc_stub->magic = 0x36d76289;
-    reloc_stub->entry_point = entry_point;
-    reloc_stub->mb_info_target = mb_info_target;
-
-    asm volatile (
-        "jmp *%%ebx"
-        :
-        : "b"(reloc_stub), "S"(multiboot2_info),
-          "c"(mb_info_size), "a"(elf_ranges), "d"(elf_ranges_count),
-          "D"(slide)
-        : "memory"
-    );
-
-    __builtin_unreachable();
-}
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index 9d8e232e..d82aa009 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -1,6 +1,7 @@
-#include <protos/multiboot2.h>
 #include <stdint.h>
 #include <stddef.h>
+#include <protos/multiboot2.h>
+#include <protos/multiboot.h>
 #include <config.h>
 #include <lib/libc.h>
 #include <lib/elf.h>
@@ -10,6 +11,7 @@
 #include <lib/uri.h>
 #include <lib/fb.h>
 #include <lib/term.h>
+#include <lib/elsewhere.h>
 #include <sys/pic.h>
 #include <sys/cpu.h>
 #include <sys/idt.h>
@@ -20,8 +22,6 @@
 #include <lib/blib.h>
 #include <drivers/vga_textmode.h>
 
-extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
-
 #define LIMINE_BRAND "Limine " LIMINE_VERSION
 
 /// Returns the size required to store the multiboot2 info.
@@ -57,26 +57,6 @@ static size_t get_multiboot2_info_size(
 
 #define append_tag(P, TAG) ({ (P) += ALIGN_UP((TAG)->size, MULTIBOOT_TAG_ALIGN); })
 
-static uint32_t kernel_top;
-
-static bool mb2_overlap_check(uint64_t base1, uint64_t top1,
-                              uint64_t base2, uint64_t top2) {
-    return ((base1 >= base2 && base1 <  top2)
-         || (top1  >  base2 && top1  <= top2));
-}
-
-static void *mb2_alloc(size_t size) {
-    void *ret = (void *)(uintptr_t)ALIGN_UP(kernel_top, 4096);
-
-    while (!memmap_alloc_range((uintptr_t)ret, size, MEMMAP_KERNEL_AND_MODULES,
-                               true, false, false, false)) {
-        ret += 0x200000;
-    }
-
-    kernel_top = (uintptr_t)ret + size;
-    return ret;
-}
-
 bool multiboot2_load(char *config, char* cmdline) {
     struct file_handle *kernel_file;
 
@@ -122,7 +102,7 @@ bool multiboot2_load(char *config, char* cmdline) {
 
     bool is_elf_info_requested = false;
 
-    uint32_t entry_point = 0xffffffff;
+    uint64_t entry_point = 0xffffffff;
 
     // Iterate through the entries...
     for (struct multiboot_header_tag *tag = (struct multiboot_header_tag*)(header + 1); // header + 1 to skip the header struct.
@@ -197,8 +177,8 @@ bool multiboot2_load(char *config, char* cmdline) {
         }
     }
 
-    struct elf_range *elf_ranges;
-    uint64_t elf_ranges_count, slide;
+    struct elsewhere_range *ranges;
+    uint64_t ranges_count;
 
     if (addresstag != NULL) {
         if (addresstag->load_addr > addresstag->header_addr)
@@ -217,7 +197,7 @@ bool multiboot2_load(char *config, char* cmdline) {
         memcpy((void *)(uintptr_t)addresstag->load_addr, kernel + (header_offset
                 - (addresstag->header_addr - addresstag->load_addr)), load_size);
 
-        kernel_top = addresstag->load_addr + load_size;
+        //kernel_top = addresstag->load_addr + load_size;
 
         if (addresstag->bss_end_addr) {
             uintptr_t bss_addr = addresstag->load_addr + load_size;
@@ -229,20 +209,20 @@ bool multiboot2_load(char *config, char* cmdline) {
             memmap_alloc_range(bss_addr, bss_size, MEMMAP_KERNEL_AND_MODULES, true, true, false, false);
             memset((void *)bss_addr, 0, bss_size);
 
-            kernel_top = bss_addr + bss_size;
+            //kernel_top = bss_addr + bss_size;
         }
     } else {
+        uint64_t e;
         int bits = elf_bits(kernel);
-        uint64_t e = 0, t = 0;
 
         switch (bits) {
             case 32:
-                if (elf32_load(kernel, (uint32_t *)&e, (uint32_t *)&t, MEMMAP_BOOTLOADER_RECLAIMABLE, &slide, &elf_ranges, &elf_ranges_count))
+                if (elf32_load_elsewhere(kernel, &e, &ranges, &ranges_count))
                     panic(true, "multiboot2: ELF32 load failure");
 
                 break;
             case 64: {
-                if (elf64_load(kernel, &e, &t, &slide, MEMMAP_BOOTLOADER_RECLAIMABLE, false, true, &elf_ranges, &elf_ranges_count, false, NULL, NULL, NULL, NULL))
+                if (elf64_load_elsewhere(kernel, &e, &ranges, &ranges_count))
                     panic(true, "multiboot2: ELF64 load failure");
 
                 break;
@@ -251,17 +231,9 @@ bool multiboot2_load(char *config, char* cmdline) {
                 panic(true, "multiboot2: Invalid ELF file bitness");
         }
 
-        e -= slide;
         if (entry_point == 0xffffffff) {
             entry_point = e;
         }
-
-        t -= slide;
-        if (t < 0x100000) {
-            kernel_top = 0x100000;
-        } else {
-            kernel_top = t;
-        }
     }
 
     struct elf_section_hdr_info *section_hdr_info = NULL;
@@ -311,41 +283,30 @@ bool multiboot2_load(char *config, char* cmdline) {
 
     size_t info_idx = 0;
 
+    // Realloc elsewhere ranges to include mb2 info, modules, and elf sections
+    struct elsewhere_range *new_ranges = ext_mem_alloc(sizeof(struct elsewhere_range) *
+        (ranges_count
+       + 1 /* mb2 info range */
+       + n_modules
+       + (section_hdr_info ? section_hdr_info->num : 0)));
+
+    memcpy(new_ranges, ranges, sizeof(struct elsewhere_range) * ranges_count);
+    pmm_free(ranges, sizeof(struct elsewhere_range) * ranges_count);
+    ranges = new_ranges;
+
     // GRUB allocates boot info at 0x10000, *except* if the kernel happens
     // to overlap this region, then it gets moved to right after the
     // kernel, or whichever PHDR happens to sit at 0x10000.
     // Allocate it wherever, then move it to where GRUB puts it
     // afterwards.
+
+    // Elsewhere append mb2 info *after* kernel but *before* modules.
     uint8_t *mb2_info = ext_mem_alloc(mb2_info_size);
     uint64_t mb2_info_final_loc = 0x10000;
-retry_mb2_info_reloc:
-    for (size_t i = 0; i < elf_ranges_count; i++) {
-        uint64_t mb2_info_top = mb2_info_final_loc + mb2_info_size;
-
-        uint64_t base = elf_ranges[i].base - slide;
-        uint64_t length = elf_ranges[i].length - slide;
-        uint64_t top = base + length;
-
-        // Do they overlap?
-        if (mb2_overlap_check(base, top, mb2_info_final_loc, mb2_info_top)) {
-            mb2_info_final_loc = top;
-            goto retry_mb2_info_reloc;
-        }
 
-        // Make sure it is memory that actually exists.
-        if (!memmap_alloc_range(mb2_info_final_loc, mb2_info_size, MEMMAP_BOOTLOADER_RECLAIMABLE,
-                                MEMMAP_USABLE, false, true, false)) {
-            if (!memmap_alloc_range(mb2_info_final_loc, mb2_info_size, MEMMAP_BOOTLOADER_RECLAIMABLE,
-                                    MEMMAP_BOOTLOADER_RECLAIMABLE, false, true, false)) {
-                mb2_info_final_loc += 0x1000;
-                goto retry_mb2_info_reloc;
-            }
-        }
-    }
-
-    if (mb2_info_final_loc + mb2_info_size > kernel_top) {
-        kernel_top = mb2_info_final_loc + mb2_info_size;
-    }
+    elsewhere_append(true /* flexible target */,
+            ranges, &ranges_count,
+            mb2_info, &mb2_info_final_loc, mb2_info_size);
 
     struct multiboot2_start_tag *mbi_start = (struct multiboot2_start_tag *)mb2_info;
     info_idx += sizeof(struct multiboot2_start_tag);
@@ -377,10 +338,13 @@ retry_mb2_info_reloc:
                 continue;
             }
 
-            void *section = mb2_alloc(shdr->sh_size);
-            memcpy(section, kernel + shdr->sh_offset, shdr->sh_size);
+            uint64_t section = (uint64_t)-1; /* no target preference, use top */
+
+            elsewhere_append(true /* flexible target */,
+                    ranges, &ranges_count,
+                    kernel + shdr->sh_offset, &section, shdr->sh_size);
 
-            shdr->sh_addr = (uintptr_t)section;
+            shdr->sh_addr = section;
         }
 
         append_tag(info_idx, tag);
@@ -406,15 +370,18 @@ retry_mb2_info_reloc:
         char *module_cmdline = conf_tuple.value2;
         if (!module_cmdline) module_cmdline = "";
 
-        void *module_addr = mb2_alloc(f->size);
+        void *module_addr = freadall(f, MEMMAP_BOOTLOADER_RECLAIMABLE);
+        uint64_t module_target = (uint64_t)-1;
 
-        fread(f, module_addr, 0, f->size);
+        elsewhere_append(true /* flexible target */,
+                ranges, &ranges_count,
+                module_addr, &module_target, f->size);
 
         struct multiboot_tag_module *module_tag = (struct multiboot_tag_module *)(mb2_info + info_idx);
 
         module_tag->type = MULTIBOOT_TAG_TYPE_MODULE;
         module_tag->size = sizeof(struct multiboot_tag_module) + strlen(module_cmdline) + 1;
-        module_tag->mod_start   = (uint32_t)(size_t)module_addr;
+        module_tag->mod_start   = module_target;
         module_tag->mod_end     = module_tag->mod_start + f->size;
         strcpy(module_tag->cmdline, module_cmdline); // Copy over the command line
 
@@ -645,9 +612,9 @@ retry_mb2_info_reloc:
     }
 #endif
 
-    // Load relocation stub where it won't get overwritten
+    // Load relocation stub where it won't get overwritten (hopefully)
     size_t reloc_stub_size = (size_t)multiboot_reloc_stub_end - (size_t)multiboot_reloc_stub;
-    void *reloc_stub = mb2_alloc(reloc_stub_size);
+    void *reloc_stub = ext_mem_alloc(reloc_stub_size);
     memcpy(reloc_stub, multiboot_reloc_stub, reloc_stub_size);
 
 #if uefi == 1
@@ -743,11 +710,8 @@ retry_mb2_info_reloc:
 
     irq_flush_type = IRQ_PIC_ONLY_FLUSH;
 
-    common_spinup(multiboot2_spinup_32, 8,
-                  entry_point,
-                  (uint32_t)(uintptr_t)mb2_info, (uint32_t)mb2_info_final_loc,
-                  (uint32_t)mb2_info_size,
-                  (uint32_t)(uintptr_t)elf_ranges, (uint32_t)elf_ranges_count,
-                  (uint32_t)slide,
-                  (uint32_t)(uintptr_t)reloc_stub);
+    common_spinup(multiboot_spinup_32, 6,
+                  (uint32_t)(uintptr_t)reloc_stub, (uint32_t)0x36d76289,
+                  (uint32_t)mb2_info_final_loc, (uint32_t)entry_point,
+                  (uint32_t)(uintptr_t)ranges, (uint32_t)ranges_count);
 }
diff --git a/common/protos/multiboot2.h b/common/protos/multiboot2.h
index 5be4108d..a0be2015 100644
--- a/common/protos/multiboot2.h
+++ b/common/protos/multiboot2.h
@@ -24,7 +24,6 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include <stdnoreturn.h>
 
 bool multiboot2_load(char *config, char *cmdline);
 
@@ -416,6 +415,4 @@ struct multiboot_tag_load_base_addr
     uint32_t load_base_addr;
 };
 
-noreturn void multiboot2_spinup_32(uint32_t entry_point, uint32_t multiboot1_info);
-
 #endif
diff --git a/common/protos/multiboot_reloc.asm_x86 b/common/protos/multiboot_reloc.asm_x86
index 821b9d83..6bb63107 100644
--- a/common/protos/multiboot_reloc.asm_x86
+++ b/common/protos/multiboot_reloc.asm_x86
@@ -8,44 +8,43 @@ multiboot_reloc_stub:
 
     times 4-($-multiboot_reloc_stub) db 0
 
-  .magic_value:    dd 0
-  .entry_point:    dd 0
-  .mb_info_target: dd 0
-
     ; EBX = self
-    ; ESI = multiboot info (original)
-    ; ECX = multiboot info (size)
-
-    ; EAX = elf ranges
-    ; EDX = elf ranges count
-    ; EDI = slide
+    ; ESI = magic value
+    ; EDI = protocol info
+    ; ECX = entry point
+    ; EAX = ranges
+    ; EDX = ranges count
 
   .code:
-    mov ebp, edi
 
-    mov edi, [ebx + (.mb_info_target - multiboot_reloc_stub)]
+    push edi
+    push esi
+    push ecx
 
-    ; Copy multiboot info; frees ESI, EDI, and ECX
-    rep movsb
+  .ranges_loop:
+    test edx, edx     ; Loop until we're done
+    jz .ranges_loop_out
 
- .elf_ranges_loop:
-    mov esi, [eax]   ; ESI = elf_range.base
-    mov edi, esi     ; EDI = elf_range.base - slide
-    sub edi, ebp
-    mov ecx, [eax+8] ; ECX = elf_range.length
-    rep movsb        ; Copy range to target location
+    mov esi, [eax]    ; ESI = range.elsewhere
+    mov edi, [eax+8]  ; EDI = range.target
+    mov ecx, [eax+16] ; ECX = range.length
+    rep movsb         ; Copy range to target location
 
-    add eax, 24      ; Move to the next elf_range
+    add eax, 24       ; Move to the next range
 
-    dec edx          ; Loop until we're done
-    jnz .elf_ranges_loop
+    dec edx
+    jmp .ranges_loop
 
+  .ranges_loop_out:
     ; We're done relocating!
+    pop ecx
+    pop esi
+    pop edi
 
-    push dword [ebx + (.entry_point - multiboot_reloc_stub)]
+    push ecx
 
-    mov eax, [ebx + (.magic_value - multiboot_reloc_stub)]
-    mov ebx, [ebx + (.mb_info_target - multiboot_reloc_stub)]
+    mov eax, esi ; EAX = magic value
+    mov ebx, edi ; EBX = protocol info
     xor ecx, ecx
     xor edx, edx
     xor esi, esi
tab: 248 wrap: offon