diff options
Diffstat (limited to 'loader/main_efi.c')
| -rw-r--r-- | loader/main_efi.c | 324 |
1 files changed, 236 insertions, 88 deletions
diff --git a/loader/main_efi.c b/loader/main_efi.c index 8abf42a..7edb44d 100644 --- a/loader/main_efi.c +++ b/loader/main_efi.c @@ -1,129 +1,277 @@ -#include "loader_efi.h" +#include <loader/efi/shim.h> -#include <stdbool.h> -#include <stddef.h> +#include <efi.h> +#include <efidebug.h> +#include <efilib.h> -EFI_SYSTEM_TABLE *e_st; -EFI_BOOT_SERVICES *e_bs; -EFI_RUNTIME_SERVICES *e_rt; +#include "../lib/elf.h" -EFI_HANDLE e_image_handle; -EFI_LOADED_IMAGE_PROTOCOL *e_loaded_image; -EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *e_system_partition; -EFI_GRAPHICS_OUTPUT_PROTOCOL *e_graphics_output; -EFI_STATUS e_last_error; +EFI_STATUS alloc_page(EFI_MEMORY_TYPE type, + UINTN size, + EFI_PHYSICAL_ADDRESS *base); +EFI_STATUS free_page(EFI_PHYSICAL_ADDRESS base, UINTN size); -extern int _text; -extern int _data; +EFI_STATUS open_image(struct efi_loader_image *image); +EFI_STATUS allocate_image(struct efi_loader_image *image); +EFI_STATUS load_image(struct efi_loader_image *image); -static EFI_LOADED_IMAGE_PROTOCOL *open_loaded_image(void); -static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *open_system_partition(void); -static EFI_GRAPHICS_OUTPUT_PROTOCOL *open_graphics_output(void); +static EFI_STATUS enter_shim(void); + +static struct efi_loader_image shim_image = +{ + .path = L"\\adasoft\\sophia\\efi.os" +}; + +static struct efi_loader_interface loader_interface = +{ + &alloc_page, + &free_page, + + &open_image, + &allocate_image, + &load_image +}; EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) { - e_image_handle = image_handle; - e_st = system_table; - e_bs = e_st->BootServices; - e_rt = e_st->RuntimeServices; - - InitializeLib(e_image_handle, e_st); - Print(L"loader starting\r\n"); - - e_loaded_image = open_loaded_image(); - e_system_partition = open_system_partition(); - e_graphics_output = open_graphics_output(); + InitializeLib(image_handle, system_table); + + shim_image.image_handle = image_handle; + + EFI_STATUS status; + + if (EFI_ERROR((status = open_image(&shim_image)))) + { + Print(L"error opening shim image: %r\r\n"); + } + + if (EFI_ERROR((status = allocate_image(&shim_image)))) + { + Print(L"error allocating shim image: %r\r\n"); + } + + if (EFI_ERROR((status = load_image(&shim_image)))) + { + Print(L"error loading shim image: %r\r\n"); + } + + if (EFI_ERROR((status = enter_shim()))) + { + Print(L"error running shim image: %r\r\n"); + } + + if (shim_image.root) + { + shim_image.root->Close(shim_image.root); + } + if (shim_image.file) + { + shim_image.file->Close(shim_image.file); + } + + if (shim_image.buffer_base && shim_image.buffer_size) + { + free_page(shim_image.buffer_base, + EFI_SIZE_TO_PAGES(shim_image.buffer_size)); + } - WaitForSingleEvent(e_st->ConIn->WaitForKey, 0); - - loader_main(); + return status; +} - efi_exit(EFI_ABORTED); +EFI_STATUS alloc_page(EFI_MEMORY_TYPE type, + UINTN size, + EFI_PHYSICAL_ADDRESS *base) +{ + return gBS->AllocatePages(AllocateAnyPages, + type, + EFI_SIZE_TO_PAGES(size), + base); } -noreturn void efi_exit(EFI_STATUS status) +EFI_STATUS free_page(EFI_PHYSICAL_ADDRESS base, UINTN size) { - if (EFI_ERROR(status)) + return gBS->FreePages(base, size); +} + + +EFI_STATUS open_image(struct efi_loader_image *image) +{ + EFI_FILE_PROTOCOL *root; + + EFI_LOADED_IMAGE_PROTOCOL *loader_image; + + EFI_STATUS status; + + status = gBS->OpenProtocol(image->image_handle, + &LoadedImageProtocol, + (void *)&loader_image, + image->image_handle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + + if (EFI_ERROR(status) || + !(root = LibOpenRoot(loader_image->DeviceHandle))) + { + Print(L"failed opening root device\r\n"); + return EFI_NOT_FOUND; + } + + Print(L"opening image %s\r\n", image->path); + + status = root->Open(root, + &image->file, + image->path, + EFI_FILE_MODE_READ, + 0); + + if (!EFI_ERROR(status)) + { + image->root = root; + } + else { - Print(L"loader exited: %r\r\n", status); + Print(L"failed opening image: %r\r\n", status); + return status; } - - e_bs->Exit(e_image_handle, status, 0, NULL); - while (true); + Elf64_Ehdr ehdr; + UINTN ehdr_size = sizeof(ehdr); + + Elf64_Phdr *phdrs = NULL; + UINTN phdrs_size = 0; + + if (!EFI_ERROR((status = image->file->Read(image->file, + &ehdr_size, + &ehdr)))) + { + if (elf_validate(&ehdr, ET_EXEC, EM_X86_64)) + { + phdrs_size = ehdr.e_phentsize * ehdr.e_phnum; + phdrs = AllocatePool(phdrs_size); + ASSERT(phdrs); + } + else + { + FreePool(phdrs); + Print(L"invalid image format detected\r\n"); + return EFI_INVALID_PARAMETER; + } + } + else + { + Print(L"failed reading shim image headers\r\n"); + return status; + } + + if (!EFI_ERROR((status = image->file->Read(image->file, + &phdrs_size, + phdrs)))) + { + image->buffer_size = elf_size(&ehdr, phdrs); + image->system_table = gST; + Print(L"elf image %d bytes\r\n", image->buffer_size); + } + else + { + Print(L"failed reading shim image segments\r\n"); + } + + FreePool(phdrs); + + return status; } -static EFI_LOADED_IMAGE_PROTOCOL *open_loaded_image(void) +EFI_STATUS allocate_image(struct efi_loader_image *image) { - Print(L"opening loaded image\r\n"); - + Print(L"allocating image %s\r\n", image->path); EFI_STATUS status; - EFI_LOADED_IMAGE_PROTOCOL *image; - - status = e_bs->OpenProtocol(e_image_handle, - &LoadedImageProtocol, - (void **)&image, - e_image_handle, - NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - - if (EFI_ERROR(status)) + + status = alloc_page(SystemMemoryType, + image->buffer_size, + &image->buffer_base); + + if (!EFI_ERROR(status)) { - Print(L"failed opening loaded image\r\n"); - efi_exit(status); + gBS->SetMem((void *)image->buffer_base, image->buffer_size, 0); } - Print(L"image base: 0x%16.0x\r\n", image->ImageBase); - Print(L"image .text segment: 0x%16.0x\r\n", &_text); - Print(L"image .data segment: 0x%16.0x\r\n", &_data); - - return image; + return status; } -static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *open_system_partition(void) +static EFI_STATUS read_image(struct efi_loader_image *image, + VOID **buffer, + UINTN offset, + UINTN length) { - Print(L"opening system partition\r\n"); - + Print(L"reading %d bytes from image at 0x%8.0x %s\r\n", length, offset, image->path); EFI_STATUS status; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *partition; - - status = e_bs->OpenProtocol(e_loaded_image->DeviceHandle, - &FileSystemProtocol, - (void **)&partition, - e_image_handle, - NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(status)) + ASSERT(buffer); + + if (!EFI_ERROR((status = image->file->SetPosition(image->file, offset)))) { - Print(L"failed opening system partition\r\n"); - efi_exit(status); + *buffer = (void *)(image->buffer_base + offset); + status = image->file->Read(image->file, &length, *buffer); } - - Print(L"opened system partition\r\n"); - - return partition; + else + { + Print(L"failed seeking shim image\r\n"); + } + + return status; } -static EFI_GRAPHICS_OUTPUT_PROTOCOL *open_graphics_output(void) +EFI_STATUS load_image(struct efi_loader_image *image) { EFI_STATUS status; - EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics; - - Print(L"opening graphics output\r\n"); - - status = e_bs->LocateProtocol(&GraphicsOutputProtocol, - NULL, - (VOID **)&graphics); + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdrs; - if (EFI_ERROR(status)) + if (!EFI_ERROR((status = read_image(image, + (void **)&ehdr, + 0, + sizeof(*ehdr)))) && + !EFI_ERROR((status = read_image(image, + (void **)&phdrs, + ehdr->e_phoff, + ehdr->e_phnum * ehdr->e_phentsize)))) { - Print(L"failed opening graphics output: %r\r\n", status); - return NULL; + for (UINTN i = 0; i < ehdr->e_phnum && !EFI_ERROR(status); i++) + { + if (PT_LOAD != phdrs[i].p_type) + { + continue; + } + + void *placement; + status = read_image(image, + &placement, + phdrs[i].p_offset, + phdrs[i].p_filesz); + + if (!EFI_ERROR(status)) + { + Print(L"loaded segment 0x%16.0x of %d bytes " + L"(file size %d bytes)\r\n", + placement, + phdrs[i].p_memsz, + phdrs[i].p_filesz); + } + } } - Print(L"graphics output opened\r\n"); + return status; +} + +static EFI_STATUS enter_shim(void) +{ + EFI_STATUS status; + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)shim_image.buffer_base; + efi_shim_entry_func entry; - return graphics; + entry = (efi_shim_entry_func)(shim_image.buffer_base + ehdr->e_entry); + status = entry(&shim_image, &loader_interface); + return status; } |
