summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2021-12-16 12:06:04 +0000
committerAda Christine <adachristine18@gmail.com>2021-12-16 12:06:04 +0000
commitec1233b4fcd61a8d1eccbf030cede36e9848e06c (patch)
tree13ffdc3b3948275e8c764ccf10368d555ff4d5e1
parenta7f79219706c357c6c15978cea5e654042b14acb (diff)
reworking loader
-rw-r--r--api/kernel/entry.h1
-rw-r--r--api/kernel/memory/paging.h1
-rw-r--r--api/kernel/memory/range.h2
-rw-r--r--api/loader/data_efi.h49
-rw-r--r--api/loader/efi/shim.h47
-rw-r--r--api/loader/shim.h4
-rw-r--r--loader/Makefile2
-rw-r--r--loader/image_efi.c211
-rw-r--r--loader/loader_efi.c182
-rw-r--r--loader/loader_efi.h64
-rw-r--r--loader/main_efi.c324
-rw-r--r--loader/memory_efi.c55
-rw-r--r--loader/paging_efi.c155
-rw-r--r--shim/Makefile36
-rw-r--r--shim/entry.c83
-rw-r--r--shim/shim.ld49
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)
+ }
+}
+