feat: paging
This commit is contained in:
parent
cf6ab74375
commit
167c99c215
8 changed files with 236 additions and 6 deletions
|
@ -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 = .;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ _start:
|
|||
|
||||
la sp, __stack_top
|
||||
j rv32_start
|
||||
|
||||
|
|
140
src/kernel/hal/rv32/paging.c
Normal file
140
src/kernel/hal/rv32/paging.c
Normal 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});
|
||||
}
|
41
src/kernel/hal/rv32/paging.h
Normal file
41
src/kernel/hal/rv32/paging.h
Normal 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);
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue