From e2ce1434c0d8adbcad70bc77b1261f52407e06e3 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 12 Jun 2024 12:44:34 -0700 Subject: [PATCH] Add section loading and entry point execution to UEFI loader This loads all sections specified by PE header at the correct memory location, and executes the entry point function. Only the OutputString function of text output protocol is implemented, so the only application we can run is hello world. Test: th Bug: 294283461 Change-Id: I786bc8b7db9e1c0a6019b8fe4ba5a8c8ab4f2936 --- lib/uefi/README.md | 29 ++++++++++++++ lib/uefi/helloworld_aa64.efi | Bin 0 -> 16896 bytes lib/uefi/rules.mk | 2 + lib/uefi/uefi.cpp | 75 +++++++++++++++++++++++++++++++++-- 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 lib/uefi/README.md create mode 100755 lib/uefi/helloworld_aa64.efi diff --git a/lib/uefi/README.md b/lib/uefi/README.md new file mode 100644 index 000000000..3b3179271 --- /dev/null +++ b/lib/uefi/README.md @@ -0,0 +1,29 @@ +## Build + +``` +make qemu-virt-arm64-test +``` + +## Run + +``` +qemu-system-aarch64 -cpu max -m 512 -smp 1 -machine virt,highmem=off \ + -kernel qemu-virt-arm64-test/lk.elf \ + -net none -nographic \ + -drive if=none,file=lib/uefi/helloworld_aa64.efi,id=blk,format=raw \ + -device virtio-blk-device,drive=blk +``` + + +Once you see the main console prompt, enter `uefi_load virtio0` to load the hello world UEFI application. + +``` +starting app shell +entering main console loop +] uefi_load virtio0 +bio_read returns 4096, took 1 msecs (4096000 bytes/sec) +PE header machine type: aa64 +Valid UEFI application found. +Entry function located at 0xffff000780067380 +Hello World! +``` \ No newline at end of file diff --git a/lib/uefi/helloworld_aa64.efi b/lib/uefi/helloworld_aa64.efi new file mode 100755 index 0000000000000000000000000000000000000000..e9ef0b0b6b28e45566547c320e9d9388a3277294 GIT binary patch literal 16896 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 N2AJP@_*rP+zX3M+Ji!0} literal 0 HcmV?d00001 diff --git a/lib/uefi/rules.mk b/lib/uefi/rules.mk index caabd1657..4b250d3e0 100644 --- a/lib/uefi/rules.mk +++ b/lib/uefi/rules.mk @@ -2,6 +2,8 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) +MODULE_INCLUDES += $(LOCAL_DIR)/include + MODULE_SRCS += \ $(LOCAL_DIR)/uefi.cpp \ diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index ec2cf0694..e676f97da 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -1,4 +1,5 @@ #include "defer.h" +#include "kernel/vm.h" #include "pe.h" #include @@ -8,10 +9,79 @@ #include #include #include +#include #include +#include + +#include "efi.h" // ASCII "PE\x0\x0" -static constexpr uint32_t kPEHeader = 0x4550; + +EfiStatus output_string(struct EfiSimpleTextOutputProtocol *self, + char16_t *string) { + char buffer[512]; + size_t i = 0; + while (string[i]) { + size_t j = 0; + for (j = 0; j < sizeof(buffer) - 1 && string[i + j]; j++) { + buffer[j] = string[i + j]; + } + i += j; + buffer[j] = 0; + + printf("%s", reinterpret_cast(buffer)); + } + return SUCCESS; +} + +typedef int (*EfiEntry)(void *handle, struct EfiSystemTable *system); + +void *alloc_page(size_t size) { + void *vptr{}; + status_t err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "uefi_program", + size, &vptr, 0, 0, 0); + if (err) { + printf("Failed to allocate memory for uefi program %d\n", err); + return nullptr; + } + return vptr; +} + +int load_sections_and_execute(bdev_t *dev, + const IMAGE_NT_HEADERS64 *pe_header) { + const auto file_header = &pe_header->FileHeader; + const auto optional_header = &pe_header->OptionalHeader; + const auto sections = file_header->NumberOfSections; + const auto section_header = reinterpret_cast( + reinterpret_cast(pe_header) + sizeof(*pe_header)); + for (size_t i = 0; i < sections; i++) { + if (section_header[i].NumberOfRelocations != 0) { + printf("Section %s requires relocation, which is not supported.\n", + section_header[i].Name); + return -6; + } + } + const auto &last_section = section_header[sections - 1]; + const auto virtual_size = + last_section.VirtualAddress + last_section.Misc.VirtualSize; + const auto image_base = reinterpret_cast(alloc_page(virtual_size)); + memset(image_base, 0, virtual_size); + + for (size_t i = 0; i < sections; i++) { + const auto §ion = section_header[i]; + bio_read(dev, image_base + section.VirtualAddress, section.PointerToRawData, + section.SizeOfRawData); + } + auto entry = reinterpret_cast(image_base + + optional_header->AddressOfEntryPoint); + printf("Entry function located at %p\n", entry); + + EfiSystemTable table; + EfiSimpleTextOutputProtocol console_out; + console_out.output_string = output_string; + table.con_out = &console_out; + return entry(nullptr, &table); +} int load_pe_file(const char *blkdev) { bdev_t *dev = bio_open(blkdev); @@ -58,8 +128,7 @@ int load_pe_file(const char *blkdev) { ToString(optional_header->Subsystem)); } printf("Valid UEFI application found.\n"); - - return 0; + return load_sections_and_execute(dev, pe_header); } int cmd_uefi_load(int argc, const console_cmd_args *argv) {