:: commit 2419a8c5be8d35c3dba85be1b7c88c8816d4b4fd

mintsuki <mintsuki@protonmail.com> — 2024-03-25 19:13

parents: 94e1b955c3

misc: Relocate to below 4GiB if possible when loaded above 4GiB

diff --git a/common/entry.s3.c b/common/entry.s3.c
index 56559a28..12fe8d62 100644
--- a/common/entry.s3.c
+++ b/common/entry.s3.c
@@ -28,6 +28,8 @@ void stage3_common(void);
 
 #if defined (UEFI)
 extern symbol __slide;
+extern symbol __image_size;
+extern symbol _start;
 
 noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
     gST = SystemTable;
@@ -37,6 +39,28 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
 
     EFI_STATUS status;
 
+#if defined (__x86_64__)
+    if ((uintptr_t)__slide >= 0x100000000) {
+        size_t image_size_pages = ALIGN_UP((size_t)__image_size, 4096) / 4096;
+        size_t new_base;
+        for (new_base = 0x1000; new_base + image_size_pages < 0x100000000; new_base += 0x1000) {
+            EFI_PHYSICAL_ADDRESS _new_base = (EFI_PHYSICAL_ADDRESS)new_base;
+            status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, image_size_pages, &_new_base);
+            if (status == 0) {
+                goto new_base_gotten;
+            }
+        }
+        panic(false, "Limine does not support being loaded above 4GiB");
+new_base_gotten:
+        memcpy((void *)new_base, __slide, (size_t)__image_size);
+        __attribute__((ms_abi))
+        void (*new_entry_point)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
+        new_entry_point = (void *)(new_base + ((uintptr_t)_start - (uintptr_t)__slide));
+        new_entry_point(ImageHandle, SystemTable);
+        __builtin_unreachable();
+    }
+#endif
+
     gST->ConOut->EnableCursor(gST->ConOut, false);
 
     init_memmap();
@@ -52,12 +76,6 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     init_gdt();
 #endif
 
-#if defined (__x86_64__)
-    if ((uintptr_t)__slide >= 0x100000000) {
-        panic(false, "Limine does not support being loaded above 4GiB");
-    }
-#endif
-
     disk_create_index();
 
     boot_volume = NULL;
tab: 248 wrap: offon