diff --git a/src/kernel.c b/src/kernel.c index cfbf293..aff1fcc 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -35,6 +35,24 @@ paddr_t alloc_pages(uint32_t n) { return paddr; } +void map_page(uint32_t *table1, uint32_t vaddr, paddr_t paddr, uint32_t flags) { + if (!is_aligned(vaddr, PAGE_SIZE)) + PANIC("unaligned vaddr %x", vaddr); + + if (!is_aligned(paddr, PAGE_SIZE)) + PANIC("unaligned paddr %x", paddr); + + uint32_t vpn1 = (vaddr >> 22) & 0x3ff; + if ((table1[vpn1] & PAGE_V) == 0) { + uint32_t pt_paddr = alloc_pages(1); + table1[vpn1] = ((pt_paddr / PAGE_SIZE) << 10) | PAGE_V; + } + + uint32_t vpn0 = (vaddr >> 12) & 0x3ff; + uint32_t *table0 = (uint32_t *)((table1[vpn1] >> 10) * PAGE_SIZE); + table0[vpn0] = ((paddr / PAGE_SIZE) << 10) | flags | PAGE_V; +} + // ===== Exception handler ===== void kernel_entry(void) { __asm__ __volatile__("csrrw sp, sscratch, sp\n" @@ -192,9 +210,15 @@ struct process *create_process(uint32_t pc) { *--sp = 0; // s0 *--sp = (uint32_t)pc; // ra + uint32_t *page_table = (uint32_t *)alloc_pages(1); + for (paddr_t paddr = (paddr_t)__kernel_base; + paddr < (paddr_t)__free_ram_end; paddr += PAGE_SIZE) + map_page(page_table, paddr, paddr, PAGE_R | PAGE_W | PAGE_X); + proc->pid = i + 1; proc->state = PROC_RUNNABLE; proc->sp = (uint32_t)sp; + proc->page_table = page_table; return proc; } void yield(void) { @@ -211,9 +235,13 @@ void yield(void) { return; __asm__ __volatile__( + "sfence.vma\n" + "csrw satp, %[satp]\n" + "sfence.vma\n" "csrw sscratch, %[sscratch]\n" : - : [sscratch] "r"((uint32_t)&next->stack[sizeof(next->stack)])); + : [satp] "r"(SATP_SV32 | ((uint32_t)next->page_table / PAGE_SIZE)), + [sscratch] "r"((uint32_t)&next->stack[sizeof(next->stack)])); struct process *prev = current_proc; current_proc = next; @@ -221,17 +249,35 @@ void yield(void) { } // ===== ENTRY POINT ===== +struct process *proc_a; +struct process *proc_b; + +void proc_a_entry(void) { + while (1) { + putchar('A'); + yield(); + } +} + +void proc_b_entry(void) { + while (1) { + putchar('B'); + yield(); + } +} + void kernel_main(void) { memset(__bss, 0, (size_t)__bss_end - (size_t)__bss); - printf("\n\n"); - WRITE_CSR(stvec, (uint32_t)kernel_entry); idle_proc = create_process((uint32_t)NULL); idle_proc->pid = -1; current_proc = idle_proc; + proc_a = create_process((uint32_t)proc_a_entry); + proc_b = create_process((uint32_t)proc_b_entry); + yield(); PANIC("switched to idle process"); } diff --git a/src/kernel.h b/src/kernel.h index 5b5fe7b..db2bdb3 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -6,6 +6,7 @@ extern char __bss[], __bss_end[]; extern char __stack_top[]; extern char __free_ram[], __free_ram_end[]; +extern char __kernel_base[]; // ===== SBI data ====== struct sbiret { @@ -58,12 +59,21 @@ struct process { int pid; int state; vaddr_t sp; + uint32_t *page_table; uint8_t stack[8192]; }; struct process procs[PROCS_MAX]; struct process *current_proc; struct process *idle_proc; +// ===== Memory allocation ===== +#define SATP_SV32 (1u << 31) +#define PAGE_V (1 << 0) +#define PAGE_R (1 << 1) +#define PAGE_W (1 << 2) +#define PAGE_X (1 << 3) +#define PAGE_U (1 << 4) + // ===== Macros ===== #define READ_CSR(reg) \ ({ \ diff --git a/src/kernel.ld b/src/kernel.ld index c4aee9e..c6d5a48 100644 --- a/src/kernel.ld +++ b/src/kernel.ld @@ -2,6 +2,7 @@ ENTRY(boot) SECTIONS { . = 0x80200000; + __kernel_base = .; .text :{ KEEP(*(.text.boot)); diff --git a/src/run.sh b/src/run.sh index 8bf3a3c..e3f7569 100755 --- a/src/run.sh +++ b/src/run.sh @@ -1,5 +1,4 @@ #!/bin/bash set -xue -make kernel -qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf +make kernel && qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf