diff options
| author | Ada Christine <adachristine18@gmail.com> | 2021-12-16 12:06:04 +0000 |
|---|---|---|
| committer | Ada Christine <adachristine18@gmail.com> | 2021-12-16 12:06:04 +0000 |
| commit | ec1233b4fcd61a8d1eccbf030cede36e9848e06c (patch) | |
| tree | 13ffdc3b3948275e8c764ccf10368d555ff4d5e1 | |
| parent | a7f79219706c357c6c15978cea5e654042b14acb (diff) | |
reworking loader
| -rw-r--r-- | api/kernel/entry.h | 1 | ||||
| -rw-r--r-- | api/kernel/memory/paging.h | 1 | ||||
| -rw-r--r-- | api/kernel/memory/range.h | 2 | ||||
| -rw-r--r-- | api/loader/data_efi.h | 49 | ||||
| -rw-r--r-- | api/loader/efi/shim.h | 47 | ||||
| -rw-r--r-- | api/loader/shim.h | 4 | ||||
| -rw-r--r-- | loader/Makefile | 2 | ||||
| -rw-r--r-- | loader/image_efi.c | 211 | ||||
| -rw-r--r-- | loader/loader_efi.c | 182 | ||||
| -rw-r--r-- | loader/loader_efi.h | 64 | ||||
| -rw-r--r-- | loader/main_efi.c | 324 | ||||
| -rw-r--r-- | loader/memory_efi.c | 55 | ||||
| -rw-r--r-- | loader/paging_efi.c | 155 | ||||
| -rw-r--r-- | shim/Makefile | 36 | ||||
| -rw-r--r-- | shim/entry.c | 83 | ||||
| -rw-r--r-- | shim/shim.ld | 49 |
16 files changed, 460 insertions, 805 deletions
diff --git a/api/kernel/entry.h b/api/kernel/entry.h index 8a26125..d119ca1 100644 --- a/api/kernel/entry.h +++ b/api/kernel/entry.h @@ -5,3 +5,4 @@ #define KERNEL_ENTRY_STACK_BASE ((char *)KERNEL_ENTRY_STACK_HEAD - KERNEL_ENTRY_STACK_SIZE) typedef void (*kernel_entry_func)(void *data); + diff --git a/api/kernel/memory/paging.h b/api/kernel/memory/paging.h index fc1aa45..000d12b 100644 --- a/api/kernel/memory/paging.h +++ b/api/kernel/memory/paging.h @@ -31,3 +31,4 @@ #define page_address(a, l) ((uintptr_t)a & ~(page_size(l) - 1)) #define page_offset(a, l) ((uintptr_t)a & (page_size(l) - 1)) #define page_count(s, l) (((s + page_size(l) - 1) & ~(page_size(l) - 1)) / page_size(l)) + diff --git a/api/kernel/memory/range.h b/api/kernel/memory/range.h index 6a68467..90b3354 100644 --- a/api/kernel/memory/range.h +++ b/api/kernel/memory/range.h @@ -11,6 +11,7 @@ enum memory_range_type RESERVED_MEMORY, SYSTEM_MEMORY, AVAILABLE_MEMORY, + INVALID_MEMORY = 0xff }; struct memory_range @@ -19,3 +20,4 @@ struct memory_range phys_addr_t base; size_t size; }; + diff --git a/api/loader/data_efi.h b/api/loader/data_efi.h deleted file mode 100644 index e5d1dd4..0000000 --- a/api/loader/data_efi.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include <kernel/memory/range.h> - -#include <efi.h> - -#include <stddef.h> - -#define UserMemoryType ((EFI_MEMORY_TYPE)0x80000000) -#define SystemMemoryType (UserMemoryType|0x01) - -enum efi_boot_data_type -{ - MEMORY_MAP_DATA, - FRAMEBUFFER_DATA, - ACPI_DATA, -}; - -struct efi_memory_map_data -{ - UINTN size; - UINTN key; - UINTN descsize; - UINT32 descver; - EFI_MEMORY_DESCRIPTOR data[]; -}; - -struct efi_framebuffer_data -{ - struct memory_range buffer; - UINT32 width; - UINT32 height; - UINT32 pitch; - UINT8 pxsize; - EFI_PIXEL_BITMASK bitmask; - EFI_GRAPHICS_PIXEL_FORMAT pxformat; -}; - -struct efi_acpi_data -{ - void *rsdp; -}; - -struct efi_boot_data -{ - struct efi_memory_map_data *memory_map; - struct efi_framebuffer_data *framebuffer; - struct efi_acpi_data *acpi; -}; diff --git a/api/loader/efi/shim.h b/api/loader/efi/shim.h new file mode 100644 index 0000000..3486c34 --- /dev/null +++ b/api/loader/efi/shim.h @@ -0,0 +1,47 @@ +#pragma once + +#include <loader/shim.h> + +#include <efi.h> + +#ifdef __ELF__ + #define EFIEXPORT __attribute__((visibility("default"))) +#else + #define EFIEXPORT __declspec(dllexport) +#endif + +#define OsVendorMemoryType(t) ((EFI_MEMORY_TYPE)(0x80000000|t)) +#define SystemMemoryType OsVendorMemoryType(1) + +struct efi_loader_image; + +struct efi_loader_image +{ + CHAR16 *path; + EFI_HANDLE image_handle; + EFI_SYSTEM_TABLE *system_table; + EFI_FILE_PROTOCOL *root; + EFI_FILE_PROTOCOL *file; + EFI_PHYSICAL_ADDRESS buffer_base; + UINTN buffer_size; +}; + +typedef EFI_STATUS (*efi_image_func)(struct efi_loader_image *image); +typedef EFI_STATUS (*efi_page_alloc_func)(EFI_MEMORY_TYPE type, + UINTN size, + EFI_PHYSICAL_ADDRESS *base); +typedef EFI_STATUS (*efi_page_free_func)(EFI_PHYSICAL_ADDRESS base, UINTN size); + +struct efi_loader_interface +{ + efi_page_alloc_func page_alloc; + efi_page_free_func page_free; + + efi_image_func image_open; + efi_image_func image_alloc; + efi_image_func image_load; +}; + +typedef EFI_STATUS (*efi_shim_entry_func)(struct efi_loader_image *image, + struct efi_loader_interface *interface); + diff --git a/api/loader/shim.h b/api/loader/shim.h new file mode 100644 index 0000000..531a62b --- /dev/null +++ b/api/loader/shim.h @@ -0,0 +1,4 @@ +#pragma once + + + diff --git a/loader/Makefile b/loader/Makefile index 975c2ce..dd8c21c 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -10,7 +10,7 @@ CPPFLAGS += -I../api all: $(BUILD) -OBJS := main_efi.o loader_efi.o paging_efi.o memory_efi.o image_efi.o \ +OBJS := main_efi.o elf.o \ memcmp.o memmove.o DEPS := $(OBJS:.o=.d) diff --git a/loader/image_efi.c b/loader/image_efi.c deleted file mode 100644 index 04d0a9b..0000000 --- a/loader/image_efi.c +++ /dev/null @@ -1,211 +0,0 @@ -#include "loader_efi.h" - -static bool validate_image(Elf64_Ehdr *ehdr); -static size_t image_size(struct system_image *image); -static enum page_type get_page_type(Elf64_Phdr *phdr); - -struct system_image *system_image_open(CHAR16 *path) -{ - EFI_STATUS status; - EFI_FILE_PROTOCOL *root; - EFI_FILE_PROTOCOL *file; - struct system_image *image = NULL; - - status = e_system_partition->OpenVolume(e_system_partition, &root); - - if (EFI_ERROR(status)) - { - Print(L"failed opening system partition root: %r\r\n", status); - return NULL; - } - - status = root->Open(root, &file, path, EFI_FILE_MODE_READ, 0); - - if (EFI_ERROR(status)) - { - Print(L"failed opening image file %s: %r\r\n", path, status); - return NULL; - } - - image = efi_allocate(sizeof(*image)); - - if (!image) - { - Print(L"failed allocating image data: %r\r\n", e_last_error); - goto failure; - } - - image->file = file; - - UINTN ehdr_size = sizeof(image->ehdr); - status = file->Read(file, &ehdr_size, &image->ehdr); - - if (EFI_ERROR(status)) - { - Print(L"failed reading image file %s: %r\r\n", path, status); - goto failure; - } - - if (!validate_image(&image->ehdr)) - { - Print(L"failed validating image file %s: %r\r\n", path, status); - goto failure; - } - - UINTN phdrs_size = image->ehdr.e_phentsize * image->ehdr.e_phnum; - image->phdrs = efi_allocate(phdrs_size); - - if (!image->phdrs) - { - Print(L"failed allocating segment data: %r", e_last_error); - goto failure; - } - - status = file->Read(file, &phdrs_size, image->phdrs); - - if (EFI_ERROR(status)) - { - Print(L"failed reading segment data: %r", status); - goto failure; - } - - return image; - -failure: - file->Close(file); - return NULL; -} - -bool system_image_load(struct system_image *image) -{ - image->buffer = system_allocate(image_size(image)); - - if (image->buffer.type != SYSTEM_MEMORY) - { - return false; - } - - e_bs->SetMem((VOID *)image->buffer.base, image->buffer.size, 0); - - Elf64_Ehdr *ehdr = &image->ehdr; - Elf64_Phdr *phdrs = image->phdrs; - - Print(L"found %d segments in image\r\n", ehdr->e_phnum); - - EFI_STATUS status = EFI_SUCCESS; - - for (UINTN i = 0; i < ehdr->e_phnum && !EFI_ERROR(status); i++) - { - switch (phdrs[i].p_type) - { - case PT_LOAD: - Print(L"loadable segment %16.0lx at offset %x of %d bytes\r\n", - phdrs[i].p_vaddr, - phdrs[i].p_offset, - phdrs[i].p_memsz); - - void *segment = (void *)(image->buffer.base + phdrs[i].p_paddr); - UINTN segment_size = phdrs[i].p_filesz; - - image->file->SetPosition(image->file, phdrs[i].p_offset); - status = image->file->Read(image->file, &segment_size, segment); - break; - default: - continue; - } - } - - if (EFI_ERROR(status)) - { - Print(L"failure reading segment from file: %r\r\n", status); - return false; - } - - return true; -} - -void system_image_map(struct system_image *image) -{ - Elf64_Ehdr *ehdr = &image->ehdr; - Elf64_Phdr *phdrs = image->phdrs; - - for (int i = 0; i < ehdr->e_phnum; i++) - { - if (phdrs[i].p_type == PT_LOAD) - { - void *virt_begin = (void *)phdrs[i].p_vaddr; - uint64_t phys_begin = image->buffer.base + phdrs[i].p_paddr; - size_t size = phdrs[i].p_memsz; - Print(L"mapping segment %16.0lx to %16.0lx %d bytes\r\n", - virt_begin, - phys_begin, - size); - - paging_map_pages(virt_begin, - phys_begin, - get_page_type(&phdrs[i]), - size); - } - } -} - - -static bool validate_image(Elf64_Ehdr *ehdr) -{ - if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || - ehdr->e_ident[EI_MAG1] != ELFMAG1 || - ehdr->e_ident[EI_MAG2] != ELFMAG2 || - ehdr->e_ident[EI_MAG3] != ELFMAG3 || - ehdr->e_ident[EI_CLASS] != ELFCLASS64 || - ehdr->e_ident[EI_DATA] != ELFDATA2LSB || - ehdr->e_ident[EI_VERSION] != EV_CURRENT || - ehdr->e_machine != EM_X86_64) - { - Print(L"invalid image format\r\n"); - return false; - } - - Print(L"elf x64 image detected\r\n"); - - return true; -} - -static size_t image_size(struct system_image *image) -{ - size_t size = 0; - Elf64_Phdr *phdrs = image->phdrs; - - for (int i = 0; i < image->ehdr.e_phnum; i++) - { - if (phdrs[i].p_type != PT_LOAD) - { - continue; - } - - if (phdrs[i].p_paddr + phdrs[i].p_memsz > size) - { - size = phdrs[i].p_paddr + phdrs[i].p_memsz; - if (phdrs[i].p_align > 1) - { - size = (size + phdrs[i].p_align - 1) & ~(phdrs[i].p_align - 1); - } - } - } - - return size; -} - -static enum page_type get_page_type(Elf64_Phdr *phdr) -{ - switch (phdr->p_flags) - { - case (PF_R|PF_X): - return CODE_PAGE_TYPE; - case (PF_R): - return RODATA_PAGE_TYPE; - case (PF_R|PF_W): - return DATA_PAGE_TYPE; - } - - return INVALID_PAGE_TYPE; -} diff --git a/loader/loader_efi.c b/loader/loader_efi.c deleted file mode 100644 index 23540ef..0000000 --- a/loader/loader_efi.c +++ /dev/null @@ -1,182 +0,0 @@ -#include "loader_efi.h" - -#include <loader/data_efi.h> - -#include <kernel/entry.h> - -static CHAR16 *kernel_path = L"\\adasoft\\sophia\\kernel.os"; -static struct system_image *kernel_image = NULL; - -static struct efi_memory_map_data *get_memory_map_data(void); -static struct efi_framebuffer_data *get_framebuffer_data(void); -static void *get_acpi_data(void); - -noreturn static void enter_kernel() -{ - struct efi_boot_data data; - kernel_entry_func kernel_entry; - kernel_entry = (kernel_entry_func)(kernel_image->ehdr.e_entry); - - struct memory_range kernel_entry_stack = - system_allocate(KERNEL_ENTRY_STACK_SIZE); - - // get a stack here for now idfk - paging_map_range(KERNEL_ENTRY_STACK_BASE, - &kernel_entry_stack, - DATA_PAGE_TYPE); - - data.acpi = get_acpi_data(); - data.framebuffer = get_framebuffer_data(); - data.memory_map = get_memory_map_data(); - - EFI_STATUS status = e_bs->ExitBootServices(e_image_handle, - data.memory_map->key); - - if (EFI_ERROR(status)) - { - Print(L"failed exiting boot services environment: %r\r\n", status); - efi_exit(status); - } - - // enter the kernel address environment - paging_enter(); - - // set the kernel entry stack. - __asm__ - ( - "mov %0, %%rsp" - : - : "r"((uint64_t)KERNEL_ENTRY_STACK_HEAD) - ); - - kernel_entry(&data); - - while(true); -} - -void loader_main(void) -{ - kernel_image = system_image_open(kernel_path); - - Print(L"loading %s\r\n", kernel_path); - - if (system_image_load(kernel_image)) - { - Print(L"loaded kernel image at base %16.0lx size %d bytes\r\n", - kernel_image->buffer.base, - kernel_image->buffer.size); - } - else - { - Print(L"failed loading kernel image\r\n"); - efi_exit(EFI_ABORTED); - } - - paging_init(); - system_image_map(kernel_image); - Print(L"kernel maps created. entering kernel\r\n"); - enter_kernel(); - - efi_exit(EFI_ABORTED); -} - -static struct efi_memory_map_data *get_memory_map_data(void) -{ - EFI_STATUS status; - UINTN mapsize = 0; - struct efi_memory_map_data *map = NULL; - - status = e_bs->GetMemoryMap(&mapsize, NULL, NULL, NULL, NULL); - - if (status == EFI_BUFFER_TOO_SMALL) - { - map = efi_allocate(sizeof(*map) + mapsize); - } - - if (map) - { - status = e_bs->GetMemoryMap(&map->size, - map->data, - &map->key, - &map->descsize, - &map->descver); - } - else - { - status = e_last_error; - } - - if (EFI_ERROR(status)) - { - Print(L"failed getting memory map: %r\r\n", status); - return NULL; - } - - return map; -} - -static struct efi_framebuffer_data *get_framebuffer_data(void) -{ - struct efi_framebuffer_data *framebuffer; - - if (!e_graphics_output) - { - return NULL; - } - - framebuffer = efi_allocate(sizeof(*framebuffer)); - - if (framebuffer) - { - EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode = e_graphics_output->Mode; - - framebuffer->bitmask = mode->Info->PixelInformation; - framebuffer->width = mode->Info->HorizontalResolution; - framebuffer->height = mode->Info->VerticalResolution; - framebuffer->buffer.base = mode->FrameBufferBase; - framebuffer->buffer.size = mode->FrameBufferSize; - framebuffer->buffer.type = RESERVED_MEMORY; - framebuffer->pxformat = mode->Info->PixelFormat; - - switch (framebuffer->pxformat) - { - //falthrough - case PixelBlueGreenRedReserved8BitPerColor: - case PixelRedGreenBlueReserved8BitPerColor: - framebuffer->pxsize = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); - break; - default: - // TODO: calculate pixel size for bitmask format - framebuffer->pxsize = 0; - } - - framebuffer->pitch = framebuffer->width * framebuffer->pxsize; - } - else - { - Print(L"failed getting framebuffer data: %r\r\n", e_last_error); - return NULL; - } - - return framebuffer; -} - -static void *get_acpi_data(void) -{ - struct efi_acpi_data *acpi = efi_allocate(sizeof(*acpi)); - - EFI_GUID acpi_20_guid = ACPI_20_TABLE_GUID; - - for (UINTN i = 0; acpi && i < e_st->NumberOfTableEntries; i++) - { - if (!CompareGuid(&acpi_20_guid, &e_st->ConfigurationTable[i].VendorGuid)) - { - acpi->rsdp = e_st->ConfigurationTable[i].VendorTable; - return acpi; - } - } - - Print(L"failed getting acpi rsdp\r\n"); - return NULL; -} - diff --git a/loader/loader_efi.h b/loader/loader_efi.h deleted file mode 100644 index 4ce3098..0000000 --- a/loader/loader_efi.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include <kernel/memory/range.h> -#include <kernel/memory/paging.h> - -#include <elf/elf64.h> - -#include <efi.h> -#include <efilib.h> - -#include <stdbool.h> -#include <stddef.h> -#include <stdnoreturn.h> - -enum page_type -{ - INVALID_PAGE_TYPE = 0x0, - CODE_PAGE_TYPE = PAGE_PR, - RODATA_PAGE_TYPE = PAGE_PR|PAGE_NX, - DATA_PAGE_TYPE = PAGE_PR|PAGE_WR|PAGE_NX -}; - -struct system_image -{ - struct memory_range buffer; - EFI_FILE_PROTOCOL *file; - Elf64_Ehdr ehdr; - Elf64_Phdr *phdrs; -}; - -extern EFI_SYSTEM_TABLE *e_st; -extern EFI_BOOT_SERVICES *e_bs; -extern EFI_RUNTIME_SERVICES *e_rt; - -extern EFI_HANDLE e_image_handle; -extern EFI_LOADED_IMAGE_PROTOCOL *e_loaded_image; -extern EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *e_system_partition; -extern EFI_GRAPHICS_OUTPUT_PROTOCOL *e_graphics_output; -extern EFI_STATUS e_last_error; - -noreturn void efi_exit(EFI_STATUS status); - -struct memory_range system_allocate(size_t size); - -void *efi_allocate(size_t size); -void efi_free(void *buffer); - -void paging_init(void); -void paging_enter(void); -void *paging_map_page(void *vaddr, phys_addr_t paddr, enum page_type type); -void *paging_map_pages(void *vaddr, - phys_addr_t paddr, - enum page_type type, - size_t size); -void *paging_map_range(void *vaddr, - struct memory_range *range, - enum page_type type); - -struct system_image *system_image_open(CHAR16 *path); -bool system_image_load(struct system_image *image); -void system_image_map(struct system_image *image); - -void loader_main(void); - 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; } diff --git a/loader/memory_efi.c b/loader/memory_efi.c deleted file mode 100644 index 2fab6b7..0000000 --- a/loader/memory_efi.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "loader_efi.h" - -#include <loader/data_efi.h> -#include <kernel/memory/paging.h> - -struct memory_range system_allocate(size_t size) -{ - EFI_STATUS status; - struct memory_range buffer; - - buffer.type = SYSTEM_MEMORY; - buffer.size = size; - - status = e_bs->AllocatePages(AllocateAnyPages, - SystemMemoryType, - page_count(buffer.size, 1), - &buffer.base); - - if (EFI_ERROR(status)) - { - Print(L"error allocating range: %r\r\n", status); - e_last_error = status; - buffer.type = UNUSABLE_MEMORY; - } - - return buffer; -} - -void *efi_allocate(size_t size) -{ - EFI_STATUS status; - void *buffer; - - status = e_bs->AllocatePool(EfiLoaderData, size, &buffer); - - if (EFI_ERROR(status)) - { - e_last_error = status; - buffer = NULL; - } - - return buffer; -} - -void efi_free(void *buffer) -{ - EFI_STATUS status; - - status = e_bs->FreePool(buffer); - - if (EFI_ERROR(status)) - { - e_last_error = status; - } -} diff --git a/loader/paging_efi.c b/loader/paging_efi.c deleted file mode 100644 index 5f65213..0000000 --- a/loader/paging_efi.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "loader_efi.h" - -#include <kernel/memory/paging.h> - -#define KERNEL_SPACE_LOWER (void *)0xffffffff80000000 -#define KERNEL_SPACE_UPPER (void *)0xffffffffc0000000 - -static uint64_t *new_page_table(void); -static uint64_t *get_page_table(void *vaddr, int level); -static uint64_t *get_page_entry(void *vaddr); - -static uint64_t *get_page_map(void); -static void set_page_map(uint64_t *map); - -static uint64_t *efi_page_map = NULL; -static uint64_t *system_page_map = NULL; - -void paging_init(void) -{ - efi_page_map = get_page_map(); - system_page_map = new_page_table(); - - if (!system_page_map) - { - Print(L"error creating page map: %r\r\n", e_last_error); - efi_exit(e_last_error); - } - - // copy the identity mappings from the EFI PML4. - system_page_map[0] = efi_page_map[0]; - - // create kernel fractal mappings - // TODO: move this into the kernel instead? - uint64_t *lower_pm2 = get_page_table(KERNEL_SPACE_LOWER, 2); - uint64_t *upper_pm2 = get_page_table(KERNEL_SPACE_UPPER, 2); - - upper_pm2[PAGE_TABLE_INDEX_MASK - 1] = (phys_addr_t)lower_pm2|DATA_PAGE_TYPE; - upper_pm2[PAGE_TABLE_INDEX_MASK] = (phys_addr_t)upper_pm2|DATA_PAGE_TYPE; -} - -void paging_enter(void) -{ - // use the system_page_map instead of efi_page_map - set_page_map(system_page_map); -} - -void *paging_map_page(void *vaddr, phys_addr_t paddr, enum page_type type) -{ - uint64_t *entry = get_page_entry(vaddr); - - if (entry) - { - *entry = paddr | type; - return vaddr; - } - - return NULL; -} - -void *paging_map_pages(void *vaddr, - phys_addr_t paddr, - enum page_type type, - size_t size) -{ - for (size_t offset = 0; offset < size; offset += page_size(1)) - { - if (!paging_map_page((char *)vaddr + offset, paddr + offset, type)) - { - return NULL; - } - } - - return vaddr; -} - -void *paging_map_range(void *vaddr, - struct memory_range *range, - enum page_type type) -{ - return paging_map_pages(vaddr, range->base, type, range->size); -} - -static uint64_t *new_page_table(void) -{ - struct memory_range table = system_allocate(page_size(1)); - - if (table.type == SYSTEM_MEMORY) - { - e_bs->SetMem((void *)table.base, table.size, 0); - return (uint64_t *)table.base; - } - - return NULL; -} - -static uint64_t *get_page_table(void *vaddr, int level) -{ - // don't try to do anything if there's no page map. - if (!system_page_map) - { - return NULL; - } - - // don't try to do anything outside of the page map - if ((level < 1) || (level > PAGE_MAP_LEVELS)) - { - return NULL; - } - - // don't use a non-canonical address - - uint64_t *map = system_page_map; - - for (int i = PAGE_MAP_LEVELS; i > level; i--) - { - if (!map[pte_index(vaddr, i)]) - { - uint64_t *next_map = new_page_table(); - map[pte_index(vaddr, i)] = (phys_addr_t)next_map|PAGE_PR|PAGE_WR; - map = next_map; - } - else - { - map = (uint64_t *)page_address(map[pte_index(vaddr, i)], 1); - } - } - - return map; -} - -static uint64_t *get_page_entry(void *vaddr) -{ - uint64_t *table = get_page_table(vaddr, 1); - return &table[pte_index(vaddr, 1)]; -} - -static uint64_t *get_page_map(void) -{ - uint64_t map; - __asm__("mov %%cr3, %0" : "=r"(map)); - return (uint64_t *)(page_address(map, 1)); -} - -static void set_page_map(uint64_t *map) -{ - __asm__ - ( - "pushf\r\n" - "cli\r\n" - "mov %0, %%cr3\r\n" - "popf" - : - : "r"(map) - ); -} diff --git a/shim/Makefile b/shim/Makefile new file mode 100644 index 0000000..51ec96c --- /dev/null +++ b/shim/Makefile @@ -0,0 +1,36 @@ +include ../defaults.mk + +VPATH := ../lib + +TARGET := efi.os +.DEFAULT: $(TARGET) + +# EFI API for temporary things + +EFIAPIDIR := /usr/local/include/efi + +CPPFLAGS += -I../api -I$(EFIAPIDIR) -I$(EFIAPIDIR)/$(ARCH) -I$(EFIAPIDIR)/protocol +CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden \ + -g -fshort-wchar -mgeneral-regs-only + +LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) +LDSCRIPT := shim.ld +LDFLAGS += -z max-page-size=4096 --export-dynamic +LOADLIBES := -lgcc + +OBJS := entry.o memcmp.o memcpy.o memmove.o memset.o +$(OBJS): CFLAGS += -fPIC -fPIE + +DEPS := $(patsubst %.o,%.d,$(OBJS)) + +$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) +$(TARGET): $(OBJS) + +CLEANLIST := $(wildcard $(OBJS) $(TARGET)) +DCLEANLIST := $(wildcard $(DEPS)) + +include ../rules.mk +-include $(DEPS) + +.DEFAULT: $(TARGET) + diff --git a/shim/entry.c b/shim/entry.c new file mode 100644 index 0000000..303f582 --- /dev/null +++ b/shim/entry.c @@ -0,0 +1,83 @@ +#include <loader/efi/shim.h> +#include <kernel/memory/range.h> + +#include <stdbool.h> + +#include "../lib/elf.h" + +struct efi_memory_map +{ + struct memory_range buffer; + UINTN size; + UINTN key; + UINTN descsize; + UINT32 descver; +}; + +struct efi_video_data +{ + struct memory_range buffer; + UINT32 width; + UINT32 height; + UINT32 pitch; + EFI_GRAPHICS_PIXEL_FORMAT format; + EFI_PIXEL_BITMASK mask; +}; + +struct efi_boot_data +{ + struct efi_memory_map memory_map; + struct efi_video_data video_data; + void *acpi_rsdp; + unsigned long acpi_version; +}; + +struct efi_loader_image kernel_image = +{ + .path = L"\\adasoft\\sophia\\kernel.os" +}; + +static struct efi_loader_image *shim_image; +static struct efi_boot_data boot_data; + +EFI_STATUS efi_shim_entry(struct efi_loader_image *image, + struct efi_loader_interface *interface) +{ + /* 1. load kernel and boot modules into memory + * 2. generate page tables for kernel and boot modules + * 2. gather boot data, store as type SystemMemoryType + * 3. exit boot services + * 5. ??????????? + */ + + EFI_STATUS status; + + if (!image) + { + return EFI_INVALID_PARAMETER; + } + else if (!shim_image) + { + shim_image = image; + kernel_image.image_handle = shim_image->image_handle; + } + else + { + return EFI_ALREADY_STARTED; + } + + if (!EFI_ERROR((status = interface->image_open(&kernel_image))) && + !EFI_ERROR((status = interface->image_alloc(&kernel_image))) && + !EFI_ERROR((status = interface->image_load(&kernel_image)))) + { + (void)boot_data; + } + + __asm__ volatile ( + "cli\n\t" + "hlt\n\t" + ); + + return status; +} + diff --git a/shim/shim.ld b/shim/shim.ld new file mode 100644 index 0000000..f0643ca --- /dev/null +++ b/shim/shim.ld @@ -0,0 +1,49 @@ +ENTRY(efi_shim_entry) + +SECTIONS +{ + . = sizeof_headers; + + .rel : + { + *(.rel.*) + } + + .rela : + { + *(.rela.*) + } + + .text : ALIGN(4K) + { + PROVIDE(_text_begin = .); + *(.text) + . = ALIGN(4K); + PROVIDE(_text_end = .); + } =0xcc + + .data : + { + PROVIDE(_data_begin = .); + *(.rodata) + *(.data) + } + + .data.rel : + { + *(.data.rel) + *(.data.rel.*) + } + + .bss : + { + *(.bss) + PROVIDE(_data_end = .); + } + + /DISCARD/ : + { + *(.eh_frame) + } +} + |
