From 8c3f2d0de8894137208df735f8f4de51dde5ff64 Mon Sep 17 00:00:00 2001 From: keyboard-slayer Date: Thu, 25 Sep 2025 19:05:39 +0200 Subject: [PATCH] paging: wip --- meta/targets/kernel-x86_64.ld | 12 +++ src/kernel/hal/x86_64/paging.c | 129 +++++++++++++++++++++++++++++++++ src/kernel/hal/x86_64/paging.h | 26 +++++++ 3 files changed, 167 insertions(+) create mode 100644 src/kernel/hal/x86_64/paging.c create mode 100644 src/kernel/hal/x86_64/paging.h diff --git a/meta/targets/kernel-x86_64.ld b/meta/targets/kernel-x86_64.ld index a4c7040..4fa63dc 100644 --- a/meta/targets/kernel-x86_64.ld +++ b/meta/targets/kernel-x86_64.ld @@ -23,6 +23,8 @@ SECTIONS /* that is the beginning of the region. */ . = 0xffffffff80000000; + text_start_addr = .; + /* Define a section to contain the Limine requests and assign it to its own PHDR */ .limine_requests : { KEEP(*(.limine_requests_start)) @@ -37,9 +39,13 @@ SECTIONS *(.text .text.*) } :text + text_end_addr = .; + /* Move to the next memory page for .rodata */ . = ALIGN(CONSTANT(MAXPAGESIZE)); + rodata_start_addr = .; + .rodata : { *(.rodata .rodata.*) } :rodata @@ -50,9 +56,13 @@ SECTIONS *(.note.gnu.build-id) } :rodata + rodata_end_addr = .; + /* Move to the next memory page for .data */ . = ALIGN(CONSTANT(MAXPAGESIZE)); + data_start_addr = .; + .data : { *(.data .data.*) } :data @@ -66,6 +76,8 @@ SECTIONS *(COMMON) } :data + data_end_addr = .; + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ /DISCARD/ : { *(.eh_frame*) diff --git a/src/kernel/hal/x86_64/paging.c b/src/kernel/hal/x86_64/paging.c new file mode 100644 index 0000000..346d006 --- /dev/null +++ b/src/kernel/hal/x86_64/paging.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include + +#include "mod.h" +#include "paging.h" +#include "pmm/mod.h" + +static uint64_t* kernel_page_table = NULL; +static size_t mapping_page_size = mib$(2); + +static int64_t transform_flags(uint8_t flags) { + int64_t ret = PAGE_NO_EXECUTE | PAGE_PRESENT; + + if (flags & HAL_MAP_READ) { + } + + if (flags & HAL_MAP_NONE) { + ret &= ~PAGE_PRESENT; + } + + if (flags & HAL_MAP_WRITE) { + ret |= PAGE_WRITABLE; + } + + if (flags & HAL_MAP_EXEC) { + ret &= ~PAGE_NO_EXECUTE; + } + + if (flags & HAL_MAP_USER) { + ret |= PAGE_USER; + } + + if (flags & HAL_MAP_HUGE) { + ret |= PAGE_HUGE; + } + + return ret; +} + +static void* paging_get_pml_alloc(uint64_t* table, size_t index, bool alloc) { + if (table[index] & PAGE_PRESENT) { + return hal_mmap_l2h(PAGE_GET_PHYS(table[index])); + } else if (alloc) { + Allocator pmm = pmm_allocator(); + void* ptr = pmm.alloc(&pmm, page_size()); + if (ptr == NULL) { + return NULL; + } + memset(ptr, 0, page_size()); + table[index] = (uint64_t)hal_mmap_h2l((uint64_t)ptr) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; + return ptr; + } + + return NULL; +} + +static HalMappingError map_page(uint64_t* table, uintptr_t vaddr, uintptr_t paddr, uint32_t flag) { + if (!aligned$(vaddr, page_size())) { + return HAL_MAP_VIRT_UNALIGNED; + } + + if (!aligned$(paddr, page_size())) { + return HAL_MAP_PHYS_UNALIGNED; + } + + size_t pml1_entry = PMLX_GET_INDEX(vaddr, 0); + size_t pml2_entry = PMLX_GET_INDEX(vaddr, 1); + size_t pml3_entry = PMLX_GET_INDEX(vaddr, 2); + size_t pml4_entry = PMLX_GET_INDEX(vaddr, 3); + + uintptr_t* pml3 = paging_get_pml_alloc(table, pml4_entry, true); + if (pml3 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + if (mapping_page_size == gib$(1) && flag & PAGE_HUGE) { + pml3[pml3_entry] = paddr | flag; + return HAL_MAP_OK; + } + + uintptr_t* pml2 = paging_get_pml_alloc(pml3, pml3_entry, true); + if (pml3 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + if (flag & PAGE_HUGE) { + pml2[pml2_entry] = paddr | flag; + return HAL_MAP_OK; + } + + uintptr_t* pml1 = paging_get_pml_alloc(pml2, pml2_entry, true); + if (pml1 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + pml1[pml1_entry] = paddr | flag; + return HAL_MAP_OK; +} + +HalMappingError hal_map_page(HalPage page, uintptr_t virt, uintptr_t phys, size_t length, uint8_t flags) { + size_t len = align_up$(length, page_size()); + uintptr_t aligned_virt = align_down$(virt, page_size()); + uintptr_t aligned_phys = align_down$(phys, page_size()); + uint32_t arch_flags = transform_flags(flags); + + for (size_t i = 0; i < len; i += page_size()) { + HalMappingError err = map_page(page.ptr, aligned_virt + i, aligned_phys + i, arch_flags); + + if (err != HAL_MAP_OK) { + return err; + } + } + + return HAL_MAP_OK; +} + +void paging_init(void) { + Allocator pmm = pmm_allocator(); + kernel_page_table = pmm.alloc(&pmm, page_size()); + + if (kernel_page_table == NULL) [[clang::unlikely]] { + panic$("Couldn't allocate kernel page table"); + } + + memset(kernel_page_table, 0, page_size()); +} diff --git a/src/kernel/hal/x86_64/paging.h b/src/kernel/hal/x86_64/paging.h new file mode 100644 index 0000000..fb7c726 --- /dev/null +++ b/src/kernel/hal/x86_64/paging.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#define PAGE_GET_PHYS(x) (x & 0x000ffffffffff000) +#define PAGE_GET_FLAGS(x) (x & 0xfff) +#define PMLX_GET_INDEX(addr, level) (((uint64_t)addr & ((uint64_t)0x1ff << (12 + level * 9))) >> (12 + level * 9)) + +enum pml_fields : uint64_t { + PAGE_PRESENT = 1 << 0, + PAGE_WRITABLE = 1 << 1, + PAGE_USER = 1 << 2, + PAGE_WRITE_THROUGH = 1 << 3, + PAGE_NO_CACHE = 1 << 4, + PAGE_ACCESSED = 1 << 5, + PAGE_DIRTY = 1 << 6, + PAGE_HUGE = 1 << 7, + PAGE_GLOBAL = 1 << 8, + PAGE_NO_EXECUTE = 1 << 63, +}; + +struct [[gnu::packed]] _hal_page { + uint64_t* ptr; +}; + +void paging_init(void);