:: commit c3c278ffdd5720f61df1a2457677226a691dbb82

mintsuki <mintsuki@protonmail.com> — 2021-03-05 05:10

parents: a81f094d1d

Always use our own (better) allocator

diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 46a07769..0064ae03 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -32,6 +32,8 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
 
     print("Limine " LIMINE_VERSION "\n\n", print);
 
+    init_memmap();
+
     disk_create_index();
 
     EFI_GUID loaded_img_prot_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
@@ -88,10 +90,6 @@ void stage3_common(struct volume *boot_volume) {
     char *cmdline;
     char *config = menu(&cmdline);
 
-#if defined (uefi)
-    efi_exit_boot_services();
-#endif
-
     char *proto = config_get_value(config, 0, "PROTOCOL");
     if (proto == NULL) {
         panic("PROTOCOL not specified");
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index 0d6019e7..bb5f05c3 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -78,15 +78,8 @@ bool efi_exit_boot_services(void) {
     uefi_call_wrapper(gBS->GetMemoryMap, 5,
         &mmap_size, tmp_mmap, &mmap_key, &desc_size, &desc_ver);
 
-    EFI_MEMORY_DESCRIPTOR *efi_mmap = ext_mem_alloc(mmap_size);
-
-    uefi_call_wrapper(gBS->GetMemoryMap, 5,
-        &mmap_size, efi_mmap, &mmap_key, &desc_size, &desc_ver);
-
     uefi_call_wrapper(gBS->ExitBootServices, 2, efi_image_handle, mmap_key);
 
-    pmm_mmap_efi2ours(efi_mmap, desc_size, mmap_size / desc_size);
-
     efi_boot_services_exited = true;
 
     print("efi: Exited boot services.\n");
diff --git a/stage23/mm/pmm.h b/stage23/mm/pmm.h
index 5f0aff1f..b12014be 100644
--- a/stage23/mm/pmm.h
+++ b/stage23/mm/pmm.h
@@ -13,17 +13,11 @@
 #define MEMMAP_BAD_MEMORY             5
 #define MEMMAP_BOOTLOADER_RECLAIMABLE 0x1000
 #define MEMMAP_KERNEL_AND_MODULES     0x1001
+#define MEMMAP_EFI_RECLAIMABLE        0x2000
 
 extern struct e820_entry_t memmap[];
 extern size_t memmap_entries;
 
-#if defined (uefi)
-#include <efi.h>
-
-bool pmm_mmap_efi2ours(EFI_MEMORY_DESCRIPTOR *efi_mmap,
-                       size_t desc_size, size_t entry_count);
-#endif
-
 void init_memmap(void);
 struct e820_entry_t *get_memmap(size_t *entries);
 void print_memmap(struct e820_entry_t *mm, size_t size);
diff --git a/stage23/mm/pmm.s2.c b/stage23/mm/pmm.s2.c
index 06addbbb..7cae5a24 100644
--- a/stage23/mm/pmm.s2.c
+++ b/stage23/mm/pmm.s2.c
@@ -33,6 +33,8 @@ static const char *memmap_type(uint32_t type) {
             return "Bootloader reclaimable";
         case MEMMAP_KERNEL_AND_MODULES:
             return "Kernel/Modules";
+        case MEMMAP_EFI_RECLAIMABLE:
+            return "EFI reclaimable";
         default:
             return "???";
     }
@@ -202,70 +204,29 @@ void init_memmap(void) {
 }
 #endif
 
-void *ext_mem_alloc(size_t count) {
-    return ext_mem_alloc_type(count, MEMMAP_BOOTLOADER_RECLAIMABLE);
-}
-
-void *ext_mem_alloc_aligned(size_t count, size_t alignment) {
-    return ext_mem_alloc_aligned_type(count, alignment, MEMMAP_BOOTLOADER_RECLAIMABLE);
-}
-
-void *ext_mem_alloc_type(size_t count, uint32_t type) {
-    return ext_mem_alloc_aligned_type(count, 4, type);
-}
-
-// Allocate memory top down, hopefully without bumping into kernel or modules
-static void *_ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type) {
-    if (allocations_disallowed)
-        panic("Extended memory allocations disallowed");
-
-    for (int i = memmap_entries - 1; i >= 0; i--) {
-        if (memmap[i].type != 1)
-            continue;
-
-        int64_t entry_base = (int64_t)(memmap[i].base);
-        int64_t entry_top  = (int64_t)(memmap[i].base + memmap[i].length);
-
-        // Let's make sure the entry is not > 4GiB
-        if (entry_base >= 0x100000000 || entry_top >= 0x100000000) {
-            // Theoretically there could be an entry which crosses the 4GiB
-            // boundary, but realistically this does not happen as far as I
-            // have seen. Let's just discard the entry.
-            continue;
-        }
-
-        int64_t alloc_base = ALIGN_DOWN(entry_top - (int64_t)count, alignment);
-
-        // This entry is too small for us.
-        if (alloc_base < entry_base)
-            continue;
+#if defined (uefi)
+void init_memmap(void) {
+    EFI_STATUS status;
 
-        // We now reserve the range we need.
-        int64_t aligned_length = entry_top - alloc_base;
-        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true);
+    EFI_MEMORY_DESCRIPTOR tmp_mmap[1];
+    UINTN mmap_size = sizeof(tmp_mmap);
+    UINTN mmap_key = 0, desc_size = 0, desc_ver = 0;
 
-        void *ret = (void *)(size_t)alloc_base;
+    status = uefi_call_wrapper(gBS->GetMemoryMap, 5,
+        &mmap_size, tmp_mmap, &mmap_key, &desc_size, &desc_ver);
 
-        // Zero out allocated space
-        memset(ret, 0, count);
+    EFI_MEMORY_DESCRIPTOR *efi_mmap;
 
-        sanitise_entries(false);
+    mmap_size += 4096;
 
-        return ret;
-    }
+    status = uefi_call_wrapper(gBS->AllocatePool, 3,
+        EfiLoaderData, mmap_size, &efi_mmap);
 
-    panic("High memory allocator: Out of memory");
-}
+    status = uefi_call_wrapper(gBS->GetMemoryMap, 5,
+        &mmap_size, efi_mmap, &mmap_key, &desc_size, &desc_ver);
 
-#if defined (bios)
-void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type) {
-    return _ext_mem_alloc_aligned_type(count, alignment, type);
-}
-#endif
+    size_t entry_count = mmap_size / desc_size;
 
-#if defined (uefi)
-bool pmm_mmap_efi2ours(EFI_MEMORY_DESCRIPTOR *efi_mmap,
-                       size_t desc_size, size_t entry_count) {
     for (size_t i = 0; i < entry_count; i++) {
         EFI_MEMORY_DESCRIPTOR *entry = (void *)efi_mmap + i * desc_size;
 
@@ -302,42 +263,81 @@ bool pmm_mmap_efi2ours(EFI_MEMORY_DESCRIPTOR *efi_mmap,
 
     sanitise_entries(false);
 
-    print_memmap(memmap, memmap_entries);
-
     allocations_disallowed = false;
 
-    return true;
+    // Let's leave 64MiB to the firmware
+    ext_mem_alloc_aligned_type(65536, 4096, MEMMAP_EFI_RECLAIMABLE);
+
+    // Now own all the usable entries
+    for (size_t i = 0; i < memmap_entries; i++) {
+        if (memmap[i].type != MEMMAP_USABLE)
+            continue;
+
+        EFI_PHYSICAL_ADDRESS base = memmap[i].base;
+
+        status = uefi_call_wrapper(gBS->AllocatePages, 4,
+          AllocateAddress, EfiLoaderData, memmap[i].length / 4096, &base);
+
+        if (status)
+            panic("AllocatePages %x", status);
+    }
+}
+#endif
+
+void *ext_mem_alloc(size_t count) {
+    return ext_mem_alloc_type(count, MEMMAP_BOOTLOADER_RECLAIMABLE);
+}
+
+void *ext_mem_alloc_aligned(size_t count, size_t alignment) {
+    return ext_mem_alloc_aligned_type(count, alignment, MEMMAP_BOOTLOADER_RECLAIMABLE);
+}
+
+void *ext_mem_alloc_type(size_t count, uint32_t type) {
+    return ext_mem_alloc_aligned_type(count, 4, type);
 }
 
+// Allocate memory top down, hopefully without bumping into kernel or modules
 void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type) {
-    if (efi_boot_services_exited) {
-        return _ext_mem_alloc_aligned_type(count, alignment, type);
-    }
+    if (allocations_disallowed)
+        panic("Extended memory allocations disallowed");
 
-    EFI_STATUS status;
+    for (int i = memmap_entries - 1; i >= 0; i--) {
+        if (memmap[i].type != 1)
+            continue;
 
-    void *ret;
+        int64_t entry_base = (int64_t)(memmap[i].base);
+        int64_t entry_top  = (int64_t)(memmap[i].base + memmap[i].length);
 
-    if (alignment && alignment % 4096 == 0) {
-        status = uefi_call_wrapper(gBS->AllocatePages, 4, 0, 2,
-                                   DIV_ROUNDUP(count, 4096), &ret);
-    } else {
-        status = uefi_call_wrapper(gBS->AllocatePool, 3, 4, count, &ret);
-    }
+        // Let's make sure the entry is not > 4GiB
+        if (entry_base >= 0x100000000 || entry_top >= 0x100000000) {
+            // Theoretically there could be an entry which crosses the 4GiB
+            // boundary, but realistically this does not happen as far as I
+            // have seen. Let's just discard the entry.
+            continue;
+        }
 
-    if (status) {
-        panic("Memory allocation error %x", status);
-    }
+        int64_t alloc_base = ALIGN_DOWN(entry_top - (int64_t)count, alignment);
 
-    if ((uintptr_t)ret % alignment) {
-        panic("Memory alloc align bad");
-    }
+        // This entry is too small for us.
+        if (alloc_base < entry_base)
+            continue;
 
-    memset(ret, 0, count);
+        // We now reserve the range we need.
+        int64_t aligned_length = entry_top - alloc_base;
+        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true);
 
-    return ret;
+        void *ret = (void *)(size_t)alloc_base;
+
+        // Zero out allocated space
+        memset(ret, 0, count);
+
+        sanitise_entries(false);
+
+        return ret;
+    }
+
+    panic("High memory allocator: Out of memory");
 }
-#endif
 
 bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic) {
     uint64_t top = base + length;
tab: 248 wrap: offon