From c36e1b5e5e069ce1735dcc2a94aa45ba72ea2441 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Tue, 9 Dec 2025 00:57:38 +0800 Subject: feat: Initial PMM implementation Introduce the foundational Physical Memory Manager (PMM) and restructure the project for modularity. Implemented basic PMM and related memory management headers (mm/pmm.h, mm/vm.h). Updated Makefile and build process to support new modular structure. --- src/boot/entry.S | 46 +++++++++++++++--------- src/kernel/main.cc | 56 +++++++++++++++++++++++++++-- src/kernel/mm/pmm.cc | 71 ++++++++++++++++++++++++++++++++++++ src/kernel/mm/vm.cc | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 20 deletions(-) create mode 100644 src/kernel/mm/pmm.cc create mode 100644 src/kernel/mm/vm.cc (limited to 'src') diff --git a/src/boot/entry.S b/src/boot/entry.S index 1a6f6b8..0ca3b29 100644 --- a/src/boot/entry.S +++ b/src/boot/entry.S @@ -1,28 +1,40 @@ .section .text.entry -.globl _start +.global _start _start: csrr t0, mhartid - bnez t0, .L_park_harts + bnez t0, .L_park - la sp, _stack_top + li t0, 0x1fffffffffffff + csrw pmpaddr0, t0 + li t0, 0xf + csrw pmpcfg0, t0 - la a0, _bss_start - la a1, _bss_end - bge a0, a1, .L_call_main + li t0, 0 + li t1, (1 << 11) | (1 << 7) + csrw mstatus, t1 -.L_clear_bss: - sd zero, (a0) - addi a0, a0, 8 - blt a0, a1, .L_clear_bss + csrw satp, zero -.L_call_main: - call kernel_main + li t0, 0xffff + csrw medeleg, t0 + csrw mideleg, t0 + + la t0, kernel_main + csrw mepc, t0 -.L_infinite_loop: - wfi - j .L_infinite_loop + la sp, stack_top + + mret -.L_park_harts: +.L_park: wfi - j .L_park_harts \ No newline at end of file + j .L_park + + +.section .bss +.align 4 +.global stack_top +stack_base: + .space 4096 * 4 +stack_top: \ No newline at end of file diff --git a/src/kernel/main.cc b/src/kernel/main.cc index 49adf2b..beda9dc 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -1,17 +1,67 @@ #include "drivers/uart.h" +#include "kernel/pmm.h" +#include "kernel/mm.h" + +void print_hex(uint64_t val) +{ + char buf[17]; + buf[16] = 0; + const char *digits = "0123456789ABCDEF"; + for (int i = 15; i >= 0; i--) + { + buf[i] = digits[val & 0xf]; + val >>= 4; + } + Drivers::uart_puts("0x"); + Drivers::uart_puts(buf); +} extern "C" void kernel_main() { Drivers::uart_init(); + Drivers::uart_puts("\n[Modern DOS Kernel] Booted in S-Mode.\n"); + Drivers::uart_puts("2025 Richard Qin\n"); + Drivers::uart_puts("\n"); + + Drivers::uart_puts("[Kernel] Initializing PMM...\n"); + PMM::init(); + Drivers::uart_puts("[Kernel] PMM initialized.\n"); + Drivers::uart_puts("[Kernel] Testing alloc_page...\n"); + void *p1 = PMM::alloc_page(); + void *p2 = PMM::alloc_page(); + + Drivers::uart_puts("Allocated Page 1: "); + print_hex((uint64_t)p1); Drivers::uart_puts("\n"); - Drivers::uart_puts("Modern DOS v1.0 [RISC-V 64]\n"); - Drivers::uart_puts("2025 Richard Qin\n"); + + Drivers::uart_puts("Allocated Page 2: "); + print_hex((uint64_t)p2); Drivers::uart_puts("\n"); - Drivers::uart_puts("A:\\> "); + Drivers::uart_puts("[Kernel] Freeing Page 1...\n"); + PMM::free_page(p1); + + void *p3 = PMM::alloc_page(); + Drivers::uart_puts("Allocated Page 3: "); + print_hex((uint64_t)p3); + Drivers::uart_puts("\n"); + + if (p3 == p1) + { + Drivers::uart_puts("[Test Passed] Reuse freed memory successfully.\n"); + } + else + { + Drivers::uart_puts("[Test Failed] Memory leak or logic error.\n"); + } + + VM::kvminit(); + Drivers::uart_puts("[Boot] Kernel page table created.\n"); + VM::kvminithart(); + Drivers::uart_puts("[Boot] MMU ENABLED! We are now using virtual addresses.\n"); while (1) { diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc new file mode 100644 index 0000000..9b68fcd --- /dev/null +++ b/src/kernel/mm/pmm.cc @@ -0,0 +1,71 @@ +#include "kernel/pmm.h" +#include "drivers/uart.h" + +extern "C" char kernel_end[]; + +namespace PMM +{ + struct Run + { + struct Run *next; + }; + + struct + { + struct Run *freelist; + } kmem; + + inline uint64_t PGROUNDUP(uint64_t a) + { + return (a + PGSIZE - 1) & ~(PGSIZE - 1); + } + + void init() + { + uint64_t start = PGROUNDUP((uint64_t)kernel_end); + + Drivers::uart_puts("PMM: Initializing from"); + + for (uint64_t p = start; p + PGSIZE <= PHYSTOP; p += PGSIZE) + { + free_page((void *)p); + } + } + + void free_page(void* pa) + { + struct Run *r; + if (((uint64_t)pa % PGSIZE) != 0 || (uint64_t)pa < (uint64_t)kernel_end || (uint64_t)pa >= PHYSTOP) + { + Drivers::uart_puts("PMM: Error - Invalid free address\n"); + return; + } + r = (struct Run*)pa; + + r->next = kmem.freelist; + kmem.freelist = r; + + } + + void* alloc_page() + { + struct Run* r; + + r = kmem.freelist; + if (r) + { + kmem.freelist = r->next; + + uint64_t *p = (uint64_t *)r; + for (int i = 0; i < PGSIZE / 8; i++) + { + p[i] = 0; + } + } + else + { + Drivers::uart_puts("PMM: Out of memory!\n"); + } + return (void *)r; + } +} \ No newline at end of file diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc new file mode 100644 index 0000000..3c14d40 --- /dev/null +++ b/src/kernel/mm/vm.cc @@ -0,0 +1,100 @@ +#include "kernel/mm.h" +#include "kernel/pmm.h" +#include "drivers/uart.h" +#include "common/types.h" + +extern "C" char text_start[]; +extern "C" char text_end[]; +extern "C" char rodata_start[]; +extern "C" char rodata_end[]; +extern "C" char data_start[]; +extern "C" char kernel_end[]; + +namespace VM +{ + pagetable_t kernel_pagetable; + + #define PX(level, va) ((((uint64)va) >> (12 + 9 * (level))) & 0x1FF) + #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) + #define PTE2PA(pte) (((pte) >> 10) << 12) + + pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) + { + for (int level = 2; level > 0; level--) + { + pte_t *pte = &pagetable[PX(level, va)]; + + if (*pte & PTE_V) + { + pagetable = (pagetable_t)PTE2PA(*pte); + } + else + { + if (!alloc) + return 0; + + pagetable = (pagetable_t)PMM::alloc_page(); + if (!pagetable) + return 0; + + *pte = PA2PTE(pagetable) | PTE_V; + } + } + return &pagetable[PX(0, va)]; + } + + int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm) + { + uint64 a, last; + pte_t *pte; + + a = (va / PGSIZE) * PGSIZE; + last = ((va + size - 1) / PGSIZE) * PGSIZE; + + for(;;) + { + if((pte = walk(pagetable, a, 1)) == 0) + return -1; + + if (*pte & PTE_V) + { + Drivers::uart_puts("Remap error\n"); + return -1; + } + + *pte = PA2PTE(pa) | perm | PTE_V; + + if (a == last) + break; + a += PGSIZE; + pa += PGSIZE; + } + return 0; + } + + void kvminit() + { + kernel_pagetable = (pagetable_t)PMM::alloc_page(); + + mappages(kernel_pagetable, 0x10000000, 0x10000, 0x10000000, PTE_R | PTE_W); + + mappages(kernel_pagetable, (uint64)text_start, (uint64)text_end - (uint64)text_start, + (uint64)text_start, PTE_R | PTE_X); + + mappages(kernel_pagetable, (uint64)data_start, PHYSTOP - (uint64)data_start, + (uint64)data_start, PTE_R | PTE_W); + + mappages(kernel_pagetable, (uint64)rodata_start, (uint64)rodata_end - (uint64)rodata_start, + (uint64)rodata_start, PTE_R); + + } + void kvminithart() + { + asm volatile("sfence.vma zero, zero"); + + uint64 satp_val = MAKE_SATP(kernel_pagetable); + asm volatile("csrw satp, %0" : : "r"(satp_val)); + + asm volatile("sfence.vma zero, zero"); + } +} \ No newline at end of file -- cgit v1.2.3