summaryrefslogtreecommitdiff
path: root/loader/main_efi.c
diff options
context:
space:
mode:
Diffstat (limited to 'loader/main_efi.c')
-rw-r--r--loader/main_efi.c324
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;
}