summaryrefslogtreecommitdiff
path: root/loader
diff options
context:
space:
mode:
Diffstat (limited to 'loader')
-rw-r--r--loader/Makefile3
-rw-r--r--loader/image_efi.c211
-rw-r--r--loader/loader_efi.c227
-rw-r--r--loader/loader_efi.h22
4 files changed, 235 insertions, 228 deletions
diff --git a/loader/Makefile b/loader/Makefile
index f552d9a..4905554 100644
--- a/loader/Makefile
+++ b/loader/Makefile
@@ -10,7 +10,8 @@ CPPFLAGS += -I../api
all: $(BUILD)
-OBJS := entry_efi.o loader_efi.o paging_efi.o memory_efi.o memcmp.o memmove.o
+OBJS := entry_efi.o loader_efi.o paging_efi.o memory_efi.o image_efi.o \
+ memcmp.o memmove.o
DEPS := $(OBJS:.o=.d)
IMAGE_SO := $(IMAGE:.efi=_efi.so)
diff --git a/loader/image_efi.c b/loader/image_efi.c
new file mode 100644
index 0000000..04d0a9b
--- /dev/null
+++ b/loader/image_efi.c
@@ -0,0 +1,211 @@
+#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
index 724e8ec..617e924 100644
--- a/loader/loader_efi.c
+++ b/loader/loader_efi.c
@@ -4,69 +4,13 @@
#include <kernel/entry.h>
-#include <elf/elf64.h>
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdnoreturn.h>
-
-struct system_image
-{
- struct memory_range buffer;
- EFI_FILE_PROTOCOL *file;
- Elf64_Ehdr ehdr;
- Elf64_Phdr *phdrs;
-};
-
static CHAR16 *kernel_path = L"\\adasoft\\sophia\\kernel.os";
static struct system_image *kernel_image = NULL;
-static struct system_image *open_system_image(CHAR16 *path);
-static bool load_system_image(struct system_image *image);
static struct efi_memory_map_data *get_memory_map_data(void);
static struct efi_framebuffer_data *get_framebuffer_data(void);
static void *get_acpi_rsdp(void);
-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;
-}
-
-static void create_image_maps(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);
- }
- }
-}
-
noreturn static void enter_kernel()
{
struct efi_boot_data data;
@@ -113,11 +57,11 @@ noreturn static void enter_kernel()
void loader_main(void)
{
- kernel_image = open_system_image(kernel_path);
+ kernel_image = system_image_open(kernel_path);
Print(L"loading %s\r\n", kernel_path);
- if (load_system_image(kernel_image))
+ if (system_image_load(kernel_image))
{
Print(L"loaded kernel image at base %16.0lx size %d bytes\r\n",
kernel_image->buffer.base,
@@ -130,178 +74,13 @@ void loader_main(void)
}
paging_init();
- create_image_maps(kernel_image);
+ system_image_map(kernel_image);
Print(L"kernel maps created. entering kernel\r\n");
enter_kernel();
efi_exit(EFI_ABORTED);
}
-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 struct system_image *open_system_image(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;
-}
-
-static UINTN get_image_size(struct system_image *image)
-{
- UINTN 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 bool load_system_image(struct system_image *image)
-{
- image->buffer = system_allocate(get_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;
-}
-
static struct efi_memory_map_data *get_memory_map_data(void)
{
EFI_STATUS status;
diff --git a/loader/loader_efi.h b/loader/loader_efi.h
index 17c58cf..4ce3098 100644
--- a/loader/loader_efi.h
+++ b/loader/loader_efi.h
@@ -1,14 +1,17 @@
#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>
-#include <kernel/memory/range.h>
-#include <kernel/memory/paging.h>
-
enum page_type
{
INVALID_PAGE_TYPE = 0x0,
@@ -17,6 +20,14 @@ enum page_type
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;
@@ -44,5 +55,10 @@ void *paging_map_pages(void *vaddr,
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);