[lib][uefi] Free memory used by UEFI app after app returns

This commit is contained in:
Kelvin Zhang
2025-07-30 16:07:12 -07:00
committed by Kelvin Zhang
parent ed656a3993
commit 9bbfeabb9d
3 changed files with 63 additions and 95 deletions

View File

@@ -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<void *>(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<void *>(
vaddr_to_paddr(reinterpret_cast<void *>(memory)));
if (pa != reinterpret_cast<void *>(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<void *>(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<vaddr_t>(memory));
vmm_free_region(set_boot_aspace(), reinterpret_cast<vaddr_t>(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)

View File

@@ -7,10 +7,13 @@
#include <uefi/types.h>
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);

View File

@@ -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<char *>(
alloc_page(reinterpret_cast<void *>(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<EfiSystemTable *>(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<EfiConfigurationTable *>(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<int>(status);
}
constexpr size_t kStackSize = 8 * 1024ul * 1024;
constexpr size_t kStackSize = 1 * 1024ul * 1024;
auto stack = reinterpret_cast<char *>(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<int>(
call_with_stack(stack + kStackSize, entry, image_base, &table));
}
int cmd_uefi_load(int argc, const console_cmd_args *argv) {