paging: wip

This commit is contained in:
Jordan ⌨️ 2025-09-25 19:05:39 +02:00
parent 2b3a27a398
commit 8c3f2d0de8
3 changed files with 167 additions and 0 deletions

View file

@ -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*)

View file

@ -0,0 +1,129 @@
#include <hal>
#include <helpers/mem.h>
#include <logger>
#include <pmm>
#include <string.h>
#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());
}

View file

@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
#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);