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