summaryrefslogtreecommitdiff
path: root/src/kernel/mm
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
commite90b72ec3082588b296956730bd2930cf8d5d671 (patch)
tree36ff6916af9b4176ea5a9662219d11e721f0b691 /src/kernel/mm
parent1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff)
downloadlume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz
lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'src/kernel/mm')
-rw-r--r--src/kernel/mm/pmm.cc305
-rw-r--r--src/kernel/mm/slab.cc259
-rw-r--r--src/kernel/mm/vm.cc459
3 files changed, 0 insertions, 1023 deletions
diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc
deleted file mode 100644
index d3d99ba..0000000
--- a/src/kernel/mm/pmm.cc
+++ /dev/null
@@ -1,305 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "common/types.h"
-#include "kernel/riscv.h"
-#include "kernel/pmm.h"
-#include "kernel/mm.h"
-#include "kernel/fdt.h"
-// #include "kernel/spinlock.h"
-#include "drivers/uart.h"
-#include "lib/string.h"
-
-extern "C" char kernel_end[];
-extern uint64 g_dtb_addr;
-
-// Default memory size 128MB, will be overwritten by FDT
-uint64 g_phys_size = 128 * 1024 * 1024;
-
-namespace PMM
-{
- // Global metadata array pointer
- struct Page *mem_map = nullptr;
- // Total number of physical memory pages
- uint64 total_pages = 0;
- // Free list array (free_area[k] stores the head of the free block list of order=k)
- struct Page *free_area[MAX_ORDER];
- // Protective lock
- Spinlock pmm_lock;
-
- struct Page *pa_to_page(uint64 pa)
- {
- if (pa < KERNBASE || pa >= PHYSTOP)
- return nullptr;
- uint64 pfn = (pa - KERNBASE) >> PGSHIFT;
- if (pfn >= total_pages)
- return nullptr;
- return &mem_map[pfn];
- }
-
- uint64 page_to_pa(struct Page *page)
- {
- uint64 pfn = page - mem_map;
- return KERNBASE + (pfn << PGSHIFT);
- }
-
- void list_add(struct Page *page, int order)
- {
- page->order = order;
- page->flags = 0; // Mark as available
- page->next = free_area[order];
- page->prev = nullptr;
-
- if (free_area[order])
- {
- free_area[order]->prev = page;
- }
- free_area[order] = page;
- }
-
- void list_del(struct Page* page, int order)
- {
- if (page->prev)
- {
- page->prev->next = page->next;
- }
- else
- {
- free_area[order] = page->next;
- }
- if (page->next)
- {
- page->next->prev = page->prev;
- }
- page->next = nullptr;
- page->prev = nullptr;
- }
-
- void init()
- {
- // Use FDT memory size if available
- if (g_devices.mem_size > 0)
- {
- g_phys_size = g_devices.mem_size;
- }
-
- pmm_lock.init("pmm");
-
- uint64 kern_end_pa = PGROUNDUP((uint64)kernel_end);
- total_pages = (PHYSTOP - KERNBASE) / PGSIZE;
-
- Drivers::uart_puts(ANSI_GREEN "[PMM] Total RAM size: ");
- Drivers::uart_put_int(g_phys_size / (1024 * 1024));
- Drivers::uart_puts(" MB\n" ANSI_RESET);
- // Place the mem_map array
- // mem_map is located immediately after kernel_end
- mem_map = (struct Page*)kern_end_pa;
-
- uint64 mem_map_size = total_pages * sizeof(struct Page);
- uint64 free_mem_start = PGROUNDUP(kern_end_pa + mem_map_size);
-
- Drivers::uart_puts(ANSI_GREEN "[PMM] MemMap placed at: " );
- Drivers::print_hex((uint64)mem_map);
- Drivers::uart_puts("\n" ANSI_RESET);
-
- Drivers::uart_puts(ANSI_GREEN "[PMM] Free memory starts at: ");
- Drivers::print_hex(free_mem_start);
- Drivers::uart_puts("\n" ANSI_RESET);
-
- if (free_mem_start >= PHYSTOP)
- {
- Drivers::uart_puts(ANSI_RED "[PMM] Error - Kernel too large, no memory left!\n" ANSI_RESET);
- while (1)
- ;
- }
-
- // Initialize all page states
- for (uint64 i = 0; i < total_pages; i++)
- {
- mem_map[i].flags = PG_reserved;
- mem_map[i].order = 0;
- mem_map[i].refcnt = 0;
- mem_map[i].next = nullptr;
- mem_map[i].prev = nullptr;
- }
-
- for (int i = 0; i < MAX_ORDER; i++)
- {
- free_area[i] = nullptr;
- }
-
- // Release actual free memory to the allocator
- // Range: [free_mem_start, PHYSTOP)
- // Note: need to avoid the page where the DTB is located
- uint64 dtb_pa_start = PGROUNDDOWN(g_dtb_addr);
- uint64 dtb_pa_end = PGROUNDUP(g_dtb_addr + 0x10000);
-
- uint64 p = free_mem_start;
- while (p < PHYSTOP)
- {
- if (p >= dtb_pa_start && p < dtb_pa_end)
- {
- p += PGSIZE;
- continue;
- }
-
- // Mark the page as Used, then call free_pages to release it
- // This allows free_pages to handle the merging logic automatically
- struct Page *page = pa_to_page(p);
- if (page)
- {
- page->flags = PG_used;
- free_pages((void *)p, 0); // Release page by page, let Buddy merge automatically
- }
- p += PGSIZE;
-
-
- }
-
- }
-
- void *alloc_pages(int order)
- {
- if (order < 0 || order >= MAX_ORDER)
- return nullptr;
-
- pmm_lock.acquire();
-
- int current_order = order;
- while (current_order < MAX_ORDER)
- {
- if (free_area[current_order])
- {
- // Find free block
- struct Page *page = free_area[current_order];
- list_del(page, current_order);
-
- // If the block is too large, split it.
- while (current_order > order)
- {
- current_order--;
- // page is the left part (Buddy A)
- // buddy is the right part (Buddy B)
- // Pointer addition: Page* + n is equivalent to address offset n * sizeof(Page)
- // Since mem_map is linearly mapped, mem_map[i + (1<<k)] exactly corresponds to physical address + (1<<k)*PGSIZE
- struct Page *buddy = page + (1 << current_order);
-
- // Add the buddy to a lower-level linked list
- list_add(buddy, current_order);
- }
-
- // Mark as Occupied
- page->flags = PG_used;
- page->order = order; // Record the orders that have been assigned
- page->refcnt = 1;
-
- pmm_lock.release();
- return (void *)page_to_pa(page);
- }
- current_order++;
- }
- pmm_lock.release();
- Drivers::uart_puts("PMM: OOM alloc_pages\n");
- return nullptr;
- }
-
- void free_pages(void *pa, int order)
- {
- if (!pa)
- return;
- struct Page *page = pa_to_page((uint64)pa);
- if (!page)
- return;
- pmm_lock.acquire();
-
- if (!(page->flags & PG_used))
- {
- Drivers::uart_puts("PMM: Double free warning\n");
- pmm_lock.release();
- return;
- }
-
- // Mark as basic status
- page->flags = 0;
- page->refcnt = 0;
-
- // try merge
- uint64 page_idx = page - mem_map;
-
- while (order < MAX_ORDER - 1)
- {
- // calculate Buddy index: index ^ (1 << order)
- uint64 buddy_idx = page_idx ^ (1 << order);
- struct Page *buddy = &mem_map[buddy_idx];
-
- // Check if the Buddy can be merged:
- // 1. Must be within the memory range
- // 2. Must be free (flags == 0)
- // 3. Must be at the current order (to prevent merging already split small blocks)
- if (buddy_idx >= total_pages || (buddy->flags & PG_used) || (buddy->flags & PG_reserved) || buddy->order != order)
- {
- break;
- }
-
- // Can be merged!
- // Remove Buddy from the free list
- list_del(buddy, order);
-
- // Update the current block to the merged block
- // The starting address of the merged block is the smaller one between index and buddy_index
- if (buddy_idx < page_idx)
- {
- page = buddy;
- page_idx = buddy_idx;
- }
-
- order++;
- }
-
- // Insert into the final order linked list
- list_add(page, order);
-
- pmm_lock.release();
- }
-
- void *alloc_page()
- {
- void *p = alloc_pages(0);
- if (p)
- {
- memset(p, 0, PGSIZE);
- }
- return p;
- }
-
- void free_page(void *pa)
- {
- free_pages(pa, 0);
- }
-
- void print_free_lists()
- {
- // Debug print the number of free blocks at each level
- Drivers::uart_puts("PMM Stats: [ ");
- for (int i = 0; i < MAX_ORDER; i++)
- {
- int count = 0;
- struct Page *p = free_area[i];
- while (p)
- {
- count++;
- p = p->next;
- }
- if (count > 0)
- {
- Drivers::uart_puts("Order");
- // Drivers::uart_put_int(i);
- Drivers::uart_puts(":");
- // Drivers::uart_put_int(count);
- Drivers::uart_puts(" ");
- }
- }
- Drivers::uart_puts("]\n");
- }
-} // namespace PMM
diff --git a/src/kernel/mm/slab.cc b/src/kernel/mm/slab.cc
deleted file mode 100644
index 3bb6b1b..0000000
--- a/src/kernel/mm/slab.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/slab.h"
-#include "kernel/pmm.h"
-#include "kernel/spinlock.h"
-#include "kernel/riscv.h"
-#include "drivers/uart.h"
-#include "lib/string.h"
-
-#define PG_slab 0x04
-
-// Supported object size (must be a multiple of 8 and <= 2048)
-const uint64 kmalloc_sizes[] = {
- 16, 32, 64, 128, 256, 512, 1024, 2048};
-const int NUM_CACHES = 8;
-
-struct SlabHeader
-{
- struct SlabHeader *next; // Next slab in the linked list
- uint16 free_idx; // Index of the head of the free list (0xFFFF means none)
- uint16 used_count; // Number of allocated objects
- // Followed immediately by object data...
- // The free list of objects is embedded in the first 2 bytes of the object itself (stores the index of the next object)
- uint32 padding;
-};
-
-struct KmemCache
-{
- Spinlock lock;
- uint64 obj_size;
- uint64 obj_count_per_slab;
- struct SlabHeader *slab_list; // Slab list with free objects
- const char *name;
-};
-
-struct KmemCache caches[NUM_CACHES];
-
-// Virtual address -> struct Page*
-static struct Page *virt_to_page(void *ptr)
-{
- uint64 pa = (uint64)ptr;
- return PMM::pa_to_page(pa);
-}
-
-// Slab Implementation
-
-namespace Slab
-{
-
- void init()
- {
- for (int i = 0; i < NUM_CACHES; i++)
- {
- caches[i].lock.init("slab_lock");
- caches[i].obj_size = kmalloc_sizes[i];
- caches[i].name = "kmalloc";
-
- // Calculate how many objects can fit on a page
- // Excluding the overhead of the SlabHeader
- uint64 available = PGSIZE - sizeof(struct SlabHeader);
- caches[i].obj_count_per_slab = available / caches[i].obj_size;
- caches[i].slab_list = nullptr;
- }
- Drivers::uart_puts("[Slab] Initialized kmalloc caches.\n");
- }
-
- // Allocate a new slab page for the cache
- // Must hold cache->lock
- static struct SlabHeader *grow_cache(struct KmemCache *c)
- {
- void *p = PMM::alloc_page();
- if (!p)
- return nullptr;
-
- // Mark this page as a Slab page
- struct Page *page = virt_to_page(p);
- if (page)
- {
- page->flags |= PG_slab;
- int cache_idx = c - caches;
- page->order = (uint8)cache_idx;
- }
-
- struct SlabHeader *slab = (struct SlabHeader *)p;
- slab->next = nullptr;
- slab->used_count = 0;
- slab->free_idx = 0;
- slab->padding = 0;
-
- // Initialize the free list of objects
- // The starting position of each object stores the index of the next object
- // Starting position of the object data area
- char *base = (char *)(slab + 1);
-
- for (uint i = 0; i < c->obj_count_per_slab - 1; i++)
- {
- // The content of the i-th object is i+1
- uint16 *ptr = (uint16 *)(base + i * c->obj_size);
- *ptr = i + 1;
- }
- // The last object points to 0xFFFF
- uint16 *ptr = (uint16 *)(base + (c->obj_count_per_slab - 1) * c->obj_size);
- *ptr = 0xFFFF;
-
- return slab;
- }
-
- void *kmalloc(uint64 size)
- {
- if (size == 0)
- return nullptr;
-
- // Large objects go directly through PMM
- if (size > 2048)
- {
- // calculate order
- int order = 0;
- uint64 req = size;
- uint64 pages = (size + PGSIZE - 1) / PGSIZE;
- (void)req;
-
- // calculate order: 2^order >= pages
- while ((1UL << order) < pages)
- {
- order++;
- }
- if (order > MAX_ORDER)
- return nullptr;
-
- void *p = PMM::alloc_pages(order);
- // Here, page->flags defaults to PG_used, not PG_slab
- // kfree needs to be able to recognize it
- return p;
- }
-
- int idx = 0;
- while (idx < NUM_CACHES && kmalloc_sizes[idx] < size)
- {
- idx++;
- }
-
- struct KmemCache *c = &caches[idx];
- c->lock.acquire();
-
- if (!c->slab_list)
- {
- c->slab_list = grow_cache(c);
- if (!c->slab_list)
- {
- c->lock.release();
- return nullptr;
- }
- }
-
- struct SlabHeader *slab = c->slab_list;
-
- int obj_idx = slab->free_idx;
- char *base = (char *)(slab + 1);
- void *ptr = base + obj_idx * c->obj_size;
-
- uint16 *link = (uint16 *)ptr;
- slab->free_idx = *link;
- slab->used_count++;
-
- if (slab->free_idx == 0xFFFF)
- {
- if (slab->next)
- {
- c->slab_list = slab->next;
- slab->next = nullptr;
- }
- else
- {
- c->slab_list = nullptr;
- }
- }
-
- c->lock.release();
-
- memset(ptr, 0, size);
- return ptr;
- }
-
- void kfree(void *ptr)
- {
- if (!ptr)
- return;
-
- struct Page *page = virt_to_page(ptr);
- if (!page)
- return;
-
- if (!page || !(page->flags & PG_slab))
- {
- PMM::free_pages(ptr, page->order);
- return;
- }
-
- int cache_idx = page->order;
- if (cache_idx >= NUM_CACHES)
- {
- Drivers::uart_puts("Slab: Corrupted page metadata\n");
- return;
- }
-
- struct KmemCache *c = &caches[cache_idx];
- c->lock.acquire();
-
- struct SlabHeader *slab = (struct SlabHeader *)PGROUNDDOWN((uint64)ptr);
-
- if ((uint64)ptr < (uint64)(slab + 1) || (uint64)ptr >= (uint64)slab + PGSIZE)
- {
- Drivers::uart_puts("Slab: kfree invalid pointer\n");
- c->lock.release();
- return;
- }
-
- char *base = (char *)(slab + 1);
- int obj_idx = ((uint64)ptr - (uint64)base) / c->obj_size;
-
- uint16 *link = (uint16 *)ptr;
- *link = slab->free_idx;
- slab->free_idx = (uint16)obj_idx;
-
- slab->used_count--;
-
- if (slab->used_count == 0)
- {
- struct SlabHeader **pp = &c->slab_list;
- // bool found = false;
- while (*pp)
- {
- if (*pp == slab)
- {
- *pp = slab->next;
- // found = true;
- break;
- }
- pp = &(*pp)->next;
- }
-
- page->flags &= ~PG_slab;
- PMM::free_page(slab);
- }
- else
- {
-
- if (slab->used_count == c->obj_count_per_slab - 1)
- {
- slab->next = c->slab_list;
- c->slab_list = slab;
- }
- }
-
- c->lock.release();
- }
-} \ No newline at end of file
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc
deleted file mode 100644
index be2f2f2..0000000
--- a/src/kernel/mm/vm.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/mm.h"
-#include "kernel/pmm.h"
-#include "kernel/riscv.h"
-#include "common/types.h"
-#include "lib/string.h"
-#include "drivers/uart.h"
-#include "kernel/fdt.h"
-
-extern "C"
-{
- extern char kernel_end[];
- extern char trampoline[];
-}
-
-namespace VM
-{
-
- uint64 *kernel_pagetable;
-
- static void page_ref_inc(uint64 pa)
- {
- struct Page *p = PMM::pa_to_page(pa);
- if (p)
- {
- __atomic_add_fetch(&p->refcnt, 1, __ATOMIC_RELAXED);
- }
- }
-
- static bool page_ref_dec(uint64 pa)
- {
- struct Page *p = PMM::pa_to_page(pa);
- if (p)
- {
- if (__atomic_sub_fetch(&p->refcnt, 1, __ATOMIC_RELEASE) == 0)
- {
- return true;
- }
- }
- return false;
- }
-
- static uint64 *walk(uint64 *pagetable, uint64 va, int alloc)
- {
- if (va >= MAXVA)
- return nullptr;
-
- for (int level = 2; level > 0; level--)
- {
- uint64 *pte = &pagetable[PX(level, va)];
- if (*pte & PTE_V)
- {
- pagetable = (uint64 *)PTE2PA(*pte);
- }
- else
- {
- if (!alloc || (pagetable = (uint64 *)PMM::alloc_page()) == nullptr)
- return nullptr;
-
- memset(pagetable, 0, PGSIZE);
- *pte = PA2PTE(pagetable) | PTE_V;
- }
- }
- return &pagetable[PX(0, va)];
- }
-
- int mappages(uint64 *pagetable, uint64 va, uint64 size, uint64 pa, int perm)
- {
- uint64 a, last;
- uint64 *pte;
-
- if (size == 0)
- return -1;
-
- a = PGROUNDDOWN(va);
- last = PGROUNDDOWN(va + size - 1);
-
- for (;;)
- {
- if ((pte = walk(pagetable, a, 1)) == nullptr)
- return -1;
-
- if (*pte & PTE_V)
- {
- return -1;
- }
-
- *pte = PA2PTE(pa) | perm | PTE_V;
-
- if (a == last)
- break;
- a += PGSIZE;
- pa += PGSIZE;
- }
- return 0;
- }
-
- uint64 *uvmcreate()
- {
- uint64 *pagetable = (uint64 *)PMM::alloc_page();
- if (pagetable)
- {
- memset(pagetable, 0, PGSIZE);
-
- if (mappages(pagetable, TRAMPOLINE, PGSIZE, (uint64)trampoline, PTE_R | PTE_X) < 0)
- {
- PMM::free_page(pagetable);
- return nullptr;
- }
- }
- return pagetable;
- }
-
- void uvminit(uint64 *pagetable, uchar *src, uint64 sz)
- {
- char *mem;
-
- if (sz >= PGSIZE)
- {
- Drivers::uart_puts("uvminit: initcode too big!\n");
- return;
- }
-
- mem = (char *)PMM::alloc_page();
- memset(mem, 0, PGSIZE);
-
- mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W | PTE_R | PTE_X | PTE_U);
- memmove(mem, src, sz);
- }
-
- uint64 uvmalloc(uint64 *pagetable, uint64 oldsz, uint64 newsz, int xperm)
- {
- char *mem;
- uint64 a;
-
- if (newsz < oldsz)
- return oldsz;
-
- oldsz = PGROUNDUP(oldsz);
- for (a = oldsz; a < newsz; a += PGSIZE)
- {
- mem = (char *)PMM::alloc_page();
- if (mem == nullptr)
- {
- uvmdealloc(pagetable, a, oldsz);
- return 0;
- }
- memset(mem, 0, PGSIZE);
- if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R | PTE_U | xperm) != 0)
- {
- PMM::free_page(mem);
- uvmdealloc(pagetable, a, oldsz);
- return 0;
- }
- }
- return newsz;
- }
-
- uint64 uvmdealloc(uint64 *pagetable, uint64 oldsz, uint64 newsz)
- {
- if (newsz >= oldsz)
- return oldsz;
-
- if (PGROUNDUP(newsz) < PGROUNDUP(oldsz))
- {
- int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
- uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
- }
-
- return newsz;
- }
-
- void uvmunmap(uint64 *pagetable, uint64 va, uint64 npages, int do_free)
- {
- uint64 a;
- uint64 *pte;
-
- if ((va % PGSIZE) != 0)
- return;
-
- for (a = va; a < va + npages * PGSIZE; a += PGSIZE)
- {
- if ((pte = walk(pagetable, a, 0)) == nullptr)
- continue;
-
- if ((*pte & PTE_V) == 0)
- continue;
-
- if ((PTE_FLAGS(*pte) & (PTE_R | PTE_W | PTE_X)) == 0)
- {
- continue;
- }
-
- if (do_free)
- {
- uint64 pa = PTE2PA(*pte);
- if (page_ref_dec(pa))
- {
- PMM::free_page((void *)pa);
- }
- }
- *pte = 0;
- }
- }
-
- static void freewalk(uint64 *pagetable)
- {
- for (int i = 0; i < 512; i++)
- {
- uint64 pte = pagetable[i];
- if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0)
- {
- uint64 *child = (uint64 *)PTE2PA(pte);
- freewalk(child);
- pagetable[i] = 0;
- }
- }
- PMM::free_page(pagetable);
- }
-
- void uvmfree(uint64 *pagetable, uint64 sz)
- {
- if (sz > 0)
- uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1);
- freewalk(pagetable);
- }
-
- int uvmcopy(uint64 *oldpt, uint64 *newpt, uint64 sz)
- {
- uint64 *pte;
- uint64 pa, i;
- uint flags;
-
- for (i = 0; i < sz; i += PGSIZE)
- {
- if ((pte = walk(oldpt, i, 0)) == nullptr)
- continue;
- if ((*pte & PTE_V) == 0)
- continue;
-
- pa = PTE2PA(*pte);
- flags = PTE_FLAGS(*pte);
-
- if (flags & PTE_W)
- {
- flags &= ~PTE_W;
- flags |= PTE_COW;
- *pte = PA2PTE(pa) | flags;
- }
-
- if (mappages(newpt, i, PGSIZE, pa, flags) != 0)
- {
- return -1;
- }
-
- page_ref_inc(pa);
- }
-
- sfence_vma();
- return 0;
- }
-
- int handle_cow_fault(uint64 *pagetable, uint64 va);
-
- int copyout(uint64 *pagetable, uint64 dstva, char *src, uint64 len)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
-
- while (len > 0)
- {
- va0 = PGROUNDDOWN(dstva);
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- // Note: Maybe a bug
- if (*pte & PTE_COW)
- {
- if (handle_cow_fault(pagetable, va0) < 0)
- return -1;
- // Re-walk because handle_cow_fault replaced the page mapping
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
- }
-
- pa0 = PTE2PA(*pte);
- n = PGSIZE - (dstva - va0);
- if (n > len)
- n = len;
-
- memmove((void *)(pa0 + (dstva - va0)), src, n);
-
- len -= n;
- src += n;
- dstva = va0 + PGSIZE;
- }
- return 0;
- }
-
- int copyin(uint64 *pagetable, char *dst, uint64 srcva, uint64 len)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
-
- while (len > 0)
- {
- va0 = PGROUNDDOWN(srcva);
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- pa0 = PTE2PA(*pte);
- n = PGSIZE - (srcva - va0);
- if (n > len)
- n = len;
-
- memmove(dst, (void *)(pa0 + (srcva - va0)), n);
-
- len -= n;
- dst += n;
- srcva = va0 + PGSIZE;
- }
- return 0;
- }
-
- int copyinstr(uint64 *pagetable, char *dst, uint64 srcva, uint64 max)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
- int got_null = 0;
- uint64 len = 0;
-
- while (len < max)
- {
- va0 = PGROUNDDOWN(srcva);
- pte = walk(pagetable, va0, 0);
-
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- pa0 = PTE2PA(*pte);
-
- n = PGSIZE - (srcva - va0);
- if (n > max - len)
- n = max - len;
-
- char *p = (char *)(pa0 + (srcva - va0));
- while (n > 0)
- {
- if (*p == '\0')
- {
- *dst = '\0';
- got_null = 1;
- break;
- }
- *dst = *p;
- n--;
- srcva++;
- dst++;
- p++;
- len++;
- }
- if (got_null)
- break;
- }
-
- if (got_null)
- return 0;
-
- return -1;
- }
-
- int handle_cow_fault(uint64 *pagetable, uint64 va)
- {
- if (va >= MAXVA)
- return -1;
-
- uint64 *pte = walk(pagetable, va, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- if ((*pte & PTE_COW) == 0)
- return -1;
-
- uint64 pa = PTE2PA(*pte);
- uint64 flags = PTE_FLAGS(*pte);
-
- char *mem = (char *)PMM::alloc_page();
- if (mem == nullptr)
- return -1;
-
- memmove(mem, (char *)pa, PGSIZE);
-
- uint64 new_flags = (flags | PTE_W) & ~PTE_COW;
- *pte = PA2PTE((uint64)mem) | new_flags | PTE_V;
-
- if (page_ref_dec(pa))
- {
- PMM::free_page((void *)pa);
- }
-
- sfence_vma();
- return 0;
- }
-
- static void kvmmap(uint64 va, uint64 pa, uint64 sz, int perm)
- {
- if (mappages(kernel_pagetable, va, sz, pa, perm) != 0)
- {
- Drivers::uart_puts("kvmmap: failed\n");
- while (1)
- ;
- }
- }
-
- void kvminit()
- {
- kernel_pagetable = uvmcreate();
-
- // 1. Map all device MMIO regions discovered by FDT
- for (int i = 0; i < g_devices.mmio_count; i++)
- {
- uint64 base = g_devices.mmio_regions[i].base;
- uint64 size = g_devices.mmio_regions[i].size;
- kvmmap(base, base, size, PTE_R | PTE_W);
- }
-
- // 2. Map Kernel Memory (PHYSTOP is now dynamic based on FDT)
- kvmmap(KERNBASE, KERNBASE, PHYSTOP - KERNBASE, PTE_R | PTE_W | PTE_X);
- }
-
- void kvminithart()
- {
- w_satp(MAKE_SATP(kernel_pagetable));
- sfence_vma();
- Drivers::uart_puts("[Boot] MMU ENABLED! Using virtual addresses.\n");
- }
-
- uint64 walkaddr(uint64 *pagetable, uint64 va)
- {
- uint64 *pte;
- uint64 pa;
-
- if (va >= MAXVA)
- return 0;
-
- pte = walk(pagetable, va, 0);
- if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return 0;
-
- pa = PTE2PA(*pte);
- return pa;
- }
-} \ No newline at end of file