summaryrefslogtreecommitdiff
path: root/kc
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2021-12-26 19:18:46 +0000
committerAda Christine <adachristine18@gmail.com>2021-12-26 19:18:46 +0000
commit7161e0a4abe5b29fb44d705e91ba33a83ffa46e7 (patch)
treeeec79ea7628cf2c48b039fe597d467a430315d7c /kc
parentbe8b55dbde1b2ac31d24a1cd30191549592c6868 (diff)
kernel now loads and executes at virtual address
Diffstat (limited to 'kc')
-rw-r--r--kc/boot/kc_main.c195
1 files changed, 184 insertions, 11 deletions
diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c
index 9829efd..28572a1 100644
--- a/kc/boot/kc_main.c
+++ b/kc/boot/kc_main.c
@@ -1,6 +1,7 @@
#include <loader/efi/shim.h>
#include <kernel/entry.h>
#include <kernel/memory/range.h>
+#include <kernel/memory/paging.h>
#include <stdbool.h>
@@ -40,17 +41,165 @@ struct efi_loader_image kernel_image =
static struct efi_loader_interface *loader_interface;
static struct efi_boot_data boot_data;
+static EFI_BOOT_SERVICES *e_bs = NULL;
+static uint64_t *system_page_map = NULL;
+static SIMPLE_TEXT_OUTPUT_INTERFACE *eto;
+
+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 inline void plog(CHAR16 *message)
+{
+ if (eto) eto->OutputString(eto, message);
+}
+
+static uint64_t *new_page_table(void)
+{
+ EFI_PHYSICAL_ADDRESS table;
+ EFI_STATUS status;
+
+ status = loader_interface->page_alloc(SystemMemoryType, page_size(1), &table);
+
+ if (EFI_ERROR(status))
+ {
+ plog(L"can't allocate page table!");
+ return NULL;
+ }
+
+ e_bs->SetMem((void *)table, page_size(1), 0);
+
+ return (uint64_t *)table;
+}
+
+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)
+ {
+ 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 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))
+ {
+ map_page(map, virt + offset, phys + offset, type);
+ }
+}
+
+#define KERNEL_SPACE_LOWER 0xffffffff80000000
+#define KERNEL_SPACE_UPPER 0xffffffffc0000000
+
+static void create_kernel_maps(Elf64_Ehdr *ehdr, void *base)
+{
+ Elf64_Phdr *phdrs = (Elf64_Phdr *)(ehdr->e_phoff + (char *)ehdr);
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ if (phdrs[i].p_type == PT_LOAD)
+ {
+ uint64_t virt_begin = phdrs[i].p_offset + (uintptr_t)base;
+ uint64_t phys_begin = phdrs[i].p_offset + (uintptr_t)ehdr;
+ size_t size = phdrs[i].p_memsz;
+ map_pages(system_page_map,
+ virt_begin,
+ phys_begin,
+ get_page_type(&phdrs[i]),
+ size);
+ }
+ }
+
+
+ // 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;
+
+}
static void collect_boot_data(void)
{
- EFI_BOOT_SERVICES *ebs = loader_interface->system_table->BootServices;
- SIMPLE_TEXT_OUTPUT_INTERFACE *eto = loader_interface->system_table->
- ConOut;
EFI_STATUS status;
boot_data.memory_map.size = 0;
- status = ebs->GetMemoryMap(&boot_data.memory_map.size,
+ status = e_bs->GetMemoryMap(&boot_data.memory_map.size,
NULL,
&boot_data.memory_map.key,
NULL,
@@ -58,7 +207,7 @@ static void collect_boot_data(void)
if (EFI_BUFFER_TOO_SMALL == status)
{
- eto->OutputString(eto, L"getting memory map size\r\n");
+ plog(L"getting memory map size\r\n");
boot_data.memory_map.buffer.size = boot_data.memory_map.size +=
EFI_PAGE_SIZE;
status = loader_interface->page_alloc(SystemMemoryType,
@@ -68,16 +217,17 @@ static void collect_boot_data(void)
if (EFI_ERROR(status))
{
- eto->OutputString(eto, L"failed allocating pages for memory map\r\n");
+ plog(L"failed allocating pages for memory map\r\n");
}
if (!EFI_ERROR(status))
{
- eto->OutputString(eto, L"got the memory map size\r\n");
+ plog(L"got the memory map size\r\n");
boot_data.memory_map.size = boot_data.memory_map.buffer.size;
- status = ebs->GetMemoryMap(&boot_data.memory_map.size,
- (EFI_MEMORY_DESCRIPTOR *)&boot_data.memory_map.buffer.base,
+ plog(L"getting memory map\r\n");
+ status = e_bs->GetMemoryMap(&boot_data.memory_map.size,
+ (EFI_MEMORY_DESCRIPTOR *)boot_data.memory_map.buffer.base,
&boot_data.memory_map.key,
&boot_data.memory_map.descsize,
&boot_data.memory_map.descver);
@@ -85,7 +235,7 @@ static void collect_boot_data(void)
if (EFI_ERROR(status))
{
- eto->OutputString(eto, L"failed getting memory map\r\n");
+ plog(L"failed getting memory map\r\n");
__asm__ volatile
(
"cli\n\t"
@@ -97,6 +247,8 @@ static void collect_boot_data(void)
__asm__ volatile ("hlt\n\t");
}
}
+
+ plog(L"boot data collected successfully\r\n");
}
EFI_STATUS kc_main(struct efi_loader_interface *interface)
@@ -115,15 +267,36 @@ EFI_STATUS kc_main(struct efi_loader_interface *interface)
}
loader_interface = interface;
+ e_bs = loader_interface->system_table->BootServices;
+ eto = loader_interface->system_table->ConOut;
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))))
{
+ plog(L"collecting boot data\r\n");
collect_boot_data();
+
+ plog(L"creating page tables\r\n");
+ system_page_map = new_page_table();
+ // parasitic map of uefi page tables is this ok???????
+ uint64_t *efi_map = get_page_map();
+ system_page_map[0] = efi_map[0];
+
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)kernel_image.buffer_base;
+
+ plog(L"mapping kernel pages\r\n");
+ create_kernel_maps(ehdr, (void *)KERNEL_SPACE_LOWER);
+
+
+ plog(L"exiting boot services\r\n");
+ e_bs->ExitBootServices(loader_interface->image_handle,
+ boot_data.memory_map.key);
+
+ set_page_map(system_page_map);
+
kc_entry_func kernel_entry = (kc_entry_func)
- (kernel_image.buffer_base + ehdr->e_entry);
+ (KERNEL_SPACE_LOWER + ehdr->e_entry);
kernel_entry(NULL);
}