diff --git a/lib/uefi/memory_protocols.cpp b/lib/uefi/memory_protocols.cpp index 35a90e55..5228af26 100644 --- a/lib/uefi/memory_protocols.cpp +++ b/lib/uefi/memory_protocols.cpp @@ -34,8 +34,11 @@ namespace { vmm_aspace_t *old_aspace = nullptr; constexpr size_t kHeapSize = 300ul * 1024 * 1024; +void *heap = nullptr; void *get_heap() { - static auto heap = alloc_page(kHeapSize); + if (heap == nullptr) { + heap = alloc_page(kHeapSize); + } return heap; } @@ -45,26 +48,52 @@ mspace create_mspace_with_base_limit(void *base, size_t capacity, int locked) { return space; } +mspace space = nullptr; + mspace get_mspace() { - static auto space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); + if (space == nullptr) { + space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); + } return space; } -void restore_aspace() { vmm_set_active_aspace(old_aspace); } +vmm_aspace_t *uefi_aspace = nullptr; -} // namespace +void restore_aspace() { + vmm_set_active_aspace(old_aspace); + vmm_free_aspace(uefi_aspace); + uefi_aspace = nullptr; +} + +} // namespace + +EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages) { + return free_pages(reinterpret_cast(memory), pages); +} + +void setup_heap() { + set_boot_aspace(); + get_mspace(); +} + +void reset_heap() { + destroy_mspace(space); + space = nullptr; + free_pages(heap, kHeapSize / PAGE_SIZE); + heap = nullptr; + restore_aspace(); +} vmm_aspace_t *set_boot_aspace() { - static vmm_aspace_t *aspace = nullptr; - if (aspace == nullptr) { - auto err = vmm_create_aspace(&aspace, "linux_kernel", 0); + if (uefi_aspace == nullptr) { + auto err = vmm_create_aspace(&uefi_aspace, "linux_kernel", 0); if (err) { printf("Failed to create address space for linux kernel %d\n", err); return nullptr; } - old_aspace = vmm_set_active_aspace(aspace); + old_aspace = vmm_set_active_aspace(uefi_aspace); } - return aspace; + return uefi_aspace; } void *alloc_page(size_t size, size_t align_log2) { @@ -139,19 +168,17 @@ EfiStatus free_pool(void *mem) { return SUCCESS; } -EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages) { - auto pa = reinterpret_cast( - vaddr_to_paddr(reinterpret_cast(memory))); - if (pa != reinterpret_cast(memory)) { - printf( - "WARN: virtual address 0x%llx is not identity mapped, physical addr: " - "%p\n", - memory, pa); +EfiStatus free_pages(void *memory, size_t pages) { + auto pa = reinterpret_cast(vaddr_to_paddr(memory)); + if (pa != memory) { + printf("WARN: virtual address %p is not identity mapped, physical addr: " + "%p\n", + memory, pa); } status_t err = - vmm_free_region(set_boot_aspace(), static_cast(memory)); + vmm_free_region(set_boot_aspace(), reinterpret_cast(memory)); if (err) { - printf("%s err:%d memory [0x%llx] pages:%zu\n", __FUNCTION__, err, memory, + printf("%s err:%d memory [%p] pages:%zu\n", __FUNCTION__, err, memory, pages); return DEVICE_ERROR; } @@ -164,32 +191,6 @@ EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages) { return SUCCESS; } -size_t get_aspace_entry_count(vmm_aspace_t *aspace) { - vmm_region_t *region = nullptr; - size_t num_entries = 0; - list_for_every_entry(&aspace->region_list, region, vmm_region_t, node) { - num_entries++; - } - return num_entries; -} - -void fill_memory_map_entry(vmm_aspace_t *aspace, EfiMemoryDescriptor *entry, - const vmm_region_t *region) { - entry->virtual_start = region->base; - entry->physical_start = entry->virtual_start; - entry->number_of_pages = region->size / PAGE_SIZE; - paddr_t pa{}; - uint flags{}; - status_t err = - arch_mmu_query(&aspace->arch_aspace, region->base, &pa, &flags); - if (err >= 0) { - entry->physical_start = pa; - } - if ((flags & ARCH_MMU_FLAG_CACHE_MASK) == ARCH_MMU_FLAG_CACHED) { - entry->attributes |= EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_WT; - } -} - EfiStatus get_physical_memory_map(size_t *memory_map_size, EfiMemoryDescriptor *memory_map, size_t *map_key, size_t *desc_size, @@ -229,50 +230,4 @@ EfiStatus get_physical_memory_map(size_t *memory_map_size, return SUCCESS; } -EfiStatus get_memory_map(size_t *memory_map_size, - EfiMemoryDescriptor *memory_map, size_t *map_key, - size_t *desc_size, uint32_t *desc_version) { - if (memory_map_size == nullptr) { - return INVALID_PARAMETER; - } - if (map_key) { - *map_key = 0; - } - if (desc_size) { - *desc_size = sizeof(EfiMemoryDescriptor); - } - if (desc_version) { - *desc_version = 1; - } - vmm_region_t *region = nullptr; - auto aspace = vmm_get_kernel_aspace(); - size_t num_entries = 0; - list_for_every_entry(&aspace->region_list, region, vmm_region_t, node) { - num_entries++; - } - const size_t size_needed = num_entries * sizeof(EfiMemoryDescriptor); - if (*memory_map_size < size_needed) { - *memory_map_size = size_needed; - return BUFFER_TOO_SMALL; - } - *memory_map_size = size_needed; - size_t i = 0; - memset(memory_map, 0, size_needed); - list_for_every_entry(&aspace->region_list, region, vmm_region_t, node) { - memory_map[i].virtual_start = region->base; - memory_map[i].physical_start = memory_map[i].virtual_start; - memory_map[i].number_of_pages = region->size / PAGE_SIZE; - paddr_t pa{}; - uint flags{}; - status_t err = - arch_mmu_query(&aspace->arch_aspace, region->base, &pa, &flags); - if (err >= 0) { - memory_map[i].physical_start = pa; - } - i++; - } - - return SUCCESS; -} - // NOLINTEND(performance-no-int-to-ptr) \ No newline at end of file diff --git a/lib/uefi/memory_protocols.h b/lib/uefi/memory_protocols.h index 262d8318..c829279e 100644 --- a/lib/uefi/memory_protocols.h +++ b/lib/uefi/memory_protocols.h @@ -7,10 +7,13 @@ #include vmm_aspace_t *set_boot_aspace(); +void setup_heap(); +void reset_heap(); void *alloc_page(void *addr, size_t size, size_t align_log2 = PAGE_SIZE_SHIFT); void *alloc_page(size_t size, size_t align_log2 = PAGE_SIZE_SHIFT); EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages); +EfiStatus free_pages(void *memory, size_t pages); void *identity_map(void *addr, size_t size); void *uefi_malloc(size_t size); EfiStatus allocate_pool(EfiMemoryType pool_type, size_t size, void **buf); diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index 821914e1..6d4ed608 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -82,9 +82,11 @@ int load_sections_and_execute(bdev_t *dev, return -6; } } + setup_heap(); + DEFER { reset_heap(); }; const auto &last_section = section_header[sections - 1]; - const auto virtual_size = - last_section.VirtualAddress + last_section.Misc.VirtualSize; + const auto virtual_size = ROUNDUP( + last_section.VirtualAddress + last_section.Misc.VirtualSize, PAGE_SIZE); const auto image_base = reinterpret_cast( alloc_page(reinterpret_cast(optional_header->ImageBase), virtual_size, 21 /* Kernel requires 2MB alignment */)); @@ -92,6 +94,7 @@ int load_sections_and_execute(bdev_t *dev, return -7; } memset(image_base, 0, virtual_size); + DEFER { free_pages(image_base, virtual_size / PAGE_SIZE); }; bio_read(dev, image_base, 0, section_header[0].PointerToRawData); for (size_t i = 0; i < sections; i++) { @@ -108,6 +111,7 @@ int load_sections_and_execute(bdev_t *dev, EfiSystemTable &table = *static_cast(alloc_page(PAGE_SIZE)); memset(&table, 0, sizeof(EfiSystemTable)); + DEFER { free_pages(&table, 1); }; EfiBootService boot_service{}; EfiRuntimeService runtime_service{}; fill(&runtime_service, 0); @@ -122,6 +126,7 @@ int load_sections_and_execute(bdev_t *dev, table.con_out = &console_out; table.configuration_table = reinterpret_cast(alloc_page(PAGE_SIZE)); + DEFER { free_pages(table.configuration_table, 1); }; memset(table.configuration_table, 0, PAGE_SIZE); setup_configuration_table(&table); auto status = platform_setup_system_table(&table); @@ -130,11 +135,16 @@ int load_sections_and_execute(bdev_t *dev, return -static_cast(status); } - constexpr size_t kStackSize = 8 * 1024ul * 1024; + constexpr size_t kStackSize = 1 * 1024ul * 1024; auto stack = reinterpret_cast(alloc_page(kStackSize, 23)); memset(stack, 0, kStackSize); + DEFER { + free_pages(stack, kStackSize / PAGE_SIZE); + stack = nullptr; + }; printf("Calling kernel with stack [%p, %p]\n", stack, stack + kStackSize - 1); - return call_with_stack(stack + kStackSize, entry, image_base, &table); + return static_cast( + call_with_stack(stack + kStackSize, entry, image_base, &table)); } int cmd_uefi_load(int argc, const console_cmd_args *argv) {