diff --git a/meta/targets/kernel-riscv32.ld b/meta/targets/kernel-riscv32.ld index b023dca..1f806b8 100644 --- a/meta/targets/kernel-riscv32.ld +++ b/meta/targets/kernel-riscv32.ld @@ -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 = .; } diff --git a/src/kernel/hal/mod.h b/src/kernel/hal/mod.h index 5c3529f..5c7d773 100644 --- a/src/kernel/hal/mod.h +++ b/src/kernel/hal/mod.h @@ -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); diff --git a/src/kernel/hal/rv32/boot.c b/src/kernel/hal/rv32/boot.c index c003c28..f4d9e00 100644 --- a/src/kernel/hal/rv32/boot.c +++ b/src/kernel/hal/rv32/boot.c @@ -8,6 +8,7 @@ #include #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(); } diff --git a/src/kernel/hal/rv32/boot.s b/src/kernel/hal/rv32/boot.s index ba02d23..8cbb97b 100644 --- a/src/kernel/hal/rv32/boot.s +++ b/src/kernel/hal/rv32/boot.s @@ -9,3 +9,4 @@ _start: la sp, __stack_top j rv32_start + diff --git a/src/kernel/hal/rv32/paging.c b/src/kernel/hal/rv32/paging.c new file mode 100644 index 0000000..f91ab66 --- /dev/null +++ b/src/kernel/hal/rv32/paging.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include + +#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}); +} diff --git a/src/kernel/hal/rv32/paging.h b/src/kernel/hal/rv32/paging.h new file mode 100644 index 0000000..3b69ad0 --- /dev/null +++ b/src/kernel/hal/rv32/paging.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +/* + * 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); diff --git a/src/libs/handover/base/mod.h b/src/libs/handover/base/mod.h index 7ca45a4..e17f52f 100644 --- a/src/libs/handover/base/mod.h +++ b/src/libs/handover/base/mod.h @@ -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 diff --git a/src/libs/helpers/mem.h b/src/libs/helpers/mem.h index 72401d6..6577677 100644 --- a/src/libs/helpers/mem.h +++ b/src/libs/helpers/mem.h @@ -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)