feat: paging

This commit is contained in:
Jordan ⌨️ 2025-04-30 00:36:20 +02:00
parent cf6ab74375
commit 167c99c215
8 changed files with 236 additions and 6 deletions

View file

@ -3,15 +3,24 @@ ENTRY(_start)
SECTIONS {
. = 0x80200000;
text_start_addr = .;
.text :{
KEEP(*(.text.boot));
*(.text .text.*);
}
text_end_addr = .;
. += CONSTANT(MAXPAGESIZE);
rodata_start_addr = .;
.rodata : ALIGN(4) {
*(.rodata .rodata.*);
}
rodata_end_addr = .;
. += CONSTANT(MAXPAGESIZE);
data_start_addr = .;
.data : ALIGN(4) {
*(.data .data.*);
}
@ -21,8 +30,13 @@ SECTIONS {
*(.bss .bss.* .sbss .sbss.*);
__bss_end = .;
}
data_end_addr = .;
. += CONSTANT(MAXPAGESIZE);
stack_start_addr = .;
. = ALIGN(4);
. += 128 * 1024; /* 128KB */
__stack_top = .;
stack_end_addr = .;
}

View file

@ -5,11 +5,41 @@
void hal_setup(void);
/* ==== PAGE MAPPING ==== */
typedef enum {
HAL_MAP_NONE = 0,
HAL_MAP_READ = 1 << 0,
HAL_MAP_WRITE = 1 << 1,
HAL_MAP_EXEC = 1 << 2,
HAL_MAP_USER = 1 << 3,
HAL_MAP_HUGE = 1 << 4,
} HalMapFlags;
typedef enum {
HAL_MAP_OK,
HAL_MAP_PHYS_UNALIGNED,
HAL_MAP_VIRT_UNALIGNED,
HAL_MAP_COULDNT_ALLOCATE,
HAL_MAP_ALREADY_MAPPED,
} HalMappingError;
typedef struct _page HalPage;
HalMappingError hal_map_page(HalPage page, uintptr_t virt, uintptr_t phys, size_t length, uint8_t flags);
void hal_switch_space(HalPage space);
size_t page_size(void);
/* === I/O === */
void hal_putc(int ch);
Writer hal_writer(void);
/* === MISC === */
void hal_brkpoint(void);
DTBNode* hal_dtb_root(void);
size_t page_size(void);

View file

@ -8,6 +8,7 @@
#include <stdio.h>
#include "exception.h"
#include "paging.h"
extern char __bss[], __bss_end[];
extern void kmain(void);
@ -33,6 +34,7 @@ void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) {
}
pmm_init();
paging_init();
kmain();
}

View file

@ -9,3 +9,4 @@ _start:
la sp, __stack_top
j rv32_start

View file

@ -0,0 +1,140 @@
#include <hal>
#include <helpers/mem.h>
#include <logger>
#include <pmm>
#include <string.h>
#include "paging.h"
#include "regs.h"
extern uint8_t text_start_addr[];
extern uint8_t text_end_addr[];
extern uint8_t rodata_start_addr[];
extern uint8_t rodata_end_addr[];
extern uint8_t data_start_addr[];
extern uint8_t data_end_addr[];
extern uint8_t stack_start_addr[];
extern uint8_t stack_end_addr[];
static uint32_t* kernel_page_table = NULL;
static uint32_t transform_flags(uint8_t flags) {
uint32_t ret = 0;
if (flags & HAL_MAP_READ) {
ret |= MAPPING_READ;
}
if (flags & HAL_MAP_WRITE) {
ret |= MAPPING_WRITE;
}
if (flags & HAL_MAP_EXEC) {
ret |= MAPPING_EXECUTE;
}
if (flags & HAL_MAP_USER) {
ret |= MAPPING_USER;
}
return ret;
}
static HalMappingError map_page(uint32_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;
}
uint32_t vpn0 = vpn0$(vaddr);
uint32_t vpn1 = vpn1$(vaddr);
if ((table[vpn1] & MAPPING_VALID) == 0) {
PhysObj page_phys = pmm_alloc(page_size());
if (page_phys.base == 0) {
return HAL_MAP_COULDNT_ALLOCATE;
}
memset((void*)page_phys.base, 0, page_size());
table[vpn1] = ((page_phys.base / page_size()) << 10) | MAPPING_VALID;
}
uint32_t* table0 = (uint32_t*)((table[vpn1] >> 10) * page_size());
if ((table0[vpn0] & MAPPING_VALID) == MAPPING_VALID) {
return HAL_MAP_ALREADY_MAPPED;
}
table0[vpn0] = ((paddr / page_size()) << 10) | flag | MAPPING_VALID;
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 hal_switch_space(HalPage space) {
write_csr$(satp, SATP_SV32 | ((uintptr_t)space.ptr / page_size()));
__asm__ volatile("sfence.vma");
}
void paging_init(void) {
PhysObj page_phys = pmm_alloc(page_size());
if (page_phys.base == 0) {
error$("Couldn't allocate page table");
hal_brkpoint();
}
memset((void*)page_phys.base, 0, page_size());
kernel_page_table = (uint32_t*)page_phys.base;
size_t text_start = align_down$((uintptr_t)text_start_addr, page_size());
size_t text_end = align_up$((uintptr_t)text_end_addr, page_size());
HalMappingError err = hal_map_page((HalPage){kernel_page_table}, text_start, text_start, text_end - text_start, HAL_MAP_READ | HAL_MAP_EXEC);
if (err != HAL_MAP_OK) {
error$("Couldn't map kernel text, cause: %d", err);
hal_brkpoint();
}
size_t rodata_start = align_down$((uintptr_t)rodata_start_addr, page_size());
size_t rodata_end = align_up$((uintptr_t)rodata_end_addr, page_size());
err = hal_map_page((HalPage){kernel_page_table}, rodata_start, rodata_start, rodata_end - rodata_start, HAL_MAP_READ);
if (err != HAL_MAP_OK) {
error$("Couldn't map kernel rodata, cause: %d", err);
hal_brkpoint();
}
size_t data_start = align_down$((uintptr_t)data_start_addr, page_size());
size_t data_end = align_up$((uintptr_t)data_end_addr, page_size());
err = hal_map_page((HalPage){kernel_page_table}, data_start, data_start, data_end - data_start, HAL_MAP_READ | HAL_MAP_WRITE);
if (err != HAL_MAP_OK) {
error$("Couldn't map kernel data, cause: %d", err);
hal_brkpoint();
}
size_t stack_start = align_down$((uintptr_t)stack_start_addr, page_size());
size_t stack_end = align_up$((uintptr_t)stack_end_addr, page_size());
err = hal_map_page((HalPage){kernel_page_table}, stack_start, stack_start, stack_end - stack_start, HAL_MAP_READ | HAL_MAP_WRITE);
if (err != HAL_MAP_OK) {
error$("Couldn't map kernel stack, cause: %d", err);
hal_brkpoint();
}
debug$("Switching to page table %p", kernel_page_table);
hal_switch_space((HalPage){kernel_page_table});
}

View file

@ -0,0 +1,41 @@
#pragma once
#include <stdint.h>
/*
* Sv32 page table entry
*
* +-------------------------+---------------------+-----+---+---+---+---+---+---+---+---+
* | PPN[1] | PPN[0] | RSW | D | A | G | U | X | W | R | V |
* +-------------------------+---------------------+-----+---+---+---+---+---+---+---+---+
*
* > V -> 1 if entry is valid
* > R -> 1 if can be read
* > W -> 1 if can be written
* > X -> 1 if can be executed
* > U -> 1 if belong to user space
* > G -> 1 if global mapping
* > A -> 1 if accessed
* > D -> 1 if dirty
* > RSW -> reserved for OS use (Aka it's for us)
* > PPN -> Page table pointer
*/
#define SATP_SV32 1u << 31
enum mapping_flags {
MAPPING_VALID = 1 << 0,
MAPPING_READ = 1 << 1,
MAPPING_WRITE = 1 << 2,
MAPPING_EXECUTE = 1 << 3,
MAPPING_USER = 1 << 4,
};
struct _page {
uint32_t* ptr;
} __attribute__((packed));
#define vpn1$(x) ((x >> 22) & 0x3FF)
#define vpn0$(x) ((x >> 12) & 0x3FF)
void paging_init(void);

View file

@ -8,11 +8,11 @@
#pragma GCC diagnostic ignored "-Wpedantic"
#ifdef __ck_bits_64__
# define KERNEL_BASE 0xffffffff80000000;
# define UPPER_HALF 0xffff800000000000;
# define KERNEL_BASE 0xffffffff80000000
# define UPPER_HALF 0xffff800000000000
#else
# define KERNEL_BASE 0xc0000000;
# define UPPER_HALF 0xc0000000;
# define KERNEL_BASE 0xc0000000
# define UPPER_HALF 0xc0000000
#endif //!__ck_bits_64__
#define HANDOVER_COOLBOOT 0xc001b001

View file

@ -4,6 +4,8 @@
#define align_down$(x, align) ((x) & ~((align) - 1))
#define aligned$(x, align) (x % align == 0)
#define kib$(x) ((uintptr_t)(x) * 1024)
#define mib$(x) (kib$(x) * 1024)