summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2025-12-09 00:57:38 +0800
committerRichard Qin <richard.qin.x@gmail.com>2025-12-09 00:57:38 +0800
commitc36e1b5e5e069ce1735dcc2a94aa45ba72ea2441 (patch)
tree34be19b553615cfe36a556452e3b7ebad5276216 /src/kernel
parent8cf8be522133548ee25fdcb0258ddf3950a68bcf (diff)
downloadlume-c36e1b5e5e069ce1735dcc2a94aa45ba72ea2441.tar.gz
lume-c36e1b5e5e069ce1735dcc2a94aa45ba72ea2441.tar.xz
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.
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/main.cc56
-rw-r--r--src/kernel/mm/pmm.cc71
-rw-r--r--src/kernel/mm/vm.cc100
3 files changed, 224 insertions, 3 deletions
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