summaryrefslogtreecommitdiff
path: root/loader
diff options
context:
space:
mode:
Diffstat (limited to 'loader')
-rw-r--r--loader/Makefile2
-rw-r--r--loader/entry_efi.c2
-rw-r--r--loader/loader_efi.c147
-rw-r--r--loader/loader_efi.h19
-rw-r--r--loader/memory_efi.c2
-rw-r--r--loader/paging_efi.c155
6 files changed, 199 insertions, 128 deletions
diff --git a/loader/Makefile b/loader/Makefile
index 582daf3..f552d9a 100644
--- a/loader/Makefile
+++ b/loader/Makefile
@@ -10,7 +10,7 @@ CPPFLAGS += -I../api
all: $(BUILD)
-OBJS := entry_efi.o loader_efi.o memory_efi.o memcmp.o memmove.o
+OBJS := entry_efi.o loader_efi.o paging_efi.o memory_efi.o memcmp.o memmove.o
DEPS := $(OBJS:.o=.d)
IMAGE_SO := $(IMAGE:.efi=_efi.so)
diff --git a/loader/entry_efi.c b/loader/entry_efi.c
index fa27c02..070cc16 100644
--- a/loader/entry_efi.c
+++ b/loader/entry_efi.c
@@ -34,6 +34,8 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
e_system_partition = open_system_partition();
e_graphics_output = open_graphics_output();
+ WaitForSingleEvent(e_st->ConIn->WaitForKey, 0);
+
loader_main();
efi_exit(EFI_ABORTED);
diff --git a/loader/loader_efi.c b/loader/loader_efi.c
index 08da215..724e8ec 100644
--- a/loader/loader_efi.c
+++ b/loader/loader_efi.c
@@ -3,12 +3,12 @@
#include <loader/data_efi.h>
#include <kernel/entry.h>
-#include <kernel/memory/paging.h>
#include <elf/elf64.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdnoreturn.h>
struct system_image
{
@@ -20,7 +20,6 @@ struct system_image
static CHAR16 *kernel_path = L"\\adasoft\\sophia\\kernel.os";
static struct system_image *kernel_image = NULL;
-static uint64_t *system_page_map = NULL;
static struct system_image *open_system_image(CHAR16 *path);
static bool load_system_image(struct system_image *image);
@@ -28,74 +27,6 @@ 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
-{
- 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
-};
-
-static uint64_t *new_page_table(void)
-{
- struct memory_range table = system_allocate(page_size(1));
- e_bs->SetMem((void *)table.base, table.size, 0);
-
- return (uint64_t *)table.base;
-}
-
-static uint64_t *get_page_map(void)
-{
- uint64_t map;
- __asm__("mov %%cr3, %0" : "=r"(map));
- return (uint64_t *)(page_address(map, 1));
-}
-
-void set_page_map(uint64_t *map)
-{
- __asm__("cli");
- __asm__("mov %0, %%cr3" :: "r"(map));
-}
-
-static uint64_t *get_page_table(uint64_t *map, uint64_t virt, int level)
-{
- if ((level < 1) || (level > PAGE_MAP_LEVELS))
- {
- return NULL;
- }
-
- for (int i = PAGE_MAP_LEVELS; i > level; i--)
- {
- if (!map[pte_index(virt, i)])
- {
- uint64_t *next_map = new_page_table();
- map[pte_index(virt, i)] = (uint64_t)next_map|PAGE_PR|PAGE_WR;
- map = next_map;
- }
- else
- {
- map = (uint64_t *)page_address(map[pte_index(virt, i)], 1);
- }
- }
-
- return map;
-}
-
-static uint64_t *get_page_entry(uint64_t *map, uint64_t virt)
-{
- int level = 1;
- uint64_t *table = get_page_table(map, virt, level);
- return &table[pte_index(virt, level)];
-}
-
-static void map_page(void *map,
- uint64_t virt,
- uint64_t phys,
- enum page_type type)
-{
- *get_page_entry(map, virt) = phys | type;
-}
-
enum page_type get_page_type(Elf64_Phdr *phdr)
{
switch (phdr->p_flags)
@@ -111,19 +42,6 @@ enum page_type get_page_type(Elf64_Phdr *phdr)
return INVALID_PAGE_TYPE;
}
-static void map_pages(void *map,
- uint64_t virt,
- uint64_t phys,
- enum page_type type,
- size_t size)
-{
- for (size_t offset = 0; offset < size; offset += page_size(1))
- {
- Print(L"mapping page %16.0lx to %16.0lx\r\n", virt + offset, phys + offset);
- map_page(map, virt + offset, phys + offset, type);
- }
-}
-
static void create_image_maps(struct system_image *image)
{
Elf64_Ehdr *ehdr = &image->ehdr;
@@ -133,23 +51,23 @@ static void create_image_maps(struct system_image *image)
{
if (phdrs[i].p_type == PT_LOAD)
{
- uint64_t virt_begin = phdrs[i].p_vaddr;
+ 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);
- map_pages(system_page_map,
- virt_begin,
- phys_begin,
- get_page_type(&phdrs[i]),
- size);
+
+ paging_map_pages(virt_begin,
+ phys_begin,
+ get_page_type(&phdrs[i]),
+ size);
}
}
}
-static void enter_kernel()
+noreturn static void enter_kernel()
{
struct efi_boot_data data;
kernel_entry_func kernel_entry;
@@ -159,12 +77,9 @@ static void enter_kernel()
system_allocate(KERNEL_ENTRY_STACK_SIZE);
// get a stack here for now idfk
- map_pages(system_page_map,
- KERNEL_ENTRY_STACK_BASE,
- kernel_entry_stack.base,
- DATA_PAGE_TYPE,
- kernel_entry_stack.size);
-
+ paging_map_range(KERNEL_ENTRY_STACK_BASE,
+ &kernel_entry_stack,
+ DATA_PAGE_TYPE);
data.system_table = e_st;
data.framebuffer = get_framebuffer_data();
@@ -180,12 +95,10 @@ static void enter_kernel()
efi_exit(status);
}
- // parasitic map of uefi page tables is this ok???????
- uint64_t *efi_map = get_page_map();
- system_page_map[0] = efi_map[0];
-
- set_page_map(system_page_map);
-
+ // enter the kernel address environment
+ paging_enter();
+
+ // set the kernel entry stack.
__asm__
(
"mov %0, %%rsp"
@@ -194,27 +107,8 @@ static void enter_kernel()
);
kernel_entry(&data);
-}
-
-#define KERNEL_SPACE_LOWER 0xffffffff80000000
-#define KERNEL_SPACE_UPPER 0xffffffffc0000000
-
-static void create_system_maps()
-{
- system_page_map = new_page_table();
-
- // Create fractal mappings
- uint64_t *lower_page_dir = get_page_table(system_page_map,
- KERNEL_SPACE_LOWER,
- 2);
- uint64_t *upper_page_dir = get_page_table(system_page_map,
- KERNEL_SPACE_UPPER,
- 2);
-
- upper_page_dir[PAGE_TABLE_INDEX_MASK] =
- (uint64_t)upper_page_dir|DATA_PAGE_TYPE;
- upper_page_dir[PAGE_TABLE_INDEX_MASK - 1] =
- (uint64_t)lower_page_dir|DATA_PAGE_TYPE;
+
+ while(true);
}
void loader_main(void)
@@ -235,8 +129,7 @@ void loader_main(void)
efi_exit(EFI_ABORTED);
}
- create_system_maps();
- Print(L"kernel pml4 %16.0lx\r\n", system_page_map);
+ paging_init();
create_image_maps(kernel_image);
Print(L"kernel maps created. entering kernel\r\n");
enter_kernel();
@@ -352,7 +245,9 @@ static UINTN get_image_size(struct system_image *image)
{
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);
+ {
+ size = (size + phdrs[i].p_align - 1) & ~(phdrs[i].p_align - 1);
+ }
}
}
diff --git a/loader/loader_efi.h b/loader/loader_efi.h
index a1ba360..17c58cf 100644
--- a/loader/loader_efi.h
+++ b/loader/loader_efi.h
@@ -7,6 +7,15 @@
#include <stdnoreturn.h>
#include <kernel/memory/range.h>
+#include <kernel/memory/paging.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
+};
extern EFI_SYSTEM_TABLE *e_st;
extern EFI_BOOT_SERVICES *e_bs;
@@ -25,5 +34,15 @@ 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);
void loader_main(void);
diff --git a/loader/memory_efi.c b/loader/memory_efi.c
index b2d38ee..2fab6b7 100644
--- a/loader/memory_efi.c
+++ b/loader/memory_efi.c
@@ -18,6 +18,7 @@ struct memory_range system_allocate(size_t size)
if (EFI_ERROR(status))
{
+ Print(L"error allocating range: %r\r\n", status);
e_last_error = status;
buffer.type = UNUSABLE_MEMORY;
}
@@ -52,4 +53,3 @@ void efi_free(void *buffer)
e_last_error = status;
}
}
-
diff --git a/loader/paging_efi.c b/loader/paging_efi.c
new file mode 100644
index 0000000..5f65213
--- /dev/null
+++ b/loader/paging_efi.c
@@ -0,0 +1,155 @@
+#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)
+ );
+}