From 3fb0e31374ab4885a50c0f9b74634717d1bf84df Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 5 Feb 2025 13:02:26 -0800 Subject: [PATCH] [app][uefi] Split memory and block io code into separate files --- lib/uefi/blockio_protocols.cpp | 85 ++++++++ lib/uefi/blockio_protocols.h | 8 + lib/uefi/boot_service_provider.cpp | 309 +---------------------------- lib/uefi/boot_service_provider.h | 7 - lib/uefi/configuration_table.cpp | 2 +- lib/uefi/memory_protocols.cpp | 258 ++++++++++++++++++++++++ lib/uefi/memory_protocols.h | 25 +++ lib/uefi/rules.mk | 2 + lib/uefi/uefi.cpp | 1 + 9 files changed, 389 insertions(+), 308 deletions(-) create mode 100644 lib/uefi/blockio_protocols.cpp create mode 100644 lib/uefi/blockio_protocols.h create mode 100644 lib/uefi/memory_protocols.cpp create mode 100644 lib/uefi/memory_protocols.h diff --git a/lib/uefi/blockio_protocols.cpp b/lib/uefi/blockio_protocols.cpp new file mode 100644 index 000000000..fb5de204a --- /dev/null +++ b/lib/uefi/blockio_protocols.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "memory_protocols.h" +#include "switch_stack.h" +#include "types.h" +#include +#include +#include +#include + +EfiStatus read_blocks(EfiBlockIoProtocol *self, uint32_t media_id, uint64_t lba, + size_t buffer_size, void *buffer) { + auto interface = reinterpret_cast(self); + auto dev = reinterpret_cast(interface->dev); + if (lba >= dev->block_count) { + printf("OOB read %llu %u\n", lba, dev->block_count); + return END_OF_MEDIA; + } + + const size_t bytes_read = + call_with_stack(interface->io_stack, bio_read_block, dev, buffer, lba, + buffer_size / dev->block_size); + if (bytes_read != buffer_size) { + printf("Failed to read %ld bytes from %s\n", buffer_size, dev->name); + return DEVICE_ERROR; + } + return SUCCESS; +} + +EfiStatus write_blocks(EfiBlockIoProtocol *self, uint32_t media_id, + uint64_t lba, size_t buffer_size, const void *buffer) { + printf("%s is called\n", __FUNCTION__); + return SUCCESS; +} + +EfiStatus flush_blocks(EfiBlockIoProtocol *self) { + printf("%s is called\n", __FUNCTION__); + return SUCCESS; +} + +EfiStatus reset(EfiBlockIoProtocol *self, bool extended_verification) { + printf("%s is called\n", __FUNCTION__); + return UNSUPPORTED; +} + +EfiStatus open_block_device(EfiHandle handle, void **intf) { + static constexpr size_t kIoStackSize = 1024ul * 1024 * 64; + static void *io_stack = nullptr; + if (io_stack == nullptr) { + vmm_alloc(vmm_get_kernel_aspace(), "uefi_io_stack", kIoStackSize, &io_stack, + PAGE_SIZE_SHIFT, 0, 0); + } + printf("%s(%p)\n", __FUNCTION__, handle); + const auto interface = reinterpret_cast( + uefi_malloc(sizeof(EfiBlockIoInterface))); + memset(interface, 0, sizeof(EfiBlockIoInterface)); + auto dev = bio_open(reinterpret_cast(handle)); + interface->dev = dev; + interface->protocol.reset = reset; + interface->protocol.read_blocks = read_blocks; + interface->protocol.write_blocks = write_blocks; + interface->protocol.flush_blocks = flush_blocks; + interface->protocol.media = &interface->media; + interface->media.block_size = dev->block_size; + interface->media.io_align = interface->media.block_size; + interface->media.last_block = dev->block_count - 1; + interface->io_stack = reinterpret_cast(io_stack) + kIoStackSize; + *intf = interface; + return SUCCESS; +} diff --git a/lib/uefi/blockio_protocols.h b/lib/uefi/blockio_protocols.h new file mode 100644 index 000000000..6df08d275 --- /dev/null +++ b/lib/uefi/blockio_protocols.h @@ -0,0 +1,8 @@ +#ifndef __LIB_UEFI_BLOCKIO_PROTOCOL_H_ +#define __LIB_UEFI_BLOCKIO_PROTOCOL_H_ + +#include "types.h" + +EfiStatus open_block_device(EfiHandle handle, void **intf); + +#endif diff --git a/lib/uefi/boot_service_provider.cpp b/lib/uefi/boot_service_provider.cpp index ae86f2c6d..ddeb41fa5 100644 --- a/lib/uefi/boot_service_provider.cpp +++ b/lib/uefi/boot_service_provider.cpp @@ -15,14 +15,14 @@ * */ #include "boot_service_provider.h" +#include "memory_protocols.h" +#include "blockio_protocols.h" + #include "arch/defines.h" #include "boot_service.h" #include "defer.h" -#include "kernel/thread.h" -#include "kernel/vm.h" #include "lib/bio.h" -#include "lib/dlmalloc.h" #include "libfdt.h" #include "protocols/block_io_protocol.h" #include "protocols/dt_fixup_protocol.h" @@ -36,80 +36,6 @@ #include #include -static vmm_aspace_t *old_aspace = nullptr; - -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 (err) { - printf("Failed to create address space for linux kernel %d\n", err); - return nullptr; - } - old_aspace = vmm_set_active_aspace(aspace); - } - return aspace; -} - -void restore_aspace() { vmm_set_active_aspace(old_aspace); } - -void *identity_map(void *addr, size_t size) { - size = ROUNDUP(size, PAGE_SIZE); - auto vaddr = reinterpret_cast(addr); - paddr_t pa{}; - uint flags{}; - auto aspace = set_boot_aspace(); - auto err = arch_mmu_query(&aspace->arch_aspace, vaddr, &pa, &flags); - if (err) { - printf("Failed to query physical address for memory 0x%p\n", addr); - return nullptr; - } - - err = arch_mmu_unmap(&aspace->arch_aspace, vaddr, size / PAGE_SIZE); - if (err) { - printf("Failed to unmap virtual address 0x%lx\n", vaddr); - return nullptr; - } - arch_mmu_map(&aspace->arch_aspace, pa, pa, size / PAGE_SIZE, flags); - if (err) { - printf("Failed to identity map physical address 0x%lx\n", pa); - return nullptr; - } - printf("Identity mapped physical address 0x%lx size %zu flags 0x%x\n", pa, - size, flags); - - return reinterpret_cast(pa); -} - -void *alloc_page(size_t size, size_t align_log2) { - auto aspace = set_boot_aspace(); - void *vptr{}; - status_t err = vmm_alloc_contiguous(aspace, "uefi_program", size, &vptr, - align_log2, 0, 0); - if (err) { - printf("Failed to allocate memory for uefi program %d\n", err); - return nullptr; - } - return identity_map(vptr, size); -} - -void *alloc_page(void *addr, size_t size, size_t align_log2) { - if (addr == nullptr) { - return alloc_page(size, align_log2); - } - auto err = - vmm_alloc_contiguous(set_boot_aspace(), "uefi_program", size, &addr, - align_log2, VMM_FLAG_VALLOC_SPECIFIC, 0); - if (err) { - printf( - "Failed to allocate memory for uefi program @ fixed address 0x%p %d , " - "falling back to non-fixed allocation\n", - addr, err); - return alloc_page(size, align_log2); - } - return identity_map(addr, size); -} - namespace { EfiStatus unload(EfiHandle handle) { return SUCCESS; } @@ -122,31 +48,13 @@ bool guid_eq(const EfiGuid *a, const EfiGuid &b) { return memcmp(a, &b, sizeof(*a)) == 0; } -constexpr size_t kHeapSize = 256ul * 1024 * 1024; - -void *get_heap() { - static auto heap = alloc_page(kHeapSize); - return heap; -} - -mspace create_mspace_with_base_limit(void *base, size_t capacity, int locked) { - auto space = create_mspace_with_base(get_heap(), kHeapSize, 1); - mspace_set_footprint_limit(space, capacity); - return space; -} - -mspace get_mspace() { - static auto space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); - return space; -} - EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf) { if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { printf("handle_protocol(%p, LOADED_IMAGE_PROTOCOL_GUID, %p);\n", handle, intf); const auto loaded_image = static_cast( - mspace_malloc(get_mspace(), sizeof(EFI_LOADED_IMAGE_PROTOCOL))); + uefi_malloc(sizeof(EFI_LOADED_IMAGE_PROTOCOL))); *loaded_image = {}; loaded_image->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; loaded_image->ParentHandle = nullptr; @@ -168,137 +76,6 @@ EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, return UNSUPPORTED; } -EfiStatus allocate_pool(EfiMemoryType pool_type, size_t size, void **buf) { - if (buf == nullptr) { - return INVALID_PARAMETER; - } - if (size == 0) { - *buf = nullptr; - return SUCCESS; - } - *buf = mspace_malloc(get_mspace(), size); - if (*buf != nullptr) { - return SUCCESS; - } - return OUT_OF_RESOURCES; -} - -EfiStatus free_pool(void *mem) { - mspace_free(get_mspace(), mem); - 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, - 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; - } - pmm_arena_t *a{}; - size_t num_entries = 0; - list_for_every_entry(get_arena_list(), a, pmm_arena_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(get_arena_list(), a, pmm_arena_t, node) { - memory_map[i].physical_start = a->base; - memory_map[i].number_of_pages = a->size / PAGE_SIZE; - memory_map[i].attributes |= EFI_MEMORY_WB; - memory_map[i].memory_type = LOADER_CODE; - i++; - } - 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; -} - EfiStatus register_protocol_notify(const EfiGuid *protocol, EfiEvent event, void **registration) { printf("%s is unsupported\n", __FUNCTION__); @@ -350,11 +127,6 @@ EfiStatus allocate_pages(EfiAllocatorType type, EfiMemoryType memory_type, return SUCCESS; } -EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages) { - printf("%s is unsupported\n", __FUNCTION__); - return UNSUPPORTED; -} - EfiStatus uninstall_multiple_protocol_interfaces(EfiHandle handle, ...) { printf("%s is unsupported\n", __FUNCTION__); return UNSUPPORTED; @@ -407,67 +179,6 @@ EfiTpl raise_tpl(EfiTpl new_tpl) { return APPLICATION; } -EfiStatus reset(EfiBlockIoProtocol *self, bool extended_verification) { - printf("%s is called\n", __FUNCTION__); - return UNSUPPORTED; -} - -EfiStatus read_blocks(EfiBlockIoProtocol *self, uint32_t media_id, uint64_t lba, - size_t buffer_size, void *buffer) { - auto interface = reinterpret_cast(self); - auto dev = reinterpret_cast(interface->dev); - if (lba >= dev->block_count) { - printf("OOB read %llu %u\n", lba, dev->block_count); - return END_OF_MEDIA; - } - - const size_t bytes_read = - call_with_stack(interface->io_stack, bio_read_block, dev, buffer, lba, - buffer_size / dev->block_size); - if (bytes_read != buffer_size) { - printf("Failed to read %ld bytes from %s\n", buffer_size, dev->name); - return DEVICE_ERROR; - } - return SUCCESS; -} - -EfiStatus write_blocks(EfiBlockIoProtocol *self, uint32_t media_id, - uint64_t lba, size_t buffer_size, const void *buffer) { - printf("%s is called\n", __FUNCTION__); - return SUCCESS; -} - -EfiStatus flush_blocks(EfiBlockIoProtocol *self) { - printf("%s is called\n", __FUNCTION__); - return SUCCESS; -} - -EfiStatus open_block_device(EfiHandle handle, void **intf) { - static constexpr size_t kIoStackSize = 1024ul * 1024 * 64; - static void *io_stack = nullptr; - if (io_stack == nullptr) { - vmm_alloc(vmm_get_kernel_aspace(), "uefi_io_stack", kIoStackSize, &io_stack, - PAGE_SIZE_SHIFT, 0, 0); - } - printf("%s(%p)\n", __FUNCTION__, handle); - const auto interface = reinterpret_cast( - mspace_malloc(get_mspace(), sizeof(EfiBlockIoInterface))); - memset(interface, 0, sizeof(EfiBlockIoInterface)); - auto dev = bio_open(reinterpret_cast(handle)); - interface->dev = dev; - interface->protocol.reset = reset; - interface->protocol.read_blocks = read_blocks; - interface->protocol.write_blocks = write_blocks; - interface->protocol.flush_blocks = flush_blocks; - interface->protocol.media = &interface->media; - interface->media.block_size = dev->block_size; - interface->media.io_align = interface->media.block_size; - interface->media.last_block = dev->block_count - 1; - interface->io_stack = reinterpret_cast(io_stack) + kIoStackSize; - *intf = interface; - return SUCCESS; -} - EFI_STATUS efi_dt_fixup(struct EfiDtFixupProtocol *self, void *fdt, size_t *buffer_size, uint32_t flags) { auto offset = fdt_subnode_offset(fdt, 0, "chosen"); @@ -542,7 +253,7 @@ EfiStatus open_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf, EfiOpenProtocolAttributes attr) { if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { auto interface = reinterpret_cast( - mspace_malloc(get_mspace(), sizeof(EfiLoadedImageProtocol))); + uefi_malloc(sizeof(EfiLoadedImageProtocol))); memset(interface, 0, sizeof(*interface)); interface->parent_handle = handle; interface->image_base = handle; @@ -641,8 +352,8 @@ EfiStatus list_block_devices(size_t *num_handles, EfiHandle **buf) { device_count++; return true; }); - auto devices = reinterpret_cast( - mspace_malloc(get_mspace(), sizeof(char *) * device_count)); + auto devices = + reinterpret_cast(uefi_malloc(sizeof(char *) * device_count)); size_t i = 0; bio_iter_devices([&i, devices, device_count](bdev_t *dev) { devices[i] = dev->name; @@ -676,8 +387,7 @@ EfiStatus locate_handle_buffer(EfiLocateHandleSearchType search_type, *num_handles = 1; } if (buf != nullptr) { - *buf = reinterpret_cast( - mspace_malloc(get_mspace(), sizeof(buf))); + *buf = reinterpret_cast(uefi_malloc(sizeof(buf))); } return SUCCESS; } else if (guid_eq(protocol, EFI_DT_FIXUP_PROTOCOL_GUID)) { @@ -687,8 +397,7 @@ EfiStatus locate_handle_buffer(EfiLocateHandleSearchType search_type, *num_handles = 1; } if (buf != nullptr) { - *buf = reinterpret_cast( - mspace_malloc(get_mspace(), sizeof(buf))); + *buf = reinterpret_cast(uefi_malloc(sizeof(buf))); } return SUCCESS; } diff --git a/lib/uefi/boot_service_provider.h b/lib/uefi/boot_service_provider.h index d89d78f94..6db70f55b 100644 --- a/lib/uefi/boot_service_provider.h +++ b/lib/uefi/boot_service_provider.h @@ -17,9 +17,7 @@ #ifndef __BOOT_SERVICE_PROVIDER_ #define __BOOT_SERVICE_PROVIDER_ -#include "arch/defines.h" #include "boot_service.h" -#include "kernel/vm.h" #include "system_table.h" void setup_boot_service_table(EfiBootService *service); @@ -122,10 +120,5 @@ struct EFI_LOADED_IMAGE_PROTOCOL { }; static constexpr size_t EFI_LOADED_IMAGE_PROTOCOL_REVISION = 0x1000; -vmm_aspace_t *set_boot_aspace(); - -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); -void *identity_map(void *addr, size_t size); #endif diff --git a/lib/uefi/configuration_table.cpp b/lib/uefi/configuration_table.cpp index ab9133b3c..c9f10e0e0 100644 --- a/lib/uefi/configuration_table.cpp +++ b/lib/uefi/configuration_table.cpp @@ -16,8 +16,8 @@ */ #include "configuration_table.h" -#include "boot_service_provider.h" #include "libfdt.h" +#include "memory_protocols.h" #include "platform.h" #include "system_table.h" #include diff --git a/lib/uefi/memory_protocols.cpp b/lib/uefi/memory_protocols.cpp new file mode 100644 index 000000000..f79cd8ea8 --- /dev/null +++ b/lib/uefi/memory_protocols.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "memory_protocols.h" + +#include +#include +#include +#include + +#include "boot_service.h" +#include "types.h" + +static vmm_aspace_t *old_aspace = nullptr; + +namespace { +constexpr size_t kHeapSize = 256ul * 1024 * 1024; + +void *get_heap() { + static auto heap = alloc_page(kHeapSize); + return heap; +} + +mspace create_mspace_with_base_limit(void *base, size_t capacity, int locked) { + auto space = create_mspace_with_base(get_heap(), kHeapSize, 1); + mspace_set_footprint_limit(space, capacity); + return space; +} + +mspace get_mspace() { + static auto space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); + return space; +} +} // namespace + +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 (err) { + printf("Failed to create address space for linux kernel %d\n", err); + return nullptr; + } + old_aspace = vmm_set_active_aspace(aspace); + } + return aspace; +} + +void restore_aspace() { vmm_set_active_aspace(old_aspace); } + +void *identity_map(void *addr, size_t size) { + size = ROUNDUP(size, PAGE_SIZE); + auto vaddr = reinterpret_cast(addr); + paddr_t pa{}; + uint flags{}; + auto aspace = set_boot_aspace(); + auto err = arch_mmu_query(&aspace->arch_aspace, vaddr, &pa, &flags); + if (err) { + printf("Failed to query physical address for memory 0x%p\n", addr); + return nullptr; + } + + err = arch_mmu_unmap(&aspace->arch_aspace, vaddr, size / PAGE_SIZE); + if (err) { + printf("Failed to unmap virtual address 0x%lx\n", vaddr); + return nullptr; + } + arch_mmu_map(&aspace->arch_aspace, pa, pa, size / PAGE_SIZE, flags); + if (err) { + printf("Failed to identity map physical address 0x%lx\n", pa); + return nullptr; + } + printf("Identity mapped physical address 0x%lx size %zu flags 0x%x\n", pa, + size, flags); + + return reinterpret_cast(pa); +} + +void *alloc_page(size_t size, size_t align_log2) { + auto aspace = set_boot_aspace(); + void *vptr{}; + status_t err = vmm_alloc_contiguous(aspace, "uefi_program", size, &vptr, + align_log2, 0, 0); + if (err) { + printf("Failed to allocate memory for uefi program %d\n", err); + return nullptr; + } + return identity_map(vptr, size); +} + +void *alloc_page(void *addr, size_t size, size_t align_log2) { + if (addr == nullptr) { + return alloc_page(size, align_log2); + } + auto err = + vmm_alloc_contiguous(set_boot_aspace(), "uefi_program", size, &addr, + align_log2, VMM_FLAG_VALLOC_SPECIFIC, 0); + if (err) { + printf( + "Failed to allocate memory for uefi program @ fixed address 0x%p %d , " + "falling back to non-fixed allocation\n", + addr, err); + return alloc_page(size, align_log2); + } + return identity_map(addr, size); +} + +void *uefi_malloc(size_t size) { return mspace_malloc(get_mspace(), size); } + +EfiStatus allocate_pool(EfiMemoryType pool_type, size_t size, void **buf) { + if (buf == nullptr) { + return INVALID_PARAMETER; + } + if (size == 0) { + *buf = nullptr; + return SUCCESS; + } + *buf = mspace_malloc(get_mspace(), size); + if (*buf != nullptr) { + return SUCCESS; + } + return OUT_OF_RESOURCES; +} + +EfiStatus free_pool(void *mem) { + mspace_free(get_mspace(), mem); + return SUCCESS; +} + +EfiStatus free_pages(EfiPhysicalAddr memory, size_t pages) { + printf("%s is unsupported\n", __FUNCTION__); + return UNSUPPORTED; +} + +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, + 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; + } + pmm_arena_t *a{}; + size_t num_entries = 0; + list_for_every_entry(get_arena_list(), a, pmm_arena_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(get_arena_list(), a, pmm_arena_t, node) { + memory_map[i].physical_start = a->base; + memory_map[i].number_of_pages = a->size / PAGE_SIZE; + memory_map[i].attributes |= EFI_MEMORY_WB; + memory_map[i].memory_type = LOADER_CODE; + i++; + } + 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; +} diff --git a/lib/uefi/memory_protocols.h b/lib/uefi/memory_protocols.h new file mode 100644 index 000000000..2214e78d7 --- /dev/null +++ b/lib/uefi/memory_protocols.h @@ -0,0 +1,25 @@ +#ifndef __LIB_UEFI_MEMORY_PROTOCOLS_H +#define __LIB_UEFI_MEMORY_PROTOCOLS_H + +#include "types.h" +#include +#include + +#include "boot_service.h" + +vmm_aspace_t *set_boot_aspace(); + +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); +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); +EfiStatus free_pool(void *mem); + +EfiStatus get_physical_memory_map(size_t *memory_map_size, + EfiMemoryDescriptor *memory_map, + size_t *map_key, size_t *desc_size, + uint32_t *desc_version); + +#endif diff --git a/lib/uefi/rules.mk b/lib/uefi/rules.mk index 8d037e512..b2afeba64 100644 --- a/lib/uefi/rules.mk +++ b/lib/uefi/rules.mk @@ -11,6 +11,8 @@ MODULE_SRCS += \ $(LOCAL_DIR)/relocation.cpp \ $(LOCAL_DIR)/text_protocol.cpp \ $(LOCAL_DIR)/boot_service_provider.cpp \ + $(LOCAL_DIR)/memory_protocols.cpp \ + $(LOCAL_DIR)/blockio_protocols.cpp \ $(LOCAL_DIR)/runtime_service_provider.cpp \ $(LOCAL_DIR)/switch_stack.S \ $(LOCAL_DIR)/configuration_table.cpp \ diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index 42d37c72d..a98989547 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -18,6 +18,7 @@ #include "boot_service.h" #include "boot_service_provider.h" #include "defer.h" +#include "memory_protocols.h" #include "pe.h" #include "relocation.h"