Skip to content

Commit

Permalink
Add section loading and entry point execution to UEFI loader
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Kelvin Zhang committed Jun 14, 2024
1 parent 4bc9bc1 commit 1490f73
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 3 deletions.
29 changes: 29 additions & 0 deletions lib/uefi/README.md
Original file line number Diff line number Diff line change
@@ -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!
```
Binary file added lib/uefi/helloworld_aa64.efi
Binary file not shown.
2 changes: 2 additions & 0 deletions lib/uefi/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ LOCAL_DIR := $(GET_LOCAL_DIR)

MODULE := $(LOCAL_DIR)

MODULE_INCLUDES += $(LOCAL_DIR)/include

MODULE_SRCS += \
$(LOCAL_DIR)/uefi.cpp \

Expand Down
75 changes: 72 additions & 3 deletions lib/uefi/uefi.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "defer.h"
#include "kernel/vm.h"
#include "pe.h"

#include <lib/bio.h>
Expand All @@ -8,10 +9,79 @@
#include <lk/err.h>
#include <lk/trace.h>
#include <platform.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>

#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<const char *>(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<const IMAGE_SECTION_HEADER *>(
reinterpret_cast<const char *>(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<char *>(alloc_page(virtual_size));
memset(image_base, 0, virtual_size);

for (size_t i = 0; i < sections; i++) {
const auto &section = section_header[i];
bio_read(dev, image_base + section.VirtualAddress, section.PointerToRawData,
section.SizeOfRawData);
}
auto entry = reinterpret_cast<EfiEntry>(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);
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 1490f73

Please sign in to comment.