diff options
Diffstat (limited to 'src/kernel')
| -rw-r--r-- | src/kernel/bio.cc | 139 | ||||
| -rw-r--r-- | src/kernel/config.cc | 13 | ||||
| -rw-r--r-- | src/kernel/cxx.cc | 78 | ||||
| -rw-r--r-- | src/kernel/fdt.cc | 273 | ||||
| -rw-r--r-- | src/kernel/initcode.S | 11 | ||||
| -rw-r--r-- | src/kernel/main.cc | 79 | ||||
| -rw-r--r-- | src/kernel/mm/pmm.cc | 305 | ||||
| -rw-r--r-- | src/kernel/mm/slab.cc | 259 | ||||
| -rw-r--r-- | src/kernel/mm/vm.cc | 459 | ||||
| -rw-r--r-- | src/kernel/proc/exec.cc | 260 | ||||
| -rw-r--r-- | src/kernel/proc/proc.cc | 654 | ||||
| -rw-r--r-- | src/kernel/proc/swtch.S | 37 | ||||
| -rw-r--r-- | src/kernel/sbi.cc | 52 | ||||
| -rw-r--r-- | src/kernel/spinlock.cc | 199 | ||||
| -rw-r--r-- | src/kernel/syscall.cc | 698 | ||||
| -rw-r--r-- | src/kernel/timer.cc | 66 | ||||
| -rw-r--r-- | src/kernel/trap/handler.cc | 217 | ||||
| -rw-r--r-- | src/kernel/trap/trampoline.S | 101 | ||||
| -rw-r--r-- | src/kernel/trap/trap.S | 90 |
19 files changed, 0 insertions, 3990 deletions
diff --git a/src/kernel/bio.cc b/src/kernel/bio.cc deleted file mode 100644 index 5f1aae9..0000000 --- a/src/kernel/bio.cc +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "kernel/buf.h" -#include "kernel/spinlock.h" -#include "kernel/riscv.h" -#include "drivers/virtio.h" -#include "drivers/uart.h" - -namespace BufferCache -{ - struct - { - Spinlock lock; - struct Buf buf[NBUF]; - struct Buf head; - } bcache; - - void init() - { - bcache.lock.init("bcache"); - // Initialize LRU doubly circular linked list - bcache.head.prev = &bcache.head; - bcache.head.next = &bcache.head; - for (struct Buf *b = bcache.buf; b < bcache.buf + NBUF; ++b) - { - b->lock.init("buffer"); - b->next = bcache.head.next; - b->prev = &bcache.head; - bcache.head.next->prev = b; - bcache.head.next = b; - } - Drivers::uart_puts("[Bio] Buffer cache initialized.\n"); - } - - static struct Buf* bget(uint32 dev, uint32 blockno) - { - struct Buf* b; - bcache.lock.acquire(); - - // Attempt to hit the cache - for (b = bcache.head.next; b != &bcache.head; b = b->next) - { - if (b->dev == dev && b->blockno == blockno) - { - b->refcnt++; - bcache.lock.release(); - b->lock.acquire(); // Acquire Sleep Lock - return b; - } - } - - // Cache miss, evicting LRU - for (b = bcache.head.prev; b != &bcache.head; b = b->prev) - { - if (b->refcnt == 0) - { - b->dev = dev; - b->blockno = blockno; - b->valid = 0; - b->refcnt = 1; - bcache.lock.release(); - b->lock.acquire(); - return b; - } - } - - Drivers::uart_puts("panic: bget: no buffers\n"); - while (1) - ; - } - - struct Buf* bread(uint32 dev, uint32 blockno) - { - struct Buf *b = bget(dev, blockno); - - if (!b->valid) - { - VirtIO::rw(0, b->blockno, (char *)b->data); - b->valid = 1; - } - - return b; - } - - void bwrite(struct Buf *b) - { - if (!b->lock.holding()) - { - Drivers::uart_puts("panic: bwrite\n"); - while (1) - ; - } - VirtIO::rw(1, b->blockno, (char *)b->data); - } - - void brelse(struct Buf *b) - { - if (!b->lock.holding()) - { - Drivers::uart_puts("panic: brelse\n"); - while (1) - ; - } - b->lock.release(); - - bcache.lock.acquire(); - b->refcnt--; - - if (b->refcnt == 0) - { - b->next->prev = b->prev; - b->prev->next = b->next; - - b->next = bcache.head.next; - b->prev = &bcache.head; - bcache.head.next->prev = b; - bcache.head.next = b; - } - - bcache.lock.release(); - } - - void bpin(struct Buf *b) - { - bcache.lock.acquire(); - b->refcnt++; - bcache.lock.release(); - } - - void bunpin(struct Buf* b) - { - bcache.lock.acquire(); - b->refcnt --; - bcache.lock.release(); - } - -} // namespace BufferCache diff --git a/src/kernel/config.cc b/src/kernel/config.cc deleted file mode 100644 index 36858a1..0000000 --- a/src/kernel/config.cc +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "common/types.h" - -uint64 g_uart_base = 0; -// uint64 g_clint_base = 0; -uint64 g_plic_base = 0; -uint64 g_ram_start = 0; -uint64 g_ram_size = 0; - -extern "C" uint64 g_dtb_addr;
\ No newline at end of file diff --git a/src/kernel/cxx.cc b/src/kernel/cxx.cc deleted file mode 100644 index 00f2799..0000000 --- a/src/kernel/cxx.cc +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "common/types.h" -#include "kernel/pmm.h" -#include "drivers/uart.h" - -/* - * C++ Kernel Runtime Support - * - * * Strategy: Map directly to PMM::alloc_page(). - * Pros: Simple, works immediately for VFS. - * Cons: Allocates 4KB for every object (wasteful for small objects), - * but acceptable for current stage. - */ - -void *operator new(unsigned long size) -{ - // Safety check: PMM allocates 4096 bytes max per call - if (size > 4096) - { - Drivers::uart_puts("panic: new allocation too big (max 4096)\n"); - while (1) - ; - } - - void *p = PMM::alloc_page(); - if (!p) - { - Drivers::uart_puts("panic: new out of memory\n"); - while (1) - ; - } - // PMM::alloc_page returns zeroed memory usually, - // but standard 'new' doesn't guarantee it. - // The constructor will handle initialization. - return p; -} - -void *operator new[](unsigned long size) -{ - return operator new(size); -} - -void operator delete(void *p) -{ - if (p) - PMM::free_page(p); -} - -void operator delete[](void *p) -{ - if (p) - PMM::free_page(p); -} - -// C++14 Sized Deallocation (Required by modern compilers) -// The compiler optimizes 'delete' calls to pass the size of the object -void operator delete(void *p, unsigned long size) -{ - (void)size; // We ignore size because PMM always frees a full page - if (p) - PMM::free_page(p); -} - -void operator delete[](void *p, unsigned long size) -{ - (void)size; - if (p) - PMM::free_page(p); -} - -void *operator new(unsigned long size, void *ptr) -{ - (void)size; - return ptr; -}
\ No newline at end of file diff --git a/src/kernel/fdt.cc b/src/kernel/fdt.cc deleted file mode 100644 index ae09c84..0000000 --- a/src/kernel/fdt.cc +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard Qin - * LumeOS - FDT Parser - * - * Parses the Flattened Device Tree to discover hardware. - * Populates g_devices for use by all drivers. - */ -#include "common/types.h" -#include "kernel/fdt.h" -#include "lib/string.h" - -// Global device registry -DeviceRegistry g_devices; - -// Keep g_dtb_addr for PMM to protect DTB pages -// g_dtb_addr is defined in entry.S, g_uart_base in config.cc -extern "C" uint64 g_dtb_addr; -extern uint64 g_uart_base; - -static inline uint32 bswap(uint32 x) -{ - return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | - ((x & 0xFF0000) >> 8) | ((x >> 24) & 0xFF); -} - -struct fdt_header -{ - uint32 magic; - uint32 totalsize; - uint32 off_dt_struct; - uint32 off_dt_strings; - uint32 off_mem_rsvmap; - uint32 version; - uint32 last_comp_version; - uint32 boot_cpuid_phys; - uint32 size_dt_strings; - uint32 size_dt_struct; -}; - -#define FDT_MAGIC 0xd00dfeed -#define FDT_BEGIN_NODE 1 -#define FDT_END_NODE 2 -#define FDT_PROP 3 -#define FDT_NOP 4 -#define FDT_END 9 - -// Check if 'str' starts with 'prefix' -static bool starts_with(const char *str, const char *prefix) -{ - while (*prefix) - { - if (*str != *prefix) - return false; - str++; - prefix++; - } - return true; -} - -// Check if 'haystack' contains 'needle' as a substring within 'len' bytes -// (compatible strings may have multiple null-separated entries) -static bool compat_match(const uint8 *data, uint32 len, const char *needle) -{ - uint32 nlen = strlen(needle); - for (uint32 i = 0; i + nlen <= len; i++) - { - if (memcmp(data + i, needle, nlen) == 0) - return true; - } - return false; -} - -// Add a MMIO region to the registry (avoids duplicates) -static void add_mmio_region(uint64 base, uint64 size) -{ - if (base == 0 || size == 0) - return; - // Only track I/O regions below RAM - if (base >= 0x80000000ULL) - return; - if (g_devices.mmio_count >= DeviceRegistry::MAX_MMIO) - return; - - // Check for overlap/duplicate - for (int i = 0; i < g_devices.mmio_count; i++) - { - if (g_devices.mmio_regions[i].base == base) - return; - } - - g_devices.mmio_regions[g_devices.mmio_count].base = base; - g_devices.mmio_regions[g_devices.mmio_count].size = size; - g_devices.mmio_count++; -} - -void fdt_parse(uint64 dtb) -{ - // Clear registry - memset(&g_devices, 0, sizeof(g_devices)); - - if (dtb == 0) - return; - - g_dtb_addr = dtb; - - struct fdt_header *header = (struct fdt_header *)dtb; - if (bswap(header->magic) != FDT_MAGIC) - return; - - uint8 *struct_ptr = (uint8 *)(dtb + bswap(header->off_dt_struct)); - char *strings_ptr = (char *)(dtb + bswap(header->off_dt_strings)); - - // Parsing state - char current_node_name[64]; - current_node_name[0] = '\0'; - - // Per-node state - uint64 current_reg_addr = 0; - uint64 current_reg_size = 0; - uint32 current_irq = 0; - const uint8 *current_compat = nullptr; - uint32 current_compat_len = 0; - bool has_reg = false; - bool has_compat = false; - // bool has_irq = false; // Unused - - // Depth tracking (for #address-cells / #size-cells) - // Default for root: 2 address-cells, 2 size-cells - int depth = 0; - - while (1) - { - uint32 token = bswap(*(uint32 *)struct_ptr); - struct_ptr += 4; - - if (token == FDT_END) - break; - if (token == FDT_NOP) - continue; - - if (token == FDT_BEGIN_NODE) - { - // Save node name - // char *name = (char *)struct_ptr; - int i = 0; - while (*struct_ptr != 0 && i < 63) - { - current_node_name[i++] = *struct_ptr; - struct_ptr++; - } - current_node_name[i] = '\0'; - while (*struct_ptr != 0) - struct_ptr++; - struct_ptr++; - struct_ptr = (uint8 *)(((uint64)struct_ptr + 3) & ~3); - - // Reset per-node state - current_reg_addr = 0; - current_reg_size = 0; - current_irq = 0; - current_compat = nullptr; - current_compat_len = 0; - has_reg = false; - has_compat = false; - // has_irq = false; - - depth++; - } - else if (token == FDT_END_NODE) - { - // Process the node we just finished - if (has_reg && has_compat) - { - // UART: ns16550a - if (compat_match(current_compat, current_compat_len, "ns16550")) - { - g_devices.uart.base_addr = current_reg_addr; - g_devices.uart.size = current_reg_size ? current_reg_size : 0x100; - g_devices.uart.irq = current_irq; - add_mmio_region(current_reg_addr, g_devices.uart.size); - } - // PLIC - else if (compat_match(current_compat, current_compat_len, "plic")) - { - g_devices.plic.base_addr = current_reg_addr; - g_devices.plic.size = current_reg_size ? current_reg_size : 0x4000000; - g_devices.plic.irq = 0; - add_mmio_region(current_reg_addr, g_devices.plic.size); - } - // CLINT - else if (compat_match(current_compat, current_compat_len, "clint")) - { - g_devices.clint.base_addr = current_reg_addr; - g_devices.clint.size = current_reg_size ? current_reg_size : 0x10000; - g_devices.clint.irq = 0; - add_mmio_region(current_reg_addr, g_devices.clint.size); - } - // VirtIO - else if (compat_match(current_compat, current_compat_len, "virtio")) - { - if (g_devices.virtio_count < DeviceRegistry::MAX_VIRTIO) - { - int idx = g_devices.virtio_count++; - g_devices.virtio[idx].base_addr = current_reg_addr; - g_devices.virtio[idx].size = current_reg_size ? current_reg_size : 0x1000; - g_devices.virtio[idx].irq = current_irq; - add_mmio_region(current_reg_addr, g_devices.virtio[idx].size); - } - } - } - - // Memory node: name starts with "memory" - if (has_reg && starts_with(current_node_name, "memory")) - { - g_devices.mem_base = current_reg_addr; - g_devices.mem_size = current_reg_size; - } - - depth--; - } - else if (token == FDT_PROP) - { - uint32 len = bswap(*(uint32 *)struct_ptr); - struct_ptr += 4; - uint32 nameoff = bswap(*(uint32 *)struct_ptr); - struct_ptr += 4; - - char *name = strings_ptr + nameoff; - uint8 *data = struct_ptr; - - struct_ptr += len; - struct_ptr = (uint8 *)(((uint64)struct_ptr + 3) & ~3); - - if (strcmp(name, "reg") == 0 && len >= 8) - { - // Assume 2 address-cells, 2 size-cells (standard for QEMU virt) - uint32 hi = bswap(*(uint32 *)data); - uint32 lo = bswap(*(uint32 *)(data + 4)); - current_reg_addr = ((uint64)hi << 32) | lo; - - if (len >= 16) - { - uint32 shi = bswap(*(uint32 *)(data + 8)); - uint32 slo = bswap(*(uint32 *)(data + 12)); - current_reg_size = ((uint64)shi << 32) | slo; - } - has_reg = true; - } - else if (strcmp(name, "compatible") == 0) - { - current_compat = data; - current_compat_len = len; - has_compat = true; - } - else if (strcmp(name, "interrupts") == 0 && len >= 4) - { - current_irq = bswap(*(uint32 *)data); - // has_irq = true; - } - else if (strcmp(name, "interrupts-extended") == 0 && len >= 8) - { - // interrupts-extended = <&phandle irq_num> - // IRQ number is typically the second cell - current_irq = bswap(*(uint32 *)(data + 4)); - // has_irq = true; - } - } - } - - // Legacy compat - g_uart_base = g_devices.uart.base_addr; -}
\ No newline at end of file diff --git a/src/kernel/initcode.S b/src/kernel/initcode.S deleted file mode 100644 index 22e55ca..0000000 --- a/src/kernel/initcode.S +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.section .rodata -.global initcode_start -.global initcode_end -.align 4 - -initcode_start: - .incbin "build/user/initcode" -initcode_end: diff --git a/src/kernel/main.cc b/src/kernel/main.cc deleted file mode 100644 index 6a19915..0000000 --- a/src/kernel/main.cc +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "common/types.h" -#include "kernel/riscv.h" -#include "drivers/uart.h" -#include "drivers/plic.h" -#include "drivers/virtio.h" -#include "kernel/pmm.h" -#include "kernel/mm.h" -#include "kernel/slab.h" -#include "kernel/proc.h" -#include "kernel/trap.h" -#include "kernel/timer.h" -#include "kernel/cpu.h" -#include "kernel/buf.h" -#include "fs/fs.h" -#include "fs/file.h" -#include "fs/fat32.h" -#include "lib/string.h" - -#include "kernel/fdt.h" // fdt_parse - -extern uint64 g_dtb_addr; - -// Placement new support (referenced from cxx.cc) -void *operator new(unsigned long size, void *ptr); - -volatile static int started = 0; - -extern "C" void kernel_main(uint64 hartid, uint64 dtb) -{ - if (hartid == 0) - { - fdt_parse(dtb); - - Drivers::uart_init(); - Drivers::uart_puts("\n[Lume OS] Booting...\n"); - - Drivers::uart_puts("[Boot] PMP configured.\n"); - - PMM::init(); // Physical Memory Management - VM::kvminit(); // Kernel Pagetable - VM::kvminithart(); // Enable MMU - Slab::init(); - Trap::init(); // Trap Management - Trap::inithart(); - PLIC::init(); - PLIC::inithart(); - VirtIO::init(); - BufferCache::init(); - VFS::init(); - // Initialize global FAT32 object manually (global constructors not supported yet) - new (&fat32_fs) FAT32FileSystem(); - VFS::register_fs(&fat32_fs); - FileTable::init(); - Timer::init(); - ProcManager::init(); // Process Management - ProcManager::user_init(); // Initialize first user process - - __atomic_store_n(&started, 1, __ATOMIC_RELEASE); - - Drivers::uart_puts("[Boot] System initialized. Entering scheduler...\n"); - } - else - { - while (__atomic_load_n(&started, __ATOMIC_ACQUIRE) == 0) - ; - - VM::kvminithart(); - Trap::inithart(); - PLIC::inithart(); - Timer::init(); - Drivers::uart_puts("[Boot] Hart started.\n"); - } - - ProcManager::scheduler(); // Enable Scheduler -}
\ No newline at end of file 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 diff --git a/src/kernel/proc/exec.cc b/src/kernel/proc/exec.cc deleted file mode 100644 index 8d8c467..0000000 --- a/src/kernel/proc/exec.cc +++ /dev/null @@ -1,260 +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/proc.h" -#include "kernel/mm.h" -#include "kernel/elf.h" -#include "fs/fs.h" -#include "lib/string.h" -#include "drivers/uart.h" -#include "kernel/trap.h" - -extern char trampoline[]; - -// RAII: Page Table Resource Management -class VmGuard -{ -public: - uint64 *pagetable = nullptr; - uint64 sz = 0; - - VmGuard() : pagetable(VM::uvmcreate()) {} - - ~VmGuard() - { - if (pagetable) - { - VM::uvmfree(pagetable, sz); - } - } - - // Copying is prohibited - VmGuard(const VmGuard &) = delete; - VmGuard &operator=(const VmGuard &) = delete; - - // Submit resources: Ownership transfer, destructor no longer releases - uint64 *commit() - { - uint64 *pt = pagetable; - pagetable = nullptr; - return pt; - } -}; - -// RAII: Inode Lock Management -class InodeGuard -{ -public: - Inode *ip; - InodeGuard(Inode *i) : ip(i) - { - if (ip) - VFS::ilock(ip); - } - ~InodeGuard() - { - if (ip) - { - VFS::iunlockput(ip); // Automatically unlock and release references - } - } - // Copying is prohibited - InodeGuard(const InodeGuard &) = delete; - InodeGuard &operator=(const InodeGuard &) = delete; -}; - -// laod segment -static int loadseg(uint64 *pagetable, uint64 va, Inode *ip, uint64 offset, uint64 sz) -{ - for (uint64 i = 0; i < sz; i += PGSIZE) - { - uint64 pa = VM::walkaddr(pagetable, va + i); - if (pa == 0) - { - Drivers::uart_puts("[Exec Debug] loadseg: walkaddr failed\n"); - return -1; - } - - uint64 n = PGSIZE - (va + i) % PGSIZE; - if (i + n > sz) - n = sz - i; - - // Read physical address (isUser=0) - if (ip->read((char *)(pa + (va + i) % PGSIZE), offset + i, n, 0) != (int)n) - { - Drivers::uart_puts("[Exec Debug] loadseg: read failed\n"); - return -1; - } - } - return 0; -} - -namespace Exec -{ - int exec(char *path, char **argv) - { - // 1. Get Inode - Inode *raw_ip = VFS::namei(path); - if (!raw_ip) - { - Drivers::uart_puts("[Exec Debug] namei failed for path: "); - Drivers::uart_puts(path); - Drivers::uart_puts("\n"); - return -1; - } - InodeGuard iguard(raw_ip); - - // Get ELF head - struct elfhdr elf; - if (raw_ip->read((char *)&elf, 0, sizeof(elf), 0) != sizeof(elf)) - { - Drivers::uart_puts("[Exec Debug] read elf header failed\n"); - return -1; - } - if (elf.magic != ELF_MAGIC) - { - Drivers::uart_puts("[Exec Debug] invalid elf magic\n"); - return -1; - } - - // Create new pagetable - VmGuard vm_guard; - if (!vm_guard.pagetable) - { - Drivers::uart_puts("[Exec Debug] uvmcreate failed\n"); - return -1; - } - - // Load Program Segment - struct proghdr ph; - for (int i = 0; i < elf.phnum; i++) - { - uint64 off = elf.phoff + i * sizeof(ph); - if (raw_ip->read((char *)&ph, off, sizeof(ph), 0) != sizeof(ph)) - { - Drivers::uart_puts("[Exec Debug] read proghdr failed\n"); - return -1; - } - - if (ph.type != ELF_PROG_LOAD) - continue; - if (ph.memsz < ph.filesz) - return -1; - if (ph.vaddr + ph.memsz < ph.vaddr) - return -1; - - uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, vm_guard.sz, ph.vaddr + ph.memsz, PTE_W | PTE_X | PTE_R | PTE_U); - if (sz1 == 0) - { - Drivers::uart_puts("[Exec Debug] uvmalloc failed (segment)\n"); - return -1; - } - vm_guard.sz = sz1; - - if (loadseg(vm_guard.pagetable, ph.vaddr, raw_ip, ph.off, ph.filesz) < 0) - return -1; - } - - // Prepare user stack - uint64 sz = PGROUNDUP(vm_guard.sz); - - const int stack_data_pages = 16; - const int stack_total_pages = stack_data_pages + 1; - - uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, sz, sz + stack_total_pages * PGSIZE, PTE_W | PTE_R | PTE_U); - if (sz1 == 0) - { - Drivers::uart_puts("[Exec Debug] uvmalloc failed (stack)\n"); - return -1; - } - vm_guard.sz = sz1; - - VM::uvmunmap(vm_guard.pagetable, sz, 1, 0); - - uint64 sp = sz1; - uint64 stackbase = sp - stack_data_pages * PGSIZE; - uint64 ustack[32]; - uint64 argc = 0; - - // Push parameter string - for (; argv[argc]; argc++) - { - if (argc >= 31) - return -1; - sp -= strlen(argv[argc]) + 1; - sp -= sp % 16; - if (sp < stackbase) - { - Drivers::uart_puts("[Exec Debug] stack overflow (args)\n"); - return -1; - } - - if (VM::copyout(vm_guard.pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0) - { - Drivers::uart_puts("[Exec Debug] copyout arg string failed\n"); - return -1; - } - ustack[argc] = sp; - } - ustack[argc] = 0; - - // Push into parameter array - sp -= (argc + 1) * sizeof(uint64); - sp -= sp % 16; - if (sp < stackbase) - { - Drivers::uart_puts("[Exec Debug] stack overflow (argv array)\n"); - return -1; - } - if (VM::copyout(vm_guard.pagetable, sp, (char *)ustack, (argc + 1) * sizeof(uint64)) < 0) - { - Drivers::uart_puts("[Exec Debug] copyout argv array failed\n"); - return -1; - } - - // Commit Changes - struct Proc *p = myproc(); - if (VM::mappages(vm_guard.pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0) - { - Drivers::uart_puts("[Exec Debug] mappages TRAPFRAME failed\n"); - return -1; - } - - uint64 oldsz = p->sz; - uint64 *oldpagetable = p->pagetable; - - p->tf->a0 = argc; - p->tf->a1 = sp; - p->tf->sp = sp; - p->tf->epc = elf.entry; - - char *s = path, *last = path; - while (*s) - { - if (*s == '/') - last = s + 1; - s++; - } - - size_t len = 0; - while (last[len] && len < sizeof(p->name) - 1) - { - p->name[len] = last[len]; - len++; - } - p->name[len] = '\0'; - - // change pagetable - p->pagetable = vm_guard.commit(); - p->sz = vm_guard.sz; - - // release old pagetable - VM::uvmfree(oldpagetable, oldsz); - asm volatile("fence.i"); - - return 0; // iguard unlocks and releases IP upon destruction - } -}
\ No newline at end of file diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc deleted file mode 100644 index 3923fe8..0000000 --- a/src/kernel/proc/proc.cc +++ /dev/null @@ -1,654 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "kernel/proc.h" -#include "kernel/proc_def.h" -#include "kernel/runqueue.h" -#include "kernel/cpu.h" -#include "kernel/spinlock.h" -#include "kernel/pmm.h" -#include "kernel/mm.h" -#include "kernel/trap.h" -#include "kernel/riscv.h" -#include "kernel/slab.h" -#include "drivers/uart.h" -#include "fs/fs.h" -#include "fs/file.h" -#include "lib/string.h" - -// #define NPROC 64 -#define NCPU 8 - -extern "C" void swtch(struct Context *old_ctx, struct Context *new_ctx); -extern char uservec[], trampoline[]; -extern "C" void usertrap(); -extern "C" void userret(uint64, uint64); -extern char initcode_start[], initcode_end[]; - -// struct Proc procs[NPROC]; -struct Proc *proc_list_head = nullptr; -struct Proc *initproc = nullptr; -struct Spinlock proc_mem_lock; -struct cpu cpus[NCPU]; -struct RunQueue runqueues[NCPU]; - - -static int nextpid = 1; - - -struct cpu *mycpu() -{ - int id = r_tp(); - return &cpus[id]; -} - - -void RunQueue::init(const char *name) -{ - lock.init(name); - count = 0; - for (int i = 0; i < N_PRIO; i++) - { - heads[i] = nullptr; - tails[i] = nullptr; - } -} - -void RunQueue::enqueue(struct Proc *p) -{ - if (p->priority < 0 || p->priority >= N_PRIO) - p->priority = PRIO_MIN; - p->next = nullptr; - if (heads[p->priority] == nullptr) - { - heads[p->priority] = p; - tails[p->priority] = p; - } - else - { - tails[p->priority]->next = p; - tails[p->priority] = p; - } - count++; -} - -struct Proc *RunQueue::dequeue() -{ - for (int i = 0; i < N_PRIO; i++) - { - if (heads[i]) - { - struct Proc *p = heads[i]; - heads[i] = p->next; - if (!heads[i]) - tails[i] = nullptr; - p->next = nullptr; - count--; - return p; - } - } - return nullptr; -} - -struct Proc *RunQueue::steal() -{ - for (int i = N_PRIO - 1; i >= 0; i--) - { - if (heads[i]) - { - struct Proc *p = heads[i]; - heads[i] = p->next; - if (!heads[i]) - tails[i] = nullptr; - p->next = nullptr; - count--; - return p; - } - } - return nullptr; -} - -// Trap Return Functions - -void usertrapret() -{ - struct Proc *p = myproc(); - - intr_off(); - - // Set stvec to point to uservec in the trampoline - // When an interrupt occurs in user mode, the CPU will jump here - uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline); - w_stvec(trampoline_uservec); - - // Fill in the Trapframe, used when uservec saves the kernel state - p->tf->kernel_satp = r_satp(); - p->tf->kernel_sp = (uint64)p->kstack + PGSIZE; - p->tf->kernel_trap = (uint64)usertrap; - p->tf->kernel_hartid = r_tp(); - - // Set SSTATUS - // SPP = 0 (return to User Mode) - // SPIE = 1 (enable interrupts) - unsigned long x = r_sstatus(); - x &= ~SSTATUS_SPP; - x |= SSTATUS_SPIE; - w_sstatus(x); - - // Set SEPC to the user program counter - w_sepc(p->tf->epc); - - // Prepare user page table SATP - uint64 satp = MAKE_SATP(p->pagetable); - - // Calculate the virtual address of userret in the trampoline - uint64 fn = TRAMPOLINE + ((uint64)userret - (uint64)trampoline); - - // Jump to userret, with parameters being the TRAPFRAME address and the user page table SATP - ((void (*)(uint64, uint64))fn)(TRAPFRAME, satp); -} - - -void forkret() -{ - - struct cpu *c = mycpu(); - c->runqueue->lock.release(); - - // Debug - // Drivers::uart_puts("[Proc] forkret: jumping to user.\n"); - - // Enter user mode - usertrapret(); -} - -// ProcManager Implementation - -static Proc *allocproc() -{ - struct Proc *p; - proc_mem_lock.acquire(); - - p = (struct Proc *)Slab::kmalloc(sizeof(struct Proc)); - - if (!p) - { - proc_mem_lock.release(); - return 0; - } - - memset(p, 0, sizeof(struct Proc)); - - p->all_next = proc_list_head; - p->all_prev = nullptr; - if (proc_list_head) - proc_list_head->all_prev = p; - proc_list_head = p; - - - p->state = USED; - p->pid = nextpid++; - p->priority = 0; - p->killed = 0; - p->cpu = mycpu(); - p->cwd = nullptr; - for (int i = 0; i < NOFILE; i++) - p->ofile[i] = nullptr; - - if ((p->tf = (struct Trapframe *)PMM::alloc_page()) == 0) - { - p->state = UNUSED; - if (p->all_next) - p->all_next->all_prev = p->all_prev; - if (p->all_prev) - p->all_prev->all_next = p->all_next; - if (p == proc_list_head) - proc_list_head = p->all_next; - Slab::kfree(p); - proc_mem_lock.release(); - return 0; - } - - if ((p->kstack = PMM::alloc_page()) == 0) - { - PMM::free_page(p->tf); - p->state = UNUSED; - if (p->all_next) - p->all_next->all_prev = p->all_prev; - if (p->all_prev) - p->all_prev->all_next = p->all_next; - if (p == proc_list_head) - proc_list_head = p->all_next; - Slab::kfree(p); - - proc_mem_lock.release(); - return 0; - } - memset(p->kstack, 0, PGSIZE); - - memset(&p->context, 0, sizeof(p->context)); - - // Set the context so that the next time this process is scheduled, it starts executing directly from forkret - p->context.ra = (uint64)forkret; - p->context.sp = (uint64)p->kstack + PGSIZE; - return p; -} - -static void freeproc(struct Proc *p) -{ - if (p->tf) - PMM::free_page(p->tf); - p->tf = 0; - if (p->kstack) - PMM::free_page(p->kstack); - p->kstack = 0; - if (p->pagetable) - VM::uvmfree(p->pagetable, p->sz); - for (int i = 0; i < NOFILE; i++) - { - if (p->ofile[i]) - { - FileTable::close(p->ofile[i]); - p->ofile[i] = nullptr; - } - } - if (p->cwd) - { - VFS::iput(p->cwd); - p->cwd = nullptr; - } - - if (p->all_prev) - p->all_prev->all_next = p->all_next; - else - proc_list_head = p->all_next; - - if (p->all_next) - p->all_next->all_prev = p->all_prev; - - Slab::kfree(p); -} - -int fork() -{ - struct Proc *np; - struct Proc *p = myproc(); - - if ((np = allocproc()) == 0) - return -1; - - np->pagetable = VM::uvmcreate(); - np->sz = p->sz; - if (VM::uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) - { - freeproc(np); - proc_mem_lock.release(); - return -1; - } - - - if (VM::mappages(np->pagetable, TRAPFRAME, PGSIZE, (uint64)np->tf, PTE_R | PTE_W) < 0) - { - freeproc(np); - proc_mem_lock.release(); - return -1; - } - - *(np->tf) = *(p->tf); - np->tf->a0 = 0; - strcpy(np->name, p->name); - np->parent = p; - np->priority = p->priority; - - for (int i = 0; i < NOFILE; i++) - { - if (p->ofile[i]) - { - np->ofile[i] = FileTable::dup(p->ofile[i]); - } - } - - if (p->cwd) - { - np->cwd = VFS::idup(p->cwd); - } - - proc_mem_lock.release(); - - struct cpu *c = mycpu(); - c->runqueue->lock.acquire(); - np->state = RUNNABLE; - c->runqueue->enqueue(np); - c->runqueue->lock.release(); - - return np->pid; -} - -namespace ProcManager -{ - - void init() - { - proc_mem_lock.init("proc_mem"); - - proc_list_head = nullptr; - - for (int i = 0; i < NCPU; i++) - { - cpus[i].runqueue = &runqueues[i]; - cpus[i].runqueue->init("runqueue"); - } - } - - void scheduler() - { - struct Proc *p; - struct cpu *c = mycpu(); - c->proc = 0; - Drivers::uart_puts("[Proc] Scheduler started (Per-CPU).\n"); - - for (;;) - { - intr_on(); - - // Get from the local queue - c->runqueue->lock.acquire(); - p = c->runqueue->dequeue(); - c->runqueue->lock.release(); - - // Work Stealing - if (!p) - { - for (int i = 0; i < NCPU; i++) - { - if ((uint64)i == r_tp()) - continue; - - struct cpu *victim = &cpus[i]; - victim->runqueue->lock.acquire(); - if (victim->runqueue->count > 0) - p = victim->runqueue->steal(); - victim->runqueue->lock.release(); - if (p) - break; - } - } - - if (p) - { - p->state = RUNNING; - c->proc = p; - - c->runqueue->lock.acquire(); - swtch(&c->context, &p->context); - c->runqueue->lock.release(); - - c->proc = 0; - } - } - } - - void yield() - { - struct Proc *p = myproc(); - struct cpu *c = mycpu(); - c->runqueue->lock.acquire(); - if (p && p->state == RUNNING) - { - p->state = RUNNABLE; - if (p->priority < PRIO_MIN) - p->priority++; - c->runqueue->enqueue(p); - swtch(&p->context, &c->context); - } - c->runqueue->lock.release(); - } - - void user_init() - { - struct Proc *p = allocproc(); - if (!p) - return; - - initproc = p; - - p->pagetable = VM::uvmcreate(); - - uint64 initcode_sz = initcode_end - initcode_start; - Drivers::uart_puts("[Proc] initcode size: "); - Drivers::uart_put_int(initcode_sz); - Drivers::uart_puts(" bytes\n"); - - uint64 code_pages = PGROUNDUP(initcode_sz) / PGSIZE; - - for (uint64 i = 0; i < code_pages; i++) - { - void *mem = PMM::alloc_page(); - if (!mem) - { - Drivers::uart_puts("user_init: out of memory for code\n"); - return; - } - memset(mem, 0, PGSIZE); - - uint64 src_offset = i * PGSIZE; - uint64 copy_len = PGSIZE; - if (src_offset + copy_len > initcode_sz) - { - copy_len = initcode_sz - src_offset; - } - memmove(mem, (void *)(initcode_start + src_offset), copy_len); - - if (VM::mappages(p->pagetable, i * PGSIZE, PGSIZE, (uint64)mem, PTE_R | PTE_W | PTE_X | PTE_U) < 0) - { - Drivers::uart_puts("user_init: mappages code failed\n"); - return; - } - } - - uint64 stack_va = (code_pages + 1) * PGSIZE; - - void *stack = PMM::alloc_page(); - if (!stack) - return; - memset(stack, 0, PGSIZE); - - if (VM::mappages(p->pagetable, stack_va, PGSIZE, (uint64)stack, PTE_R | PTE_W | PTE_U) < 0) - return; - - if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0) - return; - - p->tf->epc = 0; - p->tf->sp = stack_va + PGSIZE; - p->sz = stack_va + PGSIZE; - strcpy(p->name, "initcode"); - - p->cwd = nullptr; - - proc_mem_lock.release(); - - struct cpu *c = &cpus[0]; - c->runqueue->lock.acquire(); - p->state = RUNNABLE; - c->runqueue->enqueue(p); - c->runqueue->lock.release(); - - Drivers::uart_puts("[Proc] user_init success. PID: 1\n"); - asm volatile("fence.i"); - } - - void sleep(void *chan, Spinlock *lk) - { - struct Proc *p = myproc(); - struct cpu *c = mycpu(); - - if (lk && lk != &proc_mem_lock) - lk->release(); - - c->runqueue->lock.acquire(); - p->chan = chan; - p->state = SLEEPING; - swtch(&p->context, &c->context); - p->chan = 0; - c->runqueue->lock.release(); - - if (lk && lk != &proc_mem_lock) - lk->acquire(); - } - - void wakeup(void *chan) - { - for (struct Proc *p = proc_list_head; p != nullptr; p = p->all_next) - { - if (p->state == SLEEPING && p->chan == chan) - { - struct cpu *c = mycpu(); - c->runqueue->lock.acquire(); - p->state = RUNNABLE; - c->runqueue->enqueue(p); - c->runqueue->lock.release(); - } - } - } - - void exit(int status) - { - struct Proc *p = myproc(); - if (p == initproc) - while (1) - ; - - wakeup(p->parent); - - proc_mem_lock.acquire(); - - for (struct Proc *pp = proc_list_head; pp != nullptr; pp = pp->all_next) - { - if (pp->parent == p) - { - pp->parent = initproc; - wakeup(initproc); - } - } - - proc_mem_lock.release(); - - p->xstate = status; - - struct cpu *c = mycpu(); - c->runqueue->lock.acquire(); - p->state = ZOMBIE; - swtch(&p->context, &c->context); - while (1) - ; - } - - int wait(uint64 addr) - { - - struct Proc *np; - int havekids, pid; - struct Proc *p = myproc(); - for (;;) - { - havekids = 0; - proc_mem_lock.acquire(); - - for (np = proc_list_head; np != nullptr; np = np->all_next) - { - if (np->parent == p) - { - havekids = 1; - if (np->state == ZOMBIE) - { - - struct cpu *child_cpu = np->cpu; - if (child_cpu) - { - proc_mem_lock.release(); - child_cpu->runqueue->lock.acquire(); - child_cpu->runqueue->lock.release(); - proc_mem_lock.acquire(); - } - - pid = np->pid; - if (addr != 0 && VM::copyout(p->pagetable, addr, (char *)&np->xstate, sizeof(np->xstate)) < 0) - { - proc_mem_lock.release(); - return -1; - } - freeproc(np); - proc_mem_lock.release(); - return pid; - } - } - } - proc_mem_lock.release(); - - if (!havekids || p->state == ZOMBIE) - return -1; - sleep(p, &proc_mem_lock); - } - } - - int kill(int pid) - { - Proc* p; - proc_mem_lock.acquire(); - for (p = proc_list_head; p != nullptr; p = p->all_next) - { - if (p->pid == pid) - { - p->killed = 1; - - if (p->state == SLEEPING) - { - p->state = RUNNABLE; - - struct cpu *c = mycpu(); - c->runqueue->lock.acquire(); - c->runqueue->enqueue(p); - c->runqueue->lock.release(); - } - - proc_mem_lock.release(); - return 0; - } - } - proc_mem_lock.release(); - return -1; - } - - int growproc(int n) - { - uint64 sz; - struct Proc *p = myproc(); - - sz = p->sz; - - if (n > 0) - { - // Call VM::uvmalloc to allocate memory - // Parameters: page table, old size, new size, permissions (PTE_W) - if ((sz = VM::uvmalloc(p->pagetable, sz, sz + n, PTE_W | PTE_R | PTE_U)) == 0) - { - return -1; - } - } - else if (n < 0) - { - sz = VM::uvmdealloc(p->pagetable, sz, sz + n); - } - - p->sz = sz; - return 0; - } - - void create_kernel_thread(void (*func)(), const char *name) - { - (void)func; - (void)name; - } -}
\ No newline at end of file diff --git a/src/kernel/proc/swtch.S b/src/kernel/proc/swtch.S deleted file mode 100644 index d55c03e..0000000 --- a/src/kernel/proc/swtch.S +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.global swtch - -swtch: - sd ra, 0(a0) - sd sp, 8(a0) - sd s0, 16(a0) - sd s1, 24(a0) - sd s2, 32(a0) - sd s3, 40(a0) - sd s4, 48(a0) - sd s5, 56(a0) - sd s6, 64(a0) - sd s7, 72(a0) - sd s8, 80(a0) - sd s9, 88(a0) - sd s10, 96(a0) - sd s11, 104(a0) - - ld ra, 0(a1) - ld sp, 8(a1) - ld s0, 16(a1) - ld s1, 24(a1) - ld s2, 32(a1) - ld s3, 40(a1) - ld s4, 48(a1) - ld s5, 56(a1) - ld s6, 64(a1) - ld s7, 72(a1) - ld s8, 80(a1) - ld s9, 88(a1) - ld s10, 96(a1) - ld s11, 104(a1) - - ret diff --git a/src/kernel/sbi.cc b/src/kernel/sbi.cc deleted file mode 100644 index 5ae7edb..0000000 --- a/src/kernel/sbi.cc +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "common/types.h" -#include "kernel/sbi.h" - -namespace SBI -{ - struct sbiret - { - long error; - long value; - }; - - struct sbiret sbi_call(int ext, int fid, uint64 arg0, uint64 arg1, uint64 arg2) - { - struct sbiret ret; - register uint64 a0 asm("a0") = arg0; - register uint64 a1 asm("a1") = arg1; - register uint64 a2 asm("a2") = arg2; - register uint64 a6 asm("a6") = fid; - register uint64 a7 asm("a7") = ext; - - asm volatile( - "ecall" - : "=r"(a0), "=r"(a1) - : "r"(a0), "r"(a1), "r"(a2), "r"(a6), "r"(a7) - : "memory"); - ret.error = a0; - ret.value = a1; - return ret; - } - - void set_timer(uint64 stime_value) - { - sbi_call(0x54494D45, 0, stime_value, 0, 0); - } - - void sbi_shutdown() - { - sbi_call(0x53525354, 0, 0, 0, 0); - sbi_call(0x08, 0, 0, 0, 0); - while (1) - ; - } - - void sbi_reboot() - { - sbi_call(SBI_EID_SRST, SBI_FID_SRST_RESET, SBI_SRST_TYPE_COLD_REBOOT, SBI_SRST_REASON_NONE, 0); - } -}
\ No newline at end of file diff --git a/src/kernel/spinlock.cc b/src/kernel/spinlock.cc deleted file mode 100644 index aadce21..0000000 --- a/src/kernel/spinlock.cc +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "kernel/spinlock.h" -#include "kernel/riscv.h" -#include "kernel/cpu.h" -#include "kernel/proc_def.h" -#include "drivers/uart.h" - -extern struct cpu cpus[]; - -namespace ProcManager -{ - void sleep(void *chan, Spinlock *lk); - void wakeup(void *chan); -} - -// Interrupt Depth Management -void push_off(void); -void pop_off(void); - -// // Get the pointer of the current CPU -// // Depends on r_tp() in riscv.h to read the tp register -// struct cpu *mycpu() -// { -// int id = r_tp(); -// return &cpus[id]; -// } - -// Get the current process -// Must be called with interrupts disabled, or read atomically in a safe manner -struct Proc *myproc() -{ - push_off(); - struct cpu *c = mycpu(); - struct Proc *p = c->proc; - pop_off(); - return p; -} - -// Spinlock Implementation - -void Spinlock::init(const char *lock_name) -{ - name = lock_name; - locked = 0; - cpu = nullptr; -} - -void Spinlock::acquire() -{ - push_off(); // Disable interrupts: prevent deadlocks (interrupt handler requests a lock that is already held) - - if (holding()) - { - Drivers::uart_puts("panic: recursive acquire "); - Drivers::uart_puts(name); - Drivers::uart_puts("\n"); - while (1) - ; - } - - // Atomic Exchange - // __ATOMIC_ACQUIRE: Ensures that reads and writes after the acquire are not reordered before the acquire - while (__atomic_exchange_n(&locked, 1, __ATOMIC_ACQUIRE)) - { - // Busy-wait (Spinning) - // Optimization: Read-only, no writes, reducing cache coherence traffic - while (__atomic_load_n(&locked, __ATOMIC_RELAXED) == 1) - { - asm volatile("nop"); // RISC-V indicates that the CPU is in a spin state - } - } - - // Record holder - cpu = mycpu(); -} - -void Spinlock::release() -{ - if (!holding()) - { - Drivers::uart_puts("panic: release not holding\n"); - while (1) - ; - } - - cpu = nullptr; - - // Atomic Store - // __ATOMIC_RELEASE: Ensures all reads and writes before the Release are completed - __atomic_store_n(&locked, 0, __ATOMIC_RELEASE); - - pop_off(); -} - -// Check if the current CPU holds the lock -bool Spinlock::holding() -{ - // Interrupt checks must be disabled, otherwise a process switch may occur causing CPU fluctuations. - int r; - push_off(); - r = (locked && cpu == mycpu()); - pop_off(); - return r; -} - - -// Mutex Implementation (Sleep Locks) - -void Mutex::init(const char *lock_name) -{ - name = lock_name; - locked = 0; - pid = 0; - lk.init("mutex_internal"); -} - -void Mutex::acquire() -{ - lk.acquire(); // Acquire the internal lock to protect the locked field - - while (locked) - { - // Lock is held, preparing to sleep - // Atomicity contract of sleep(): - // 1. Mark the current process as SLEEPING - // 2. Release lk (so others can operate on locked) - // 3. Switch CPU (context switch) - // 4. After being woken up, reacquire the lk lock and return - ProcManager::sleep(this, &lk); - } - - locked = 1; - pid = myproc()->pid; - - lk.release(); -} - -void Mutex::release() -{ - lk.acquire(); - - locked = 0; - pid = 0; - - // Wake up all processes sleeping on this lock (chan = this) - ProcManager::wakeup(this); - - lk.release(); -} - -bool Mutex::holding() -{ - lk.acquire(); // Must use a lock when reading to prevent race conditions. - bool r = locked && (pid == myproc()->pid); - lk.release(); - return r; -} - -// Interrupt Depth Management - -void push_off(void) -{ - int old = intr_get(); - intr_off(); - - struct cpu *c = mycpu(); - - if (c->noff == 0) - c->intena = old; - - c->noff += 1; -} - -void pop_off(void) -{ - struct cpu *c = mycpu(); - - if (intr_get()) - { - Drivers::uart_puts("panic: pop_off - interruptible\n"); - while (1) - ; - } - if (c->noff < 1) - { - Drivers::uart_puts("panic: pop_off count\n"); - while (1) - ; - } - - c->noff -= 1; - - // An interrupt is only truly enabled when the nesting level returns to zero and the outermost layer allows interrupts. - if (c->noff == 0 && c->intena) - intr_on(); -}
\ No newline at end of file diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc deleted file mode 100644 index 0979c24..0000000 --- a/src/kernel/syscall.cc +++ /dev/null @@ -1,698 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard Qin - */ -#include "kernel/syscall.h" -#include "common/types.h" -#include "common/fcntl.h" -#include "kernel/proc.h" -#include "kernel/riscv.h" -#include "drivers/uart.h" -#include "drivers/virtio.h" -#include "kernel/timer.h" -#include "kernel/mm.h" -#include "kernel/trap.h" -#include "kernel/slab.h" -#include "kernel/sbi.h" -#include "fs/fat32.h" -#include "fs/file.h" -#include "lib/string.h" -#include "lib/errno.h" - -extern "C++" int fork(); -namespace Exec -{ - int exec(char *path, char **argv); -} - -namespace ProcManager -{ - void exit(int status); - int wait(uint64_t addr); -} - -static uint64_t argraw(int n) -{ - Proc *p = myproc(); - switch (n) - { - case 0: - return p->tf->a0; - case 1: - return p->tf->a1; - case 2: - return p->tf->a2; - case 3: - return p->tf->a3; - case 4: - return p->tf->a4; - case 5: - return p->tf->a5; - default: - return static_cast<uint64_t>(-1); - } -} - -static int argint(int n, int *ip) -{ - *ip = static_cast<int>(argraw(n)); - return 0; -} - -static int argstr(int n, char *buf, int max) -{ - uint64 addr = argraw(n); - return VM::copyinstr(myproc()->pagetable, buf, addr, max); -} - -struct KernelArgv -{ - static const int MAX_ARGS = 32; - static const int MAX_ARG_LEN = 128; - char *args[MAX_ARGS]; - - KernelArgv() { memset(args, 0, sizeof(args)); } - ~KernelArgv() - { - for (int i = 0; i < MAX_ARGS; i++) - if (args[i]) - { - Slab::kfree(args[i]); - args[i] = nullptr; - } - } - KernelArgv(const KernelArgv &) = delete; - KernelArgv &operator=(const KernelArgv &) = delete; -}; - -static int fdalloc(struct file *f) -{ - struct Proc *p = myproc(); - for (int i = 0; i < NOFILE; i++) - { - if (p->ofile[i] == 0) - { - p->ofile[i] = f; - return i; - } - } - return -1; -} - -// sys_openat(int dfd, const char *filename, int flags, mode_t mode) -static uint64 sys_openat() -{ - char path[128]; - int dfd, omode, mode_unused; - int fd; - struct file *f; - Inode *ip; - - if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &omode) < 0 || argint(3, &mode_unused) < 0) - return -EINVAL; - - if (omode & O_CREATE) - { - ip = VFS::namei(path); - if (ip == nullptr) - { - char name[128]; - Inode *dp = VFS::nameiparent(path, name); - if (dp) - { - VFS::ilock(dp); - ip = dp->create(name, T_FILE, 0, 0); - VFS::iunlockput(dp); - } - } - } - else - { - ip = VFS::namei(path); - } - - if (ip == nullptr) - return -ENOENT; - - VFS::ilock(ip); - if ((omode & O_TRUNC) && ip->type == T_FILE) - { - ip->truncate(); - } - VFS::iunlock(ip); - - f = FileTable::alloc(); - if (f == nullptr) - { - VFS::iput(ip); - return -ENFILE; - } - - fd = fdalloc(f); - if (fd < 0) - { - f->ref = 0; - f->type = FD_NONE; - VFS::iput(ip); - return -EMFILE; - } - - f->type = FD_INODE; - f->ip = ip; - f->off = 0; - f->readable = !(omode & O_WRONLY); - f->writable = (omode & O_WRONLY) || (omode & O_RDWR); - - return fd; -} - -// sys_mkdirat(int dfd, const char *pathname, mode_t mode) -static uint64 sys_mkdirat() -{ - char path[128]; - int dfd, mode; - - if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0) - return -EINVAL; - - Inode *ip = VFS::namei(path); - if (ip != nullptr) - { - VFS::iput(ip); - return -EEXIST; - } - - char name[128]; - Inode *dp = VFS::nameiparent(path, name); - if (dp == nullptr) - return -ENOENT; - - VFS::ilock(dp); - ip = dp->create(name, T_DIR, 0, 0); - VFS::iunlockput(dp); - - if (ip == nullptr) - return -EIO; - - VFS::iput(ip); - return 0; -} - -static uint64 sys_chdir() -{ - char path[128]; - if (argstr(0, path, 128) < 0) - return -EFAULT; - - Inode *ip = VFS::namei(path); - if (ip == nullptr) - return -ENOENT; - - VFS::ilock(ip); - if (ip->type != T_DIR) - { - VFS::iunlockput(ip); - return -ENOTDIR; - } - VFS::iunlock(ip); - - struct Proc *p = myproc(); - if (p->cwd) - VFS::iput(p->cwd); - p->cwd = ip; - return 0; -} - -static uint64 sys_dup() -{ - int oldfd; - if (argint(0, &oldfd) < 0) - return -EINVAL; - - struct Proc *p = myproc(); - if (oldfd < 0 || oldfd >= NOFILE || p->ofile[oldfd] == nullptr) - return -EBADF; - - struct file *f = FileTable::dup(p->ofile[oldfd]); - int newfd = fdalloc(f); - if (newfd < 0) - { - FileTable::close(f); - return -EMFILE; - } - return newfd; -} - -static uint64 sys_fstat() -{ - int fd; - uint64 stat_addr; - - if (argint(0, &fd) < 0 || argint(1, (int *)&stat_addr) < 0) - return -EINVAL; - - struct Proc *p = myproc(); - if (fd < 0 || fd >= NOFILE || p->ofile[fd] == nullptr) - return -EBADF; - - if (FileTable::stat(p->ofile[fd], stat_addr) < 0) - return -EIO; - - return 0; -} - -// sys_mknodat(int dfd, const char *filename, mode_t mode, dev_t dev) -static uint64 sys_mknodat() -{ - char path[128]; - int dfd, mode, dev; - - if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0 || argint(3, &dev) < 0) - return -EINVAL; - - Inode *ip = VFS::namei(path); - if (ip != nullptr) - { - VFS::iput(ip); - return -EEXIST; - } - - char name[128]; - Inode *dp = VFS::nameiparent(path, name); - if (dp == nullptr) - return -ENOENT; - - // Decode dev_t (Assuming simplified minor/major for now) - int major = (dev >> 20) & 0xFFF; // Just a guess for Linux packing, or pass raw - int minor = dev & 0xFFFFF; - - // For Phase 1 compatibility with init.cc: - // init.cc passes raw major/minor. Shim will pack them. - // We just unpack naively or assume Shim passed us correct structure. - - VFS::ilock(dp); - ip = dp->create(name, T_DEVICE, major, minor); - VFS::iunlockput(dp); - - if (ip == nullptr) - return -EIO; - - VFS::iput(ip); - return 0; -} - -static uint64 sys_close() -{ - int fd; - if (argint(0, &fd) < 0) - return -EINVAL; - - struct Proc *p = myproc(); - if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) - return -EBADF; - - FileTable::close(p->ofile[fd]); - p->ofile[fd] = 0; - return 0; -} - -static uint64 sys_pipe2() -{ - uint64 fdarray; - int flags; - struct file *rf, *wf; - int fd0, fd1; - struct Proc *p = myproc(); - - if (argint(0, (int *)&fdarray) < 0 || argint(1, &flags) < 0) - return -EFAULT; - - if (Pipe::create_pair(&rf, &wf) < 0) - return -ENFILE; - - if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) - { - if (fd0 >= 0) - p->ofile[fd0] = nullptr; - FileTable::close(rf); - FileTable::close(wf); - return -EMFILE; - } - - if (VM::copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(int)) < 0 || - VM::copyout(p->pagetable, fdarray + sizeof(int), (char *)&fd1, sizeof(int)) < 0) - { - p->ofile[fd0] = nullptr; - p->ofile[fd1] = nullptr; - FileTable::close(rf); - FileTable::close(wf); - return -EFAULT; - } - return 0; -} - -static uint64 sys_unlinkat() -{ - char path[128], name[128]; - int dfd, flag; - - if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &flag) < 0) - return -EINVAL; - - Inode *dp = VFS::nameiparent(path, name); - if (!dp) - return -ENOENT; - - VFS::ilock(dp); - int ret = dp->unlink(name); - VFS::iunlockput(dp); - - return (ret < 0) ? -EIO : 0; -} - -// sys_linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) -static uint64 sys_linkat() -{ - // FAT32 does not support hard links. - // Return Error to allow compilation/running to proceed (ln will fail gracefully). - return -EPERM; -} - -static uint64 sys_execve() -{ - char path[128]; - uint64 uargv_ptr; - - if (argstr(0, path, sizeof(path)) < 0) - return -EFAULT; - - uargv_ptr = argraw(1); - // uenvp_ptr = argraw(2); // Ignored - - KernelArgv kargv; - - for (int i = 0; i < KernelArgv::MAX_ARGS; ++i) - { - uint64 uarg_str_ptr; - if (VM::copyin(myproc()->pagetable, (char *)&uarg_str_ptr, uargv_ptr + i * sizeof(uint64), sizeof(uint64)) < 0) - { - return -EFAULT; - } - - if (uarg_str_ptr == 0) - { - kargv.args[i] = nullptr; - break; - } - - kargv.args[i] = (char *)Slab::kmalloc(KernelArgv::MAX_ARG_LEN); - if (kargv.args[i] == nullptr) - { - return -ENOMEM; - } - - if (VM::copyinstr(myproc()->pagetable, kargv.args[i], uarg_str_ptr, KernelArgv::MAX_ARG_LEN) < 0) - { - return -EFAULT; - } - } - return Exec::exec(path, kargv.args); -} - -static uint64 sys_exit() -{ - int n; - if (argint(0, &n) < 0) - return -EINVAL; - ProcManager::exit(n); - return 0; -} - -static uint64 sys_clone() -{ - return static_cast<uint64>(fork()); -} - -static uint64 sys_wait4() -{ - uint64 status_addr; - - // argraw(0) is pid (ignored) - status_addr = argraw(1); - // argraw(2) is options (ignored) - // argraw(3) is rusage (ignored) - - if (status_addr == static_cast<uint64>(-1)) - return -EINVAL; - - return static_cast<uint64>(ProcManager::wait(status_addr)); -} - -static uint64 sys_getpid() -{ - return static_cast<uint64>(myproc()->pid); -} - -static uint64 sys_putc() -{ - char c = static_cast<char>(argraw(0)); - Drivers::uart_putc(c); - return 0; -} - -static uint64 sys_write() -{ - struct file *f; - int n; - uint64 p; - int fd; - - if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0) - return -EINVAL; - - p = argraw(1); - - struct Proc *proc = myproc(); - - if (fd == 1 && proc->ofile[fd] == nullptr) - { - constexpr int MAX_WRITE_BUF = 128; - char buf[MAX_WRITE_BUF]; - int i = 0; - - while (i < n) - { - int len = n - i; - if (len > MAX_WRITE_BUF) - len = MAX_WRITE_BUF; - - if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64>(len)) < 0) - return -EFAULT; - - for (int j = 0; j < len; j++) - { - Drivers::uart_putc(buf[j]); - } - i += len; - } - return static_cast<uint64>(n); - } - - if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) - return -EBADF; - - return FileTable::write(f, p, n); -} - -static uint64_t sys_read() -{ - struct file *f; - int n; - uint64 p; - int fd; - - if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0) - return -EINVAL; - - p = argraw(1); - - struct Proc *proc = myproc(); - if (fd == 0 && proc->ofile[fd] == nullptr) - return Drivers::console_read(p, n); - - if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) - return -EBADF; - - return FileTable::read(f, p, n); -} - -static uint64 sys_brk() -{ - int n; - if (argint(0, &n) < 0) - return -EINVAL; - - uint64 addr = myproc()->sz; - if (ProcManager::growproc(n) < 0) - return -ENOMEM; - - return addr; -} - -static uint64 sys_kill() -{ - int pid; - if (argint(0, &pid) < 0) - return -EINVAL; - return ProcManager::kill(pid); -} - -static uint64 sys_sleep() -{ - int n; - uint64 ticks0; - - if (argint(0, &n) < 0) - return -EINVAL; - - Spinlock *lk = Timer::get_lock(); - lk->acquire(); - ticks0 = Timer::get_ticks(); - while (Timer::get_ticks() - ticks0 < (uint64)n) - { - if (myproc()->killed) - { - lk->release(); - return -EINTR; - } - ProcManager::sleep(Timer::get_tick_chan(), lk); - } - lk->release(); - return 0; -} - -static uint64 sys_disk_test() -{ - // VirtIO::test_rw(); - // VirtIO::test_bio(); - fat32_test(); - return 0; -} - -static uint64 sys_lseek() -{ - int fd, offset, whence; - if (argint(0, &fd) < 0 || argint(1, &offset) < 0 || argint(2, &whence) < 0) - return -EINVAL; - - struct Proc *p = myproc(); - if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) - return -EBADF; - - return FileTable::lseek(p->ofile[fd], offset, whence); -} - -static uint64 sys_reboot() -{ - SBI::sbi_shutdown(); - return 0; -} - -void syscall() -{ - Proc *p = myproc(); - int num = p->tf->a7; - uint64 ret = static_cast<uint64>(-ENOSYS); - - switch (num) - { - case SYS_mknodat: - ret = sys_mknodat(); - break; - case SYS_mkdirat: - ret = sys_mkdirat(); - break; - case SYS_unlinkat: - ret = sys_unlinkat(); - break; - case SYS_linkat: - ret = sys_linkat(); - break; - case SYS_chdir: - ret = sys_chdir(); - break; - case SYS_openat: - ret = sys_openat(); - break; - case SYS_dup: - ret = sys_dup(); - break; - case SYS_close: - ret = sys_close(); - break; - case SYS_pipe2: - ret = sys_pipe2(); - break; - case SYS_lseek: - ret = sys_lseek(); - break; - case SYS_read: - ret = sys_read(); - break; - case SYS_write: - ret = sys_write(); - break; - case SYS_fstat: - ret = sys_fstat(); - break; - case SYS_exit: - ret = sys_exit(); - break; - case SYS_exit_group: - ret = sys_exit(); - break; - case SYS_kill: - ret = sys_kill(); - break; - case SYS_getpid: - ret = sys_getpid(); - break; - case SYS_brk: - ret = sys_brk(); - break; - case SYS_clone: - ret = sys_clone(); - break; - case SYS_execve: - ret = sys_execve(); - if (ret == 0) - return; - break; - case SYS_wait4: - ret = sys_wait4(); - break; - - // Custom / Debug - case SYS_reboot: - ret = sys_reboot(); - break; - case SYS_putc: - ret = sys_putc(); - break; - case SYS_disk_test: - ret = sys_disk_test(); - break; - case SYS_nanosleep: - ret = sys_sleep(); - break; - - default: - Drivers::uart_puts("Unknown Syscall ID: "); - Drivers::print_hex(num); - Drivers::uart_puts("\n"); - ret = -ENOSYS; - break; - } - - p->tf->a0 = ret; -}
\ No newline at end of file diff --git a/src/kernel/timer.cc b/src/kernel/timer.cc deleted file mode 100644 index fc02f27..0000000 --- a/src/kernel/timer.cc +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "common/types.h" -#include "kernel/config.h" -#include "kernel/spinlock.h" -#include "kernel/proc.h" -#include "kernel/sbi.h" - -#define INTERVAL 1000000 - -namespace Timer -{ - uint64 ticks; - Spinlock tickslock; - - uint64 get_time() - { - uint64 time; - asm volatile("rdtime %0" : "=r"(time)); - return time; - } - - void set_next_trigger() - { - SBI::set_timer(get_time() + INTERVAL); - } - - void init() - { - set_next_trigger(); - - uint64 sie; - asm volatile("csrr %0, sie" : "=r"(sie)); - sie |= (1L << 5); - asm volatile("csrw sie, %0" : : "r"(sie)); - } - - void tick() - { - tickslock.acquire(); - ticks++; - ProcManager::wakeup(&ticks); - tickslock.release(); - set_next_trigger(); - } - - uint64 get_ticks() - { - tickslock.acquire(); - uint64 t = ticks; - tickslock.release(); - return t; - } - - Spinlock *get_lock() - { - return &tickslock; - } - - void *get_tick_chan() - { - return &ticks; - } -}
\ No newline at end of file diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc deleted file mode 100644 index b7bd5f0..0000000 --- a/src/kernel/trap/handler.cc +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "kernel/trap.h" -#include "kernel/riscv.h" -#include "kernel/proc.h" -#include "drivers/uart.h" -#include "kernel/syscall.h" -#include "kernel/mm.h" -#include "kernel/timer.h" -#include "drivers/plic.h" -#include "drivers/virtio.h" -#include "kernel/fdt.h" -#include "lib/string.h" - - -extern "C" void kernelvec(); - -// Handle Function - -void panic(const char *s) -{ - Drivers::uart_puts("\n\n!!! KERNEL PANIC !!!\n"); - Drivers::uart_puts(s); - Drivers::uart_puts("\nSystem Halted.\n"); - while (1) - ; -} - -// Trap Implementation - -namespace Trap -{ - void init() - { - Drivers::uart_puts("[Trap] Global init done.\n"); - } - - // Each CPU core needs to call this function when starting to set its own stvec - void inithart() - { - w_stvec((uint64)kernelvec); - - // Ensure that the S-Mode interrupt enable bit (SIE) is cleared during initialization - // Interrupt enabling will be done by the scheduler when the first process runs - w_sstatus(r_sstatus() & ~SSTATUS_SIE); - - // Enable the external interrupt, clock interrupt, and software interrupt bits in S-Mode (in SIE register) - uint64 sie = r_sie(); - sie |= SIE_SEIE | SIE_STIE | SIE_SSIE; - w_sie(sie); - - Drivers::uart_puts("[Trap] Hart initialized (stvec set).\n"); - } - - // Device Interrupt Check - int devintr() - { - uint64 scause = r_scause(); - - bool is_interrupt = (scause & 0x8000000000000000L) != 0; - uint64 code = scause & 0xff; - - if (is_interrupt && code == 9) - { - // Supervisor External Interrupt (IRQ 9) - int irq = PLIC::claim(); - - if (irq == (int)g_devices.uart.irq) - { - Drivers::uart_intr(); - } - else - { - // Check if it's a VirtIO IRQ - bool handled = false; - for (int i = 0; i < g_devices.virtio_count; i++) - { - if (irq == (int)g_devices.virtio[i].irq) - { - VirtIO::intr(); - handled = true; - break; - } - } - } - - if (irq > 0) - { - PLIC::complete(irq); - } - - return 1; - } - else if (is_interrupt && code == 5) - { - // Supervisor Timer Interrupt (IRQ 5) - // Timer::set_next_trigger(); - Timer::tick(); - // w_sip(r_sip() & ~2); - return 2; - } - - return 0; - } -} - -// Exception Handling Entry - -extern "C" void kerneltrap(struct Trapframe *tf) -{ - uint64 sepc = r_sepc(); - uint64 sstatus = r_sstatus(); - uint64 scause = r_scause(); - - if ((sstatus & SSTATUS_SPP) == 0) - panic("kerneltrap: not from supervisor mode"); - - if (intr_get() != 0) - panic("kerneltrap: interrupts enabled"); - - if (Trap::devintr() == 0) - { - Drivers::uart_puts("\n--- KERNEL EXCEPTION ---\n"); - Drivers::uart_puts("scause: "); - Drivers::print_hex(scause); - Drivers::uart_puts("\n"); - Drivers::uart_puts("sepc: "); - Drivers::print_hex(sepc); - Drivers::uart_puts("\n"); - Drivers::uart_puts("stval: "); - Drivers::print_hex(r_stval()); - Drivers::uart_puts("\n"); - panic("kerneltrap exception"); - } - - w_sepc(sepc); - w_sstatus(sstatus); -} - -extern "C" void usertrap() -{ - // Drivers::uart_puts("[Debug] Entered usertrap!\n"); - int which_dev = 0; - - if ((r_sstatus() & SSTATUS_SPP) != 0) - panic("usertrap: not from user mode"); - - w_stvec((uint64)kernelvec); - - struct Proc *p = myproc(); - if (!p) - panic("usertrap: no process"); - - p->tf->epc = r_sepc(); - - uint64 scause = r_scause(); - uint64 stval = r_stval(); - - if (scause == 8) // Syscall - { - if (p->state == ZOMBIE) - ProcManager::exit(-1); - p->tf->epc += 4; - intr_on(); - syscall(); - intr_off(); - } - else if (scause == 15) // Store Page Fault - { - if (VM::handle_cow_fault(p->pagetable, PGROUNDDOWN(stval)) != 0) - { - uint64 pa = VM::walkaddr(p->pagetable, stval); - - if (pa == 0) - { - Drivers::uart_puts("usertrap: Segmentation Fault (unmapped) at "); - } - else - { - Drivers::uart_puts("usertrap: Protection Fault (or OOM) at "); - } - - Drivers::print_hex(stval); - Drivers::uart_puts("\n"); - p->state = ZOMBIE; - ProcManager::exit(-1); - } - } - else if ((which_dev = Trap::devintr()) != 0) - { - if (which_dev == 2) - { - ProcManager::yield(); - } - } - else - { - Drivers::uart_puts("\nusertrap(): unexpected scause "); - Drivers::print_hex(scause); - Drivers::uart_puts(" pid="); - Drivers::uart_put_int(p->pid); - Drivers::uart_puts(" sepc="); - Drivers::print_hex(p->tf->epc); - Drivers::uart_puts(" stval="); - Drivers::print_hex(stval); - Drivers::uart_puts("\n"); - p->state = ZOMBIE; - ProcManager::exit(-1); - } - - if (p->state == ZOMBIE) - ProcManager::exit(-1); - - usertrapret(); -}
\ No newline at end of file diff --git a/src/kernel/trap/trampoline.S b/src/kernel/trap/trampoline.S deleted file mode 100644 index 57d6f25..0000000 --- a/src/kernel/trap/trampoline.S +++ /dev/null @@ -1,101 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.section .text -.globl trampoline -.globl uservec -.globl userret - -.align 12 -trampoline: -.align 4 -uservec: - - csrrw a0, sscratch, a0 - - sd ra, 40(a0) - sd sp, 48(a0) - sd gp, 56(a0) - sd tp, 64(a0) - sd t0, 72(a0) - sd t1, 80(a0) - sd t2, 88(a0) - sd s0, 96(a0) - sd s1, 104(a0) - sd a1, 120(a0) - sd a2, 128(a0) - sd a3, 136(a0) - sd a4, 144(a0) - sd a5, 152(a0) - sd a6, 160(a0) - sd a7, 168(a0) - sd s2, 176(a0) - sd s3, 184(a0) - sd s4, 192(a0) - sd s5, 200(a0) - sd s6, 208(a0) - sd s7, 216(a0) - sd s8, 224(a0) - sd s9, 232(a0) - sd s10, 240(a0) - sd s11, 248(a0) - sd t3, 256(a0) - sd t4, 264(a0) - sd t5, 272(a0) - sd t6, 280(a0) - - csrr t0, sscratch - sd t0, 112(a0) - - ld sp, 8(a0) - ld tp, 32(a0) - ld t0, 16(a0) - ld t1, 0(a0) - - csrw satp, t1 - sfence.vma zero, zero - - jr t0 - -.align 4 -userret: - - csrw satp, a1 - sfence.vma zero, zero - - csrw sscratch, a0 - - ld ra, 40(a0) - ld sp, 48(a0) - ld gp, 56(a0) - ld tp, 64(a0) - ld t0, 72(a0) - ld t1, 80(a0) - ld t2, 88(a0) - ld s0, 96(a0) - ld s1, 104(a0) - ld a1, 120(a0) - ld a2, 128(a0) - ld a3, 136(a0) - ld a4, 144(a0) - ld a5, 152(a0) - ld a6, 160(a0) - ld a7, 168(a0) - ld s2, 176(a0) - ld s3, 184(a0) - ld s4, 192(a0) - ld s5, 200(a0) - ld s6, 208(a0) - ld s7, 216(a0) - ld s8, 224(a0) - ld s9, 232(a0) - ld s10, 240(a0) - ld s11, 248(a0) - ld t3, 256(a0) - ld t4, 264(a0) - ld t5, 272(a0) - ld t6, 280(a0) - - ld a0, 112(a0) - - sret
\ No newline at end of file diff --git a/src/kernel/trap/trap.S b/src/kernel/trap/trap.S deleted file mode 100644 index 8bce53d..0000000 --- a/src/kernel/trap/trap.S +++ /dev/null @@ -1,90 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.section .text -.global kernelvec -.global uservec -.global userret -.align 12 - -kernelvec: - addi sp, sp, -288 - - sd ra, 40(sp) - sd sp, 48(sp) - sd gp, 56(sp) - sd tp, 64(sp) - sd t0, 72(sp) - sd t1, 80(sp) - sd t2, 88(sp) - sd s0, 96(sp) - sd s1, 104(sp) - sd a0, 112(sp) - sd a1, 120(sp) - sd a2, 128(sp) - sd a3, 136(sp) - sd a4, 144(sp) - sd a5, 152(sp) - sd a6, 160(sp) - sd a7, 168(sp) - sd s2, 176(sp) - sd s3, 184(sp) - sd s4, 192(sp) - sd s5, 200(sp) - sd s6, 208(sp) - sd s7, 216(sp) - sd s8, 224(sp) - sd s9, 232(sp) - sd s10, 240(sp) - sd s11, 248(sp) - sd t3, 256(sp) - sd t4, 264(sp) - sd t5, 272(sp) - sd t6, 280(sp) - - csrr t0, sepc - csrr t1, sstatus - sd t0, 24(sp) # Trapframe.epc - sd t1, 32(sp) # Trapframe.kernel_hartid - - mv a0, sp - call kerneltrap - - ld t0, 24(sp) - ld t1, 32(sp) - csrw sepc, t0 - csrw sstatus, t1 - - ld ra, 40(sp) - ld gp, 56(sp) - ld tp, 64(sp) - ld t0, 72(sp) - ld t1, 80(sp) - ld t2, 88(sp) - ld s0, 96(sp) - ld s1, 104(sp) - ld a0, 112(sp) - ld a1, 120(sp) - ld a2, 128(sp) - ld a3, 136(sp) - ld a4, 144(sp) - ld a5, 152(sp) - ld a6, 160(sp) - ld a7, 168(sp) - ld s2, 176(sp) - ld s3, 184(sp) - ld s4, 192(sp) - ld s5, 200(sp) - ld s6, 208(sp) - ld s7, 216(sp) - ld s8, 224(sp) - ld s9, 232(sp) - ld s10, 240(sp) - ld s11, 248(sp) - ld t3, 256(sp) - ld t4, 264(sp) - ld t5, 272(sp) - ld t6, 280(sp) - - addi sp, sp, 288 - sret
\ No newline at end of file |
