From e90b72ec3082588b296956730bd2930cf8d5d671 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Fri, 10 Jul 2026 11:31:46 +0800 Subject: 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. --- src/boot/entry.S | 47 -- src/drivers/plic.cc | 77 --- src/drivers/uart.cc | 204 -------- src/drivers/virtio_dist.cc | 382 --------------- src/fs/fat32.cc | 806 -------------------------------- src/fs/file.cc | 358 -------------- src/fs/fs.cc | 268 ----------- src/kernel/bio.cc | 139 ------ src/kernel/config.cc | 13 - src/kernel/cxx.cc | 78 ---- src/kernel/fdt.cc | 273 ----------- src/kernel/initcode.S | 11 - src/kernel/main.cc | 79 ---- src/kernel/mm/pmm.cc | 305 ------------ src/kernel/mm/slab.cc | 259 ----------- src/kernel/mm/vm.cc | 459 ------------------ src/kernel/proc/exec.cc | 260 ----------- src/kernel/proc/proc.cc | 654 -------------------------- src/kernel/proc/swtch.S | 37 -- src/kernel/sbi.cc | 52 --- src/kernel/spinlock.cc | 199 -------- src/kernel/syscall.cc | 698 ---------------------------- src/kernel/timer.cc | 66 --- src/kernel/trap/handler.cc | 217 --------- src/kernel/trap/trampoline.S | 101 ---- src/kernel/trap/trap.S | 90 ---- src/lib/string.cc | 88 ---- src/ulib/assert.c | 12 - src/ulib/cxx.cc | 35 -- src/ulib/iostream.cpp | 12 - src/ulib/stdio.c | 1056 ------------------------------------------ src/ulib/stdlib.c | 543 ---------------------- src/ulib/string.c | 335 -------------- src/ulib/syscalls.c | 153 ------ src/user/cat.cc | 52 --- src/user/cp.cc | 52 --- src/user/echo.cc | 26 -- src/user/entry.S | 12 - src/user/grep.cc | 72 --- src/user/init.cc | 64 --- src/user/kill.cc | 27 -- src/user/ln.cc | 22 - src/user/ls.cc | 116 ----- src/user/mkdir.cc | 25 - src/user/mv.cc | 30 -- src/user/rm.cc | 28 -- src/user/sh.cc | 423 ----------------- src/user/touch.cc | 31 -- src/user/user.ld | 36 -- src/user/usys.S | 38 -- src/user/wc.cc | 60 --- 51 files changed, 9480 deletions(-) delete mode 100644 src/boot/entry.S delete mode 100644 src/drivers/plic.cc delete mode 100644 src/drivers/uart.cc delete mode 100644 src/drivers/virtio_dist.cc delete mode 100644 src/fs/fat32.cc delete mode 100644 src/fs/file.cc delete mode 100644 src/fs/fs.cc delete mode 100644 src/kernel/bio.cc delete mode 100644 src/kernel/config.cc delete mode 100644 src/kernel/cxx.cc delete mode 100644 src/kernel/fdt.cc delete mode 100644 src/kernel/initcode.S delete mode 100644 src/kernel/main.cc delete mode 100644 src/kernel/mm/pmm.cc delete mode 100644 src/kernel/mm/slab.cc delete mode 100644 src/kernel/mm/vm.cc delete mode 100644 src/kernel/proc/exec.cc delete mode 100644 src/kernel/proc/proc.cc delete mode 100644 src/kernel/proc/swtch.S delete mode 100644 src/kernel/sbi.cc delete mode 100644 src/kernel/spinlock.cc delete mode 100644 src/kernel/syscall.cc delete mode 100644 src/kernel/timer.cc delete mode 100644 src/kernel/trap/handler.cc delete mode 100644 src/kernel/trap/trampoline.S delete mode 100644 src/kernel/trap/trap.S delete mode 100644 src/lib/string.cc delete mode 100644 src/ulib/assert.c delete mode 100644 src/ulib/cxx.cc delete mode 100644 src/ulib/iostream.cpp delete mode 100644 src/ulib/stdio.c delete mode 100644 src/ulib/stdlib.c delete mode 100644 src/ulib/string.c delete mode 100644 src/ulib/syscalls.c delete mode 100644 src/user/cat.cc delete mode 100644 src/user/cp.cc delete mode 100644 src/user/echo.cc delete mode 100644 src/user/entry.S delete mode 100644 src/user/grep.cc delete mode 100644 src/user/init.cc delete mode 100644 src/user/kill.cc delete mode 100644 src/user/ln.cc delete mode 100644 src/user/ls.cc delete mode 100644 src/user/mkdir.cc delete mode 100644 src/user/mv.cc delete mode 100644 src/user/rm.cc delete mode 100644 src/user/sh.cc delete mode 100644 src/user/touch.cc delete mode 100644 src/user/user.ld delete mode 100644 src/user/usys.S delete mode 100644 src/user/wc.cc (limited to 'src') diff --git a/src/boot/entry.S b/src/boot/entry.S deleted file mode 100644 index 8910ddc..0000000 --- a/src/boot/entry.S +++ /dev/null @@ -1,47 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.section .text.entry -.global _start - -_start: - mv tp, a0 - - la t0, stack_base - li t1, 4096 - addi t2, a0, 1 - mul t1, t1, t2 - add sp, t0, t1 - - bnez a0, .L_jump_main - - la t0, sbss - la t1, ebss -.L_clear_bss: - bge t0, t1, .L_save_dtb - sd zero, 0(t0) - addi t0, t0, 8 - j .L_clear_bss - -.L_save_dtb: - la t0, g_dtb_addr - sd a1, 0(t0) - -.L_jump_main: - call kernel_main - -.L_park: - wfi - j .L_park - -.section .bss -.align 4 -.global stack_top -stack_base: - .space 4096 * 8 -stack_top: - -.align 8 -.global g_dtb_addr -g_dtb_addr: - .space 8 \ No newline at end of file diff --git a/src/drivers/plic.cc b/src/drivers/plic.cc deleted file mode 100644 index a975c44..0000000 --- a/src/drivers/plic.cc +++ /dev/null @@ -1,77 +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/plic.h" -#include "drivers/uart.h" -#include "kernel/fdt.h" - -// Helper Macros — all relative to PLIC base from FDT -#define PLIC_BASE (g_devices.plic.base_addr) -#define PLIC_PRIORITY (PLIC_BASE + 0x0) -#define PLIC_PENDING (PLIC_BASE + 0x1000) - -#define PLIC_SENABLE_ADDR(hart) (PLIC_BASE + 0x2080 + (hart) * 0x100) -#define PLIC_STHRESHOLD_ADDR(hart) (PLIC_BASE + 0x201000 + (hart) * 0x2000) -#define PLIC_SCLAIM_ADDR(hart) (PLIC_BASE + 0x201004 + (hart) * 0x2000) - -// Helper for Volatile Access -static inline volatile uint32 *REG32(uint64 addr) -{ - return reinterpret_cast(addr); -} - -namespace PLIC -{ - void init() - { - // Set priority for UART IRQ - if (g_devices.uart.irq > 0) - *REG32(PLIC_PRIORITY + g_devices.uart.irq * 4) = 1; - - // Set priority for all VirtIO IRQs - for (int i = 0; i < g_devices.virtio_count; i++) - { - if (g_devices.virtio[i].irq > 0) - *REG32(PLIC_PRIORITY + g_devices.virtio[i].irq * 4) = 1; - } - } - - void inithart() - { - int hart = static_cast(r_tp()); - - // Build enable bitmask from discovered devices - uint32 enable = 0; - - if (g_devices.uart.irq > 0 && g_devices.uart.irq < 32) - enable |= (1 << g_devices.uart.irq); - - for (int i = 0; i < g_devices.virtio_count; i++) - { - if (g_devices.virtio[i].irq > 0 && g_devices.virtio[i].irq < 32) - enable |= (1 << g_devices.virtio[i].irq); - } - - *REG32(PLIC_SENABLE_ADDR(hart)) = enable; - - // Set Priority Threshold to 0 (Allow all) - *REG32(PLIC_STHRESHOLD_ADDR(hart)) = 0; - - Drivers::uart_puts("[PLIC] Hart Init Done.\n"); - } - - int claim() - { - int hart = static_cast(r_tp()); - return *REG32(PLIC_SCLAIM_ADDR(hart)); - } - - void complete(int irq) - { - int hart = static_cast(r_tp()); - *REG32(PLIC_SCLAIM_ADDR(hart)) = static_cast(irq); - } -} \ No newline at end of file diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc deleted file mode 100644 index 397a402..0000000 --- a/src/drivers/uart.cc +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "drivers/uart.h" -#include "kernel/riscv.h" -#include "kernel/spinlock.h" -#include "kernel/proc.h" -#include "kernel/mm.h" -#include "lib/string.h" - -namespace Drivers -{ - struct - { - Spinlock lock; - char buf[128]; // Line buffer - uint32 r; // Read pointer (position taken by the user) - uint32 w; // Write pointer (position confirmed by Enter) - uint32 e; // Editing cursor (current typing position) - } cons; - - // Circular buffer structure - struct - { - Spinlock lock; - char buf[UART_RX_BUF_SIZE]; - uint32 r; // read index - uint32 w; // write index - } uart_rx; - - Spinlock uart_tx_lock; - - void uart_init() - { - uart_rx.lock.init("uart_rx"); - cons.lock.init("console"); - uart_tx_lock.init("uart_tx"); - uart_rx.r = 0; - uart_rx.w = 0; - - // Disable interrupts and configure - *(volatile uint8 *)(uart_base() + IER) = 0x00; - - // Enter baud rate setting mode (LCR_DLAB) = 0x80; - *(volatile uint8 *)(uart_base() + LCR) = 0x80; - *(volatile uint8 *)(uart_base() + 0) = 0x03; // DLL: 38.4K baud - *(volatile uint8 *)(uart_base() + 1) = 0x00; // DLM - - // Exit baud rate setting, set 8-bit word length, no parity - *(volatile uint8 *)(uart_base() + LCR) = 0x03; - - // Reset and enable FIFO - *(volatile uint8 *)(uart_base() + FCR) = 0x07; - - // Enable Receive Data Available Interrupt - *(volatile uint8 *)(uart_base() + IER) = 0x01; - } - - void uart_putc(char c) - { - uart_tx_lock.acquire(); - while ((*(volatile uint8 *)(uart_base() + LSR) & LSR_TX_IDLE) == 0) - ; - *(volatile uint8 *)(uart_base() + THR) = c; - uart_tx_lock.release(); - } - - void uart_puts(const char *s) - { - while (*s) - uart_putc(*s++); - } - - void uart_put_int(int val) - { - char buf[16]; - int i = 0; - if (val == 0) - { - uart_puts("0"); - return; - } - if (val < 0) - { - uart_puts("-"); - val = -val; - } - while (val > 0) - { - buf[i++] = (val % 10) + '0'; - val /= 10; - } - while (i > 0) - { - uart_putc(buf[--i]); - } - } - - void print_hex(uint64 val) - { - char hex[] = "0123456789ABCDEF"; - uart_puts("0x"); - for (int i = 60; i >= 0; i -= 4) - { - uart_putc(hex[(val >> i) & 0xF]); - } - } - - void uart_intr() - { - uart_rx.lock.acquire(); - - while (1) - { - if ((*(volatile uint8 *)(uart_base() + LSR) & LSR_RX_READY) == 0) - break; - - char c = *(volatile uint8 *)(uart_base() + RHR); - - uart_rx.buf[uart_rx.w % UART_RX_BUF_SIZE] = c; - uart_rx.w++; - - ProcManager::wakeup(&uart_rx); - } - - uart_rx.lock.release(); - } - - // Modern console read: Line buffering + Editing Keys + Echo - int console_read(uint64 target, int len) - { - struct Proc *p = myproc(); - int target_idx = 0; - - cons.lock.acquire(); - - while (target_idx < len) - { - while (cons.r < cons.w) - { - char c = cons.buf[cons.r++ % sizeof(cons.buf)]; - cons.lock.release(); - - if (VM::copyout(p->pagetable, target + target_idx, &c, 1) < 0) - return -1; - - target_idx++; - if (c == '\n') - return target_idx; - if (target_idx == len) - return target_idx; - - cons.lock.acquire(); - } - - uart_rx.lock.acquire(); - while (uart_rx.r == uart_rx.w) - { - if (p->xstate) - { - uart_rx.lock.release(); - cons.lock.release(); - return -1; - } - cons.lock.release(); - ProcManager::sleep(&uart_rx, &uart_rx.lock); - cons.lock.acquire(); - } - - char c = uart_rx.buf[uart_rx.r++ % UART_RX_BUF_SIZE]; - uart_rx.lock.release(); - - if (c == 127 || c == '\b') - { - if (cons.e != cons.w) - { - cons.e--; - uart_putc('\b'); - uart_putc(' '); - uart_putc('\b'); - } - } - else - { - if (c == '\r') - c = '\n'; - - uart_putc(c); - - cons.buf[cons.e++ % sizeof(cons.buf)] = c; - - if (c == '\n' || cons.e == cons.w + sizeof(cons.buf)) - { - cons.w = cons.e; - ProcManager::wakeup(&cons); - } - } - } - - cons.lock.release(); - return target_idx; - } -} \ No newline at end of file diff --git a/src/drivers/virtio_dist.cc b/src/drivers/virtio_dist.cc deleted file mode 100644 index 8292874..0000000 --- a/src/drivers/virtio_dist.cc +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "drivers/virtio.h" -#include "kernel/fdt.h" -#include "kernel/riscv.h" -#include "kernel/pmm.h" -#include "kernel/spinlock.h" -#include "lib/string.h" -#include "drivers/uart.h" -#include "kernel/proc.h" -#include "kernel/buf.h" - -static uint64 virtio_base = 0x10001000; - -// VirtIO Block Device Config Structure -struct virtio_blk_config -{ - uint64 capacity; - uint32 size_max; - uint32 seg_max; - struct virtio_blk_geometry - { - uint16 cylinders; - uint8 heads; - uint8 sectors; - } geometry; - uint32 blk_size; - uint8 physical_block_exp; - uint8 alignment_offset; - uint16 min_io_size; - uint32 opt_io_size; -} __attribute__((packed)); - -static inline volatile uint32 *REG(uint32 offset) -{ - return reinterpret_cast(virtio_base + offset); -} - -namespace VirtIO -{ - struct Disk - { - struct VRingDesc *desc; - struct VRingAvail *avail; - struct VRingUsed *used; - - int free_head; - int num_free; - int free_chain[NUM_DESCS]; - - uint16 used_idx; - - struct TraceInfo - { - int busy; - int status; - } info[NUM_DESCS]; - - struct BlockRequest reqs[NUM_DESCS]; - uint8 req_status[NUM_DESCS]; - - Spinlock lock; - } disk; - - void init() - { - disk.lock.init("virtio_disk"); - - // 1. Probe VirtIO devices discovered by FDT - bool found = false; - for (int i = 0; i < g_devices.virtio_count; i++) - { - uint64 addr = g_devices.virtio[i].base_addr; - if (addr == 0) - continue; - - volatile uint32 *magic = (volatile uint32 *)(addr + VIRTIO_MMIO_MAGIC_VALUE); - volatile uint32 *dev_id = (volatile uint32 *)(addr + VIRTIO_MMIO_DEVICE_ID); - - if (*magic == 0x74726976 && *dev_id == 2) // ID 2 = Block Device - { - virtio_base = addr; - found = true; - Drivers::uart_puts(ANSI_GREEN "[VirtIO] Found Block Device @ "); - Drivers::print_hex(addr); - Drivers::uart_puts(ANSI_RESET "\n"); - break; - } - } - - if (!found) - { - Drivers::uart_puts(ANSI_RED "[VirtIO] Fatal - No Block Device found.\n" ANSI_RESET); - return; - } - - // 2. Check Device Version (We want Modern v2) - if (*REG(VIRTIO_MMIO_VERSION) != 2) - { - Drivers::uart_puts(ANSI_YELLOW "[VirtIO] Warning: Legacy device detected (expected v2).\n" ANSI_RESET); - } - - // 3. Reset Device - *REG(VIRTIO_MMIO_STATUS) = 0; - - // 4. Set ACKNOWLEDGE & DRIVER status - uint32 status = *REG(VIRTIO_MMIO_STATUS); - status |= VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; - *REG(VIRTIO_MMIO_STATUS) = status; - - // 5. Feature Negotiation - *REG(VIRTIO_MMIO_DEVICE_FEATURES_SEL) = 0; - uint32 device_features_lo = *REG(VIRTIO_MMIO_DEVICE_FEATURES); - (void)device_features_lo; - - *REG(VIRTIO_MMIO_DEVICE_FEATURES_SEL) = 1; - uint32 device_features_hi = *REG(VIRTIO_MMIO_DEVICE_FEATURES); - (void)device_features_hi; - - *REG(VIRTIO_MMIO_DRIVER_FEATURES_SEL) = 0; - *REG(VIRTIO_MMIO_DRIVER_FEATURES) = 0; - - *REG(VIRTIO_MMIO_DRIVER_FEATURES_SEL) = 1; - // VIRTIO_F_VERSION_1 is usually bit 32. - // If not defined in header, we hardcode logic here: (1ULL << 0) for high bits - *REG(VIRTIO_MMIO_DRIVER_FEATURES) = 1; - - status |= VIRTIO_CONFIG_S_FEATURES_OK; - *REG(VIRTIO_MMIO_STATUS) = status; - - if (!(*REG(VIRTIO_MMIO_STATUS) & VIRTIO_CONFIG_S_FEATURES_OK)) - { - Drivers::uart_puts("VirtIO: Feature negotiation failed.\n"); - return; - } - - // 6. Queue Configuration - *REG(VIRTIO_MMIO_QUEUE_SEL) = 0; - if (*REG(VIRTIO_MMIO_QUEUE_READY)) - { - Drivers::uart_puts("VirtIO: Queue 0 not ready.\n"); - } - - uint32 max_queue = *REG(VIRTIO_MMIO_QUEUE_NUM_MAX); - if (max_queue < NUM_DESCS) - { - Drivers::uart_puts("VirtIO: Queue size too small.\n"); - return; - } - - *REG(VIRTIO_MMIO_QUEUE_NUM) = NUM_DESCS; - - // Allocate Memory for VirtQueues - void *ptr = PMM::alloc_pages(1); // 4KB is enough for small rings - memset(ptr, 0, PGSIZE); - - uint64 base_addr = (uint64)ptr; - disk.desc = reinterpret_cast(base_addr); - disk.avail = reinterpret_cast(base_addr + NUM_DESCS * 16); - disk.used = reinterpret_cast(base_addr + PGSIZE / 2); - - *REG(VIRTIO_MMIO_QUEUE_DESC_LOW) = (uint32)base_addr; - *REG(VIRTIO_MMIO_QUEUE_DESC_HIGH) = (uint32)(base_addr >> 32); - - uint64 avail_addr = (uint64)disk.avail; - *REG(VIRTIO_MMIO_QUEUE_DRIVER_LOW) = (uint32)avail_addr; - *REG(VIRTIO_MMIO_QUEUE_DRIVER_HIGH) = (uint32)(avail_addr >> 32); - - uint64 used_addr = (uint64)disk.used; - *REG(VIRTIO_MMIO_QUEUE_DEVICE_LOW) = (uint32)used_addr; - *REG(VIRTIO_MMIO_QUEUE_DEVICE_HIGH) = (uint32)(used_addr >> 32); - - *REG(VIRTIO_MMIO_QUEUE_READY) = 1; - - // 7. Initialize Internal Structures - disk.free_head = 0; - disk.num_free = NUM_DESCS; - disk.used_idx = 0; - for (int i = 0; i < NUM_DESCS; i++) - { - disk.free_chain[i] = i + 1; - disk.info[i].busy = 0; - } - - // 8. Finalize Setup - status |= VIRTIO_CONFIG_S_DRIVER_OK; - *REG(VIRTIO_MMIO_STATUS) = status; - - // === [Feature] Read Capacity === - volatile struct virtio_blk_config *config = (volatile struct virtio_blk_config *)(virtio_base + VIRTIO_MMIO_CONFIG); - uint64 capacity_sectors = config->capacity; - uint64 size_mb = (capacity_sectors * 512) / (1024 * 1024); - - Drivers::uart_puts(ANSI_GREEN "[VirtIO] Initialized. Capacity: "); - Drivers::uart_put_int(size_mb); - Drivers::uart_puts(" MB\n" ANSI_RESET); - } - - static int alloc_desc() - { - if (disk.num_free == 0) - return -1; - int id = disk.free_head; - disk.free_head = disk.free_chain[id]; - disk.num_free--; - return id; - } - - static void free_desc(int id) - { - disk.free_chain[id] = disk.free_head; - disk.free_head = id; - disk.num_free++; - ProcManager::wakeup(&disk.free_head); - } - - static void free_chain_soft(int head_idx) - { - int curr = head_idx; - while (1) - { - int flag = disk.desc[curr].flags; - int next = disk.desc[curr].next; - free_desc(curr); - if (flag & VRING_DESC_F_NEXT) - curr = next; - else - break; - } - } - - void rw(int write, uint64 blockno, char *buf) - { - uint64 sector = blockno * (1024 / 512); // Assume 1KB blocks - - disk.lock.acquire(); - - // Wait for enough descriptors - while (disk.num_free < 3) - { - ProcManager::sleep(&disk.free_head, &disk.lock); - } - - int idx[3]; - idx[0] = alloc_desc(); - idx[1] = alloc_desc(); - idx[2] = alloc_desc(); - - // 1. Request Header - struct BlockRequest *req = &disk.reqs[idx[0]]; - req->type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN; - req->reserved = 0; - req->sector = sector; - - disk.desc[idx[0]].addr = (uint64)req; - disk.desc[idx[0]].len = sizeof(struct BlockRequest); - disk.desc[idx[0]].flags = VRING_DESC_F_NEXT; - disk.desc[idx[0]].next = idx[1]; - - // 2. Data Buffer - disk.desc[idx[1]].addr = (uint64)buf; - disk.desc[idx[1]].len = 1024; // Fixed 1KB for this test - disk.desc[idx[1]].flags = VRING_DESC_F_NEXT; - if (!write) - disk.desc[idx[1]].flags |= VRING_DESC_F_WRITE; - disk.desc[idx[1]].next = idx[2]; - - // 3. Status Byte - disk.desc[idx[2]].addr = (uint64)&disk.req_status[idx[0]]; - disk.desc[idx[2]].len = 1; - disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; - disk.desc[idx[2]].next = 0; - - disk.info[idx[0]].busy = 1; - - // Submit to Avail Ring - disk.avail->ring[disk.avail->idx % NUM_DESCS] = idx[0]; - __sync_synchronize(); - disk.avail->idx++; - __sync_synchronize(); - - // Notify Device - *REG(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; - - // Wait for Completion - while (disk.info[idx[0]].busy) - { - ProcManager::sleep(&disk.info[idx[0]], &disk.lock); - } - - free_chain_soft(idx[0]); - disk.lock.release(); - } - - void intr() - { - disk.lock.acquire(); - - uint32 status = *REG(VIRTIO_MMIO_INTERRUPT_STATUS); - *REG(VIRTIO_MMIO_INTERRUPT_ACK) = status & 0x3; - - volatile struct VRingUsed *used_ring = (volatile struct VRingUsed *)disk.used; - - while (disk.used_idx != used_ring->idx) - { - int id = used_ring->ring[disk.used_idx % NUM_DESCS].id; - - if (disk.info[id].busy) - { - disk.info[id].busy = 0; - ProcManager::wakeup(&disk.info[id]); - } - disk.used_idx++; - } - - disk.lock.release(); - } - - void test_rw() - { - Drivers::uart_puts(ANSI_BLUE "[VirtIO] Disk Test Start...\n" ANSI_RESET); - - char *buf = (char *)PMM::alloc_page(); - if (!buf) - return; - - const char *msg = "Lume OS Disk Driver Test Pattern"; - strcpy(buf, msg); - - rw(1, 0, buf); // Write - memset(buf, 0, PGSIZE); - rw(0, 0, buf); // Read - - if (strcmp(buf, msg) == 0) - { - Drivers::uart_puts(ANSI_GREEN "[VirtIO] Test PASSED (R/W Verified).\n" ANSI_RESET); - } - else - { - Drivers::uart_puts(ANSI_RED "[VirtIO] Test FAILED.\n" ANSI_RESET); - } - - PMM::free_page(buf); - } - - void test_bio() - { - Drivers::uart_puts(ANSI_BLUE "[Bio] Starting Buffer Cache Test...\n" ANSI_RESET); - - struct Buf *b = BufferCache::bread(0, 100); - - Drivers::uart_puts("[Bio] Bread block 100 (1st time).\n"); - - b->data[0] = 'L'; - b->data[1] = 'u'; - b->data[2] = 'm'; - b->data[3] = 'e'; - b->data[4] = '\0'; - - BufferCache::bwrite(b); - Drivers::uart_puts("[Bio] Bwrite block 100.\n"); - - BufferCache::brelse(b); - Drivers::uart_puts("[Bio] Brelease block 100.\n"); - - struct Buf *b2 = BufferCache::bread(0, 100); - Drivers::uart_puts("[Bio] Bread block 100 (2nd time).\n"); - - if (b2->data[0] == 'L' && b2->data[1] == 'u' && b2->data[3] == 'e') - { - Drivers::uart_puts(ANSI_GREEN "[Bio] Data verification PASSED.\n" ANSI_RESET); - } - else - { - Drivers::uart_puts(ANSI_RED "[Bio] Data verification FAILED.\n" ANSI_RESET); - } - - BufferCache::brelse(b2); - } -} \ No newline at end of file diff --git a/src/fs/fat32.cc b/src/fs/fat32.cc deleted file mode 100644 index e4089d4..0000000 --- a/src/fs/fat32.cc +++ /dev/null @@ -1,806 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "fs/fat32.h" -#include "lib/string.h" -#include "drivers/uart.h" -#include "kernel/mm.h" -#include "kernel/proc.h" - -FAT32FileSystem fat32_fs; - -// Helper function -static void generate_short_name(char *dst, const char *src) -{ - memset(dst, ' ', 11); - - int i = 0; - for (; *src && *src != '.' && i < 8; src++) - { - char c = *src; - if (c >= 'a' && c <= 'z') - c -= 32; - dst[i++] = c; - } - - while (*src && *src != '.') - src++; - if (*src == '.') - src++; - - i = 8; - for (; *src && i < 11; src++) - { - char c = *src; - if (c >= 'a' && c <= 'z') - c -= 32; - dst[i++] = c; - } -} - -// FAT32 FileSystem Implementation - -void FAT32FileSystem::init() -{ - struct Buf *b = BufferCache::bread(0, 0); - uint8 *data = (uint8 *)b->data; - struct FAT32_BPB *bpb = (struct FAT32_BPB *)data; - - uint32 partition_lba = 0; - - bool is_valid_bpb = (bpb->bytesPerSector == 512) && (bpb->rootClus != 0); - - if (!is_valid_bpb) - { - Drivers::uart_puts("[FAT32] Sector 0 is not a valid BPB. Checking MBR...\n"); - - if (data[510] != 0x55 || data[511] != 0xAA) - { - Drivers::uart_puts("[FAT32] Panic: Invalid Disk Signature!\n"); - while (1) - ; - } - - uint32 lba = *(uint32 *)(data + 446 + 8); - - if (lba > 0) - { - Drivers::uart_puts("[FAT32] MBR Partition 1 found @ Sector "); - Drivers::uart_put_int(lba); - Drivers::uart_puts("\n"); - partition_lba = lba; - } - else - { - Drivers::uart_puts("[FAT32] Panic: No partition found.\n"); - while (1) - ; - } - - BufferCache::brelse(b); - - b = BufferCache::bread(0, partition_lba / 2); - bpb = (struct FAT32_BPB *)b->data; - } - - if (bpb->bytesPerSector != 512) - { - Drivers::uart_puts("[FAT32] Panic: Invalid FAT32 BPB in partition.\n"); - while (1) - ; - } - - uint32 fat_sz = bpb->FATSz32; - this->fat_sz = fat_sz; - uint32 reserved_sec = bpb->reservedSecCnt; - uint8 num_fats = bpb->numFATs; - - sectors_per_cluster = bpb->secPerClus; - bytes_per_cluster = sectors_per_cluster * 512; - root_cluster = bpb->rootClus; - - fat_start_sector = partition_lba + reserved_sec; - data_start_sector = partition_lba + reserved_sec + (fat_sz * num_fats); - - Drivers::uart_puts(ANSI_GREEN); - Drivers::uart_puts("[FAT32] Init Success: RootClus="); - Drivers::uart_put_int(root_cluster); - Drivers::uart_puts(", DataStart="); - Drivers::uart_put_int(data_start_sector); - Drivers::uart_puts(ANSI_RESET); - Drivers::uart_puts("\n"); - - BufferCache::brelse(b); -} - -Inode *FAT32FileSystem::root() -{ - FAT32Inode *ip = new FAT32Inode(); - - ip->fs = this; - ip->dev = 0; - ip->inum = root_cluster; - ip->ref_cnt = 1; - ip->valid = 1; - ip->type = T_DIR; - ip->size = 0; - ip->nlink = 1; - - ip->first_clus = root_cluster; - ip->parent_clus = 0; - - return ip; -} - -uint32 FAT32FileSystem::cluster_to_sector(uint32 cluster) -{ - return data_start_sector + (cluster - 2) * sectors_per_cluster; -} - -uint32 FAT32FileSystem::next_cluster(uint32 cluster) -{ - uint32 fat_offset = cluster * 4; - uint32 fat_sector = fat_start_sector + (fat_offset / 512); - uint32 ent_offset = fat_offset % 512; - - // block = sector / 2 - struct Buf *b = BufferCache::bread(0, fat_sector / 2); - - uint32 block_offset = (fat_sector % 2) * 512 + ent_offset; - uint32 next = *(uint32 *)(b->data + block_offset); - - BufferCache::brelse(b); - - return next & 0x0FFFFFFF; -} - -// FAT32 Inode Implementation - -static bool match_name(const char *disk_name, const char *target) -{ - char temp[13]; - int i, j; - - for (i = 0; i < 8 && disk_name[i] != ' '; i++) - temp[i] = disk_name[i]; - if (disk_name[8] != ' ') - { - temp[i++] = '.'; - for (j = 0; j < 3 && disk_name[8 + j] != ' '; j++) - temp[i++] = disk_name[8 + j]; - } - temp[i] = 0; - return strcasecmp(temp, target) == 0; -} - -int FAT32Inode::read(char *dst, uint32 off, uint32 n, int isUser) -{ - if (first_clus == 0) - return 0; - - // [FIX] 只有非目录文件才检查 size 边界 - // 目录文件 size 可能为 0,应允许读取直到簇链结束 - if (type != T_DIR) - { - if (off >= size) - { - return 0; - } - if (off + n > size) - { - n = size - off; - } - } - - uint32 tot = 0; - uint32 clus = first_clus; - uint32 clus_sz = fs->bytes_per_cluster; - - uint32 skip = off / clus_sz; - uint32 current_off = off % clus_sz; - - while (skip > 0) - { - clus = fs->next_cluster(clus); - if (clus >= 0x0FFFFFF8) - return 0; - skip--; - } - - while (tot < n) - { - uint32 sec_in_clus = current_off / 512; - - if (sec_in_clus >= fs->sectors_per_cluster) - { - clus = fs->next_cluster(clus); - if (clus >= 0x0FFFFFF8) - break; - current_off = 0; - continue; - } - - uint32 sec = fs->cluster_to_sector(clus) + sec_in_clus; - uint32 off_in_sec = current_off % 512; - - uint32 m = 512 - off_in_sec; - if (n - tot < m) - m = n - tot; - - struct Buf *b = BufferCache::bread(dev, sec / 2); - uint32 block_offset = (sec % 2) * 512 + off_in_sec; - - if (isUser) - { - if (VM::copyout(myproc()->pagetable, (uint64)dst, (char *)(b->data + block_offset), m) < 0) - { - BufferCache::brelse(b); - return -1; - } - } - else - { - memmove(dst, b->data + block_offset, m); - } - BufferCache::brelse(b); - - tot += m; - dst += m; - current_off += m; - } - return tot; -} - -Inode *FAT32Inode::lookup(const char *name) -{ - if (type != T_DIR) - return nullptr; - - uint32 clus = first_clus; - struct FAT32_DirEnt de; - - while (clus < 0x0FFFFFF8) - { - uint32 sec = fs->cluster_to_sector(clus); - - for (uint32 i = 0; i < fs->sectors_per_cluster; i++) - { - uint32 current_sec = sec + i; - struct Buf *b = BufferCache::bread(dev, current_sec / 2); - uint32 block_base = (current_sec % 2) * 512; - - for (int off = 0; off < 512; off += 32) - { - memmove(&de, b->data + block_base + off, 32); - - if (de.name[0] == 0x00) - { - BufferCache::brelse(b); - return nullptr; - } - if (de.name[0] == 0xE5) - continue; - if (de.attr & ATTR_LONG_NAME) - continue; - - if (match_name(de.name, name)) - { - FAT32Inode *ip = new FAT32Inode(); - ip->fs = fs; - ip->dev = dev; - ip->type = (de.attr & ATTR_DIRECTORY) ? T_DIR : T_FILE; - ip->size = de.fileSize; - ip->first_clus = (de.fstClusHI << 16) | de.fstClusLO; - ip->inum = ip->first_clus; - ip->nlink = 1; - ip->ref_cnt = 1; - ip->valid = 1; - ip->ent_sec = current_sec; // Log Sector - ip->ent_off = off; // Log Setoff - - BufferCache::brelse(b); - return ip; - } - } - BufferCache::brelse(b); - } - clus = fs->next_cluster(clus); - } - return nullptr; -} - -// Placeholder -uint32 FAT32FileSystem::alloc_cluster() -{ - uint32 fat_entries_per_sector = 512 / 4; - for (uint32 i = 0; i < fat_sz; i++) - { - uint32 current_fat_sec = fat_start_sector + i; - struct Buf *b = BufferCache::bread(0, current_fat_sec / 2); - uint32 *table = (uint32 *)(b->data + (current_fat_sec % 2) * 512); - for (uint32 j = 0; j < fat_entries_per_sector; j++) - { - if (i == 0 && j < 2) - continue; - - if ((table[j] & 0x0FFFFFFF) == 0) - { - // Find the free cluster and mark it as EOF (0x0FFFFFFF) - table[j] = 0x0FFFFFFF; - BufferCache::bwrite(b); // Write back to disk - BufferCache::brelse(b); - - uint32 cluster_idx = i * fat_entries_per_sector + j; - - // Clear the data content of the new cluster - uint32 data_sec = cluster_to_sector(cluster_idx); - for (uint32 k = 0; k < sectors_per_cluster; k++) - { - struct Buf *db = BufferCache::bread(0, (data_sec + k) / 2); - memset(db->data + ((data_sec + k) % 2) * 512, 0, 512); - BufferCache::bwrite(db); - BufferCache::brelse(db); - } - - return cluster_idx; - } - } - BufferCache::brelse(b); - } - Drivers::uart_puts("[FAT32] Out of space!\n"); - return 0; -} - -void FAT32FileSystem::free_cluster_chain(uint32 cluster) -{ - while (cluster >= 2 && cluster < 0x0FFFFFF8) - { - uint32 next = next_cluster(cluster); - - // Calculate the current cluster's position in the FAT table - uint32 fat_offset = cluster * 4; - uint32 fat_sector = fat_start_sector + (fat_offset / 512); - uint32 ent_offset = fat_offset % 512; - - // Read FAT sector - struct Buf *b = BufferCache::bread(0, fat_sector / 2); - - // Marked as idle (0x00000000) - uint32 *entry = (uint32 *)(b->data + (fat_sector % 2) * 512 + ent_offset); - *entry = 0; - - BufferCache::bwrite(b); - BufferCache::brelse(b); - - cluster = next; - } -} - -void FAT32Inode::update() -{ - struct Buf *b = BufferCache::bread(dev, ent_sec / 2); - uint32 offset = (ent_sec % 2) * 512 + ent_off; - - struct FAT32_DirEnt *de = (struct FAT32_DirEnt *)(b->data + offset); - - // Update file size and starting cluster - de->fileSize = size; - de->fstClusHI = (uint16)((first_clus >> 16) & 0xFFFF); - de->fstClusLO = (uint16)(first_clus & 0xFFFF); - - BufferCache::bwrite(b); - BufferCache::brelse(b); -} - -int FAT32Inode::write(const char *src, uint32 off, uint32 n, int isUser) -{ - if (off > size) - { - return -1; - } - - uint32 tot = 0; - uint32 clus = first_clus; - uint32 clus_sz = fs->bytes_per_cluster; - uint32 prev_clus = 0; - - if (clus == 0) - { - clus = fs->alloc_cluster(); - if (clus == 0) - return -1; - first_clus = clus; - // Update the metadata immediately to prevent data loss in case of a power outage. - update(); - } - - uint32 skip = off / clus_sz; - uint32 current_off = off % clus_sz; - - while (skip > 0) - { - prev_clus = clus; - clus = fs->next_cluster(clus); - if (clus >= 0x0FFFFFF8) - { - return -1; - } - skip--; - } - while (tot < n) - { - if (current_off == clus_sz) - { - uint32 next = fs->next_cluster(clus); - if (next >= 0x0FFFFFF8) - { - uint32 new_clus = fs->alloc_cluster(); - if (new_clus == 0) - break; - - // Point the current cluster to the new cluster (update the FAT table) - uint32 fat_offset = clus * 4; - uint32 fat_sec = fs->fat_start_sector + (fat_offset / 512); - struct Buf *fat_b = BufferCache::bread(dev, fat_sec / 2); - uint32 *entry = (uint32 *)(fat_b->data + (fat_sec % 2) * 512 + (fat_offset % 512)); - *entry = new_clus; // Link - BufferCache::bwrite(fat_b); - BufferCache::brelse(fat_b); - - clus = new_clus; - } - else - { - clus = next; - } - current_off = 0; - } - - // Calculate the physical sector to write - uint32 sec_in_clus = current_off / 512; - uint32 sec = fs->cluster_to_sector(clus) + sec_in_clus; - uint32 off_in_sec = current_off % 512; - - // Calculate how many bytes can be written this time - uint32 m = 512 - off_in_sec; - if (n - tot < m) - m = n - tot; - - struct Buf *b = BufferCache::bread(dev, sec / 2); - uint32 block_offset = (sec % 2) * 512 + off_in_sec; - - if (isUser) - { - if (VM::copyin(myproc()->pagetable, (char *)(b->data + block_offset), (uint64)src, m) < 0) - { - BufferCache::brelse(b); - return -1; - } - } - else - { - memmove(b->data + block_offset, src, m); - } - - BufferCache::bwrite(b); - BufferCache::brelse(b); - - tot += m; - src += m; - current_off += m; - } - if (off + n > size) - { - size = off + n; - update(); - } - - return tot; -} - -Inode *FAT32Inode::create(const char *name, short type, short major, short minor) -{ - Inode *exist = lookup(name); - if (exist) - { - return exist; - } - - struct FAT32_DirEnt de; - memset(&de, 0, sizeof(de)); - generate_short_name(de.name, name); - de.attr = (type == T_DIR) ? ATTR_DIRECTORY : ATTR_ARCHIVE; - - uint32 new_dir_clus = 0; - if (type == T_DIR) - { - new_dir_clus = fs->alloc_cluster(); - if (new_dir_clus == 0) - return nullptr; - - de.fstClusHI = (uint16)((new_dir_clus >> 16) & 0xFFFF); - de.fstClusLO = (uint16)(new_dir_clus & 0xFFFF); - } - else - { - de.fileSize = 0; - } - - uint32 clus = first_clus; - bool written = false; - - while (true) - { - uint32 sec = fs->cluster_to_sector(clus); - - for (uint32 i = 0; i < fs->sectors_per_cluster; i++) - { - struct Buf *b = BufferCache::bread(dev, (sec + i) / 2); - uint8 *data = (uint8 *)b->data + ((sec + i) % 2) * 512; - - for (int off = 0; off < 512; off += 32) - { - if (data[off] == 0x00 || data[off] == 0xE5) - { - memmove(data + off, &de, 32); - BufferCache::bwrite(b); - BufferCache::brelse(b); - written = true; - break; - } - } - - if (written) - break; - BufferCache::brelse(b); - } - - if (written) - break; - - uint32 next = fs->next_cluster(clus); - if (next >= 0x0FFFFFF8) - { - uint32 new_parent_clus = fs->alloc_cluster(); - if (new_parent_clus == 0) - return nullptr; - - uint32 fat_off = clus * 4; - uint32 fat_sec = fs->fat_start_sector + (fat_off / 512); - struct Buf *fb = BufferCache::bread(dev, fat_sec / 2); - *(uint32 *)(fb->data + (fat_sec % 2) * 512 + (fat_off % 512)) = new_parent_clus; - BufferCache::bwrite(fb); - BufferCache::brelse(fb); - - uint32 s = fs->cluster_to_sector(new_parent_clus); - for (uint32 k = 0; k < fs->sectors_per_cluster; k++) - { - struct Buf *zb = BufferCache::bread(dev, (s + k) / 2); - uint8 *zdata = (uint8 *)zb->data + ((s + k) % 2) * 512; - memset(zdata, 0, 512); - - if (k == 0) - { - memmove(zdata, &de, 32); - } - - BufferCache::bwrite(zb); - BufferCache::brelse(zb); - } - - written = true; - break; - } - clus = next; - } - - if (written && type == T_DIR) - { - struct FAT32_DirEnt dot; - memset(&dot, 0, 32); - memset(dot.name, ' ', 11); - dot.name[0] = '.'; - dot.attr = ATTR_DIRECTORY; - dot.fstClusHI = (uint16)((new_dir_clus >> 16) & 0xFFFF); - dot.fstClusLO = (uint16)(new_dir_clus & 0xFFFF); - - struct FAT32_DirEnt dotdot; - memset(&dotdot, 0, 32); - memset(dotdot.name, ' ', 11); - dotdot.name[0] = '.'; - dotdot.name[1] = '.'; - dotdot.attr = ATTR_DIRECTORY; - - uint32 parent_clus_num = this->first_clus; - if (parent_clus_num == fs->root_cluster) - { - parent_clus_num = 0; - } - dotdot.fstClusHI = (uint16)((parent_clus_num >> 16) & 0xFFFF); - dotdot.fstClusLO = (uint16)(parent_clus_num & 0xFFFF); - - uint32 s = fs->cluster_to_sector(new_dir_clus); - - struct Buf *zb = BufferCache::bread(dev, s / 2); - uint8 *zdata = (uint8 *)zb->data + (s % 2) * 512; - - memmove(zdata, &dot, 32); // Offset 0 - memmove(zdata + 32, &dotdot, 32); // Offset 32 - - BufferCache::bwrite(zb); - BufferCache::brelse(zb); - } - - if (written) - { - return lookup(name); - } - - return nullptr; -} - -void FAT32Inode::truncate() -{ - if (first_clus == 0) - { - if (size != 0) - { - size = 0; - update(); - } - return; - } - - fs->free_cluster_chain(first_clus); - - size = 0; - first_clus = 0; - - update(); -} - -int FAT32Inode::unlink(const char *name) -{ - if (type != T_DIR) - return -1; - if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) - return -1; - - uint32_t clus = first_clus; - bool found = false; - - // [FIX] Deadlock prevention: Do not hold buffer while looking up inode - uint32_t target_block = 0; - uint32_t target_offset = 0; - struct FAT32_DirEnt de; - - while (true) - { - uint32_t sec = fs->cluster_to_sector(clus); - for (uint32 i = 0; i < fs->sectors_per_cluster; ++i) - { - struct Buf *b = BufferCache::bread(dev, (sec + i) / 2); - uint8_t *data = (uint8_t *)b->data + ((sec + i) % 2) * 512; - - for (int off = 0; off < 512; off += 32) - { - memmove(&de, data + off, 32); - if (de.name[0] == 0x00) // end of dir - { - BufferCache::brelse(b); - return -1; // Not found - } - if (de.name[0] == 0xE5) - continue; // have been unlink - if (de.attr & ATTR_LONG_NAME) - continue; - - if (match_name(de.name, name)) - { - target_block = (sec + i) / 2; - target_offset = ((sec + i) % 2) * 512 + off; - found = true; - break; - } - } - - BufferCache::brelse(b); // Always release buffer - if (found) - break; - } - - if (found) - break; - - clus = fs->next_cluster(clus); - if (clus >= 0x0FFFFFF8) - return -1; - } - - if (found) - { - Inode *target_ip = lookup(name); - if (target_ip) - { - VFS::ilock(target_ip); - if (target_ip->type == T_DIR) - { - VFS::iunlockput(target_ip); - return -1; - } - - target_ip->nlink--; - target_ip->update(); - VFS::iunlockput(target_ip); - } - - // Re-read buffer to mark deletion - struct Buf *target_buf = BufferCache::bread(dev, target_block); - uint8_t *ptr = (uint8_t *)target_buf->data + target_offset; - *ptr = 0xE5; - - BufferCache::bwrite(target_buf); - BufferCache::brelse(target_buf); - return 0; - } - - return -1; -} - -// Test Function -void fat32_test() -{ - static bool inited = false; - if (!inited) - { - fat32_fs.init(); - inited = true; - } - - Drivers::uart_puts("\n[FAT32] Starting Test via Syscall...\n"); - - Inode *root = fat32_fs.root(); - if (root) - { - Drivers::uart_puts("[FAT32] Root Inode retrieved. Inum: "); - Drivers::uart_put_int(root->inum); - Drivers::uart_puts("\n"); - - Drivers::uart_puts("[FAT32] Looking for TEST.TXT...\n"); - Inode *node = root->lookup("test.txt"); - - if (node) - { - Drivers::uart_puts("[FAT32] Found TEST.TXT! Size: "); - Drivers::uart_put_int(node->size); - Drivers::uart_puts("\n"); - - char buf[128]; - int n = node->read(buf, 0, 127, 0); - if (n > 0) - { - buf[n] = 0; - Drivers::uart_puts("[FAT32] Content:\n>> "); - Drivers::uart_puts(buf); - Drivers::uart_puts("\n"); - } - else - { - Drivers::uart_puts("[FAT32] Read returned 0.\n"); - } - VFS::iput(node); - } - else - { - Drivers::uart_puts("[FAT32] TEST.TXT not found.\n"); - } - VFS::iput(root); - } - else - { - Drivers::uart_puts("[FAT32] Failed to get root inode.\n"); - } - - Drivers::uart_puts("[FAT32] Test Finished.\n"); -} \ No newline at end of file diff --git a/src/fs/file.cc b/src/fs/file.cc deleted file mode 100644 index d814332..0000000 --- a/src/fs/file.cc +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "fs/file.h" -#include "kernel/spinlock.h" -#include "kernel/mm.h" -#include "drivers/uart.h" -#include "kernel/proc.h" -#include "kernel/slab.h" - -#define NFILE 100 -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -extern void *operator new(unsigned long, void *p); - -int Pipe::create_pair(file** f0, file** f1) -{ - void *mem = Slab::kmalloc(sizeof(Pipe)); - if (!mem) - return -1; - Pipe *pi = new (mem) Pipe(); - - *f0 = FileTable::alloc(); - *f1 = FileTable::alloc(); - - if (*f0 == nullptr || *f1 == nullptr) - { - if (*f0) - FileTable::close(*f0); - if (*f1) - FileTable::close(*f1); - pi->~Pipe(); - Slab::kfree(pi); - return -1; - } - - (*f0)->type = FD_PIPE; - (*f0)->readable = 1; - (*f0)->writable = 0; - (*f0)->pipe = pi; - - (*f1)->type = FD_PIPE; - (*f1)->readable = 0; - (*f1)->writable = 1; - (*f1)->pipe = pi; - - return 0; -} - -void Pipe::close(bool is_writer) -{ - lock.acquire(); - if (is_writer) - { - write_open = false; - ProcManager::wakeup(&nread); // Wake up the process that is currently reading - } - else - { - read_open = false; - ProcManager::wakeup(&nwrite); // Wake up the process that is writing - } - - bool empty = !read_open && !write_open; - lock.release(); - - if (empty) - { - this->~Pipe(); - Slab::kfree(this); - } -} - -int Pipe::write(uint64_t addr, int n) -{ - int i = 0; - struct Proc *p = myproc(); - - lock.acquire(); - while (i < n) - { - if (!read_open || p->xstate) // The read end is closed or the process is abnormal - { - lock.release(); - return -1; - } - - if (nwrite == nread + SIZE) // buffer is full - { - ProcManager::wakeup(&nread); - ProcManager::sleep(&nwrite, &lock); - } - else - { - char ch; - if (VM::copyin(p->pagetable, &ch, addr + i, 1) < 0) - break; - data[nwrite++ % SIZE] = ch; - i++; - } - } - ProcManager::wakeup(&nread); - lock.release(); - return i; -} - -int Pipe::read(uint64_t addr, int n) -{ - int i = 0; - struct Proc *p = myproc(); - - lock.acquire(); - while (nread == nwrite && write_open) // The buffer is empty and the write end is not closed - { - if (p->xstate) - { - lock.release(); - return -1; - } - ProcManager::sleep(&nread, &lock); - } - - for (i = 0; i < n; ++i) - { - if (nread == nwrite) - break; - char ch = data[nread++ % SIZE]; - if (VM::copyout(p->pagetable, addr + i, &ch, 1) < 0) - break; - } - ProcManager::wakeup(&nwrite); - lock.release(); - return i; -} - -namespace FileTable -{ - struct - { - Spinlock lock; - struct file files[NFILE]; - } ftable; - - void init() - { - ftable.lock.init("file_table"); - } - - struct file *alloc() - { - struct file *f; - ftable.lock.acquire(); - for (f = ftable.files; f < ftable.files + NFILE; f++) - { - if (f->ref == 0) - { - f->ref = 1; - ftable.lock.release(); - return f; - } - } - ftable.lock.release(); - return nullptr; - } - - struct file *dup(struct file *f) - { - ftable.lock.acquire(); - if (f->ref < 1) - { - Drivers::uart_puts("panic: file dup\n"); - while (1) - ; - } - f->ref++; - ftable.lock.release(); - return f; - } - - void close(struct file *f) - { - struct file ff; - - ftable.lock.acquire(); - if(f->ref < 1) - { - Drivers::uart_puts("panic: file close\n"); - while (1) - ; - } - f->ref--; - if (f->ref > 0) - { - ftable.lock.release(); - return; - } - - ff = *f; - f->ref = 0; - f->type = FD_NONE; - ftable.lock.release(); - if (ff.type == FD_INODE) - { - // Release the corresponding Inode - VFS::iput(ff.ip); - } - else if (ff.type == FD_PIPE) - { - if (ff.pipe) - ff.pipe->close(ff.writable); - } - } - - int read(struct file *f, uint64 addr, int n) - { - if (f->readable == 0) - return -1; - if (f->type == FD_INODE) - { - VFS::ilock(f->ip); - - if (f->ip->type == T_DEVICE) - { - if (f->ip->major == 1) - { - VFS::iunlock(f->ip); - return Drivers::console_read(addr, n); - } - } - - int r = f->ip->read((char*)addr, f->off, n, 1); - if(r > 0) - { - f->off += r; - } - VFS::iunlock(f->ip); - return r; - } - else if (f->type == FD_PIPE) - { - if (f->pipe) - return f->pipe->read(addr, n); - } - return -1; - } - - int write(struct file *f, uint64 addr, int n) - { - if (f->writable == 0) - return -1; - if (f->type == FD_INODE) - { - VFS::ilock(f->ip); - - if (f->ip->type == T_DEVICE) - { - if (f->ip->major == 1) // Console - { - VFS::iunlock(f->ip); - struct Proc *proc = myproc(); - 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, addr + i, static_cast(len)) < 0) - { - return -1; - } - - for (int j = 0; j < len; j++) - { - Drivers::uart_putc(buf[j]); - } - i += len; - } - return n; - } - } - - int r = f->ip->write((char *)addr, f->off, n, 1); - if (r > 0) - { - f->off += r; - } - VFS::iunlock(f->ip); - return r; - } - else if (f->type == FD_PIPE) - { - if (f->pipe) - return f->pipe->write(addr, n); - } - - return -1; - } - - int stat(struct file *f, uint64 addr) - { - if (f->type == FD_INODE) - { - struct kstat st; - VFS::ilock(f->ip); - f->ip->getattr(&st); - VFS::iunlock(f->ip); - - struct Proc *p = myproc(); - if (VM::copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0) - return -1; - return 0; - } - return -1; - } - - int lseek(struct file *f, int offset, int whence) - { - if (f->type != FD_INODE) - return -1; - - VFS::ilock(f->ip); - - int new_off = f->off; - int size = f->ip->size; - - switch (whence) - { - case SEEK_SET: - new_off = offset; - break; - case SEEK_CUR: - new_off += offset; - break; - case SEEK_END: - new_off = size + offset; - break; - default: - VFS::iunlock(f->ip); - return -1; - } - - if (new_off < 0) - { - VFS::iunlock(f->ip); - return -1; - } - - f->off = new_off; - VFS::iunlock(f->ip); - return new_off; - } -} // namespace FileTable diff --git a/src/fs/fs.cc b/src/fs/fs.cc deleted file mode 100644 index fc8f555..0000000 --- a/src/fs/fs.cc +++ /dev/null @@ -1,268 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "fs/fs.h" -#include "kernel/riscv.h" -#include "drivers/uart.h" -#include "kernel/spinlock.h" -#include "kernel/proc.h" -// #include "fs/fat32.h" // Decoupled -#include "lib/string.h" - -static Inode *global_root_inode = nullptr; - -static const char *skipelem(const char *path, char *name) -{ - const char *s; - int len; - - while (*path == '/') - path++; - if (*path == 0) - return nullptr; - - s = path; - while (*path != '/' && *path != 0) - path++; - - len = path - s; - if (len >= 128) - len = 127; - - memmove(name, s, len); - name[len] = 0; - - while (*path == '/') - path++; - return path; -} - -void Inode::getattr(struct kstat *st) -{ - st->dev = dev; - st->ino = inum; - st->type = type; - st->nlink = nlink; - st->size = size; - - st->uid = 0; - st->gid = 0; - st->mode = 0; -} - -namespace VFS -{ - // File System Registry - static FileSystem *filesystems[8]; - static int fs_count = 0; - - void register_fs(FileSystem *fs) - { - if (fs_count < 8) - { - filesystems[fs_count++] = fs; - } - } - - void init() - { - Drivers::uart_puts("[VFS] Inode subsystem initialized.\n"); - } - - void iput(Inode *ip) - { - if (ip == nullptr) - return; - - ip->lock.acquire(); - if(ip->ref_cnt < 1) - { - Drivers::uart_puts("panic: iput ref\n"); - while (1) - ; - } - ip->ref_cnt--; - int ref = ip->ref_cnt; - ip->lock.release(); - - if (ref == 0) - { - delete ip; - } - } - - Inode* idup(Inode *ip) - { - if (ip == nullptr) - return nullptr; - - ip->lock.acquire(); - ip->ref_cnt++; - ip->lock.release(); - return ip; - } - - void ilock(Inode *ip) - { - if (ip == 0 || ip->ref_cnt < 1) - { - Drivers::uart_puts("panic: ilock\n"); - while (1) - ; - } - - ip->lock.acquire(); - - } - - void iunlock(Inode *ip) - { - if (ip == 0 || !ip->lock.holding() || ip->ref_cnt < 1) - { - Drivers::uart_puts("panic: iunlock\n"); - while (1) - ; - } - ip->lock.release(); - } - - void iunlockput(Inode *ip) - { - if (!ip) - return; - iunlock(ip); - iput(ip); - } - - void mount_root(Inode *root) - { - if (global_root_inode) - { - Drivers::uart_puts("VFS: Root already mounted!\n"); - return; - } - global_root_inode = root; - Drivers::uart_puts("[VFS] Root filesystem mounted.\n"); - } - - Inode *get_root() - { - if (global_root_inode == nullptr) - { - // Try to mount the first registered FS - if (fs_count > 0) - { - Drivers::uart_puts("[VFS] Lazy init: Mounting root FS...\n"); - filesystems[0]->init(); - mount_root(filesystems[0]->root()); - } - else - { - Drivers::uart_puts("[VFS] No filesystem registered!\n"); - } - } - if (!global_root_inode) - return nullptr; - return idup(global_root_inode); - } - - Inode *namei(const char *path) - { - char name[128]; - Inode *ip, *next; - struct Proc *p = myproc(); - - // 1. 确定起点 - if (*path == '/') - { - ip = get_root(); - } - else - { - if (p->cwd == nullptr) - { - ip = get_root(); - } - else - { - ip = idup(p->cwd); - } - } - - if (ip == nullptr) - return nullptr; - - while ((path = skipelem(path, name)) != nullptr) - { - if (strcmp(name, ".") == 0) - { - continue; - } - - if (strcmp(name, "..") == 0) - { - Inode *root = get_root(); - bool is_root = (ip->inum == root->inum); - iput(root); - - if (is_root) - { - continue; - } - } - - ilock(ip); - - if (ip->type != T_DIR) - { - iunlockput(ip); - return nullptr; - } - - next = ip->lookup(name); - iunlockput(ip); - - ip = next; - if (ip == nullptr) - return nullptr; - } - - return ip; - } - - Inode *nameiparent(const char* path, char* name) - { - Inode* ip; - Inode* next; - - if (*path == '/') - ip = get_root(); - else - ip = idup(myproc()->cwd ? myproc()->cwd : get_root()); - - while ((path = skipelem(path, name)) != nullptr) - { - if (*path == 0) - { - return ip; - } - - ilock(ip); - if (ip->type != T_DIR) - { - iunlockput(ip); - return nullptr; - } - - next = ip->lookup(name); - iunlockput(ip); - - ip = next; - if (!ip) - return nullptr; - } - iput(ip); - return nullptr; - } -} // namespace VFS 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<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(-1); - } -} - -static int argint(int n, int *ip) -{ - *ip = static_cast(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(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(-1)) - return -EINVAL; - - return static_cast(ProcManager::wait(status_addr)); -} - -static uint64 sys_getpid() -{ - return static_cast(myproc()->pid); -} - -static uint64 sys_putc() -{ - char c = static_cast(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(len)) < 0) - return -EFAULT; - - for (int j = 0; j < len; j++) - { - Drivers::uart_putc(buf[j]); - } - i += len; - } - return static_cast(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(-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 diff --git a/src/lib/string.cc b/src/lib/string.cc deleted file mode 100644 index e8eccb3..0000000 --- a/src/lib/string.cc +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "lib/string.h" - -void *memset(void *dst, int c, uint n) -{ - char *cdst = (char *)dst; - for (uint i = 0; i < n; i++) - cdst[i] = c; - return dst; -} - -int memcmp(const void *v1, const void *v2, uint n) -{ - const uchar *s1 = (const uchar *)v1; - const uchar *s2 = (const uchar *)v2; - while (n-- > 0) - { - if (*s1 != *s2) - return *s1 - *s2; - s1++, s2++; - } - return 0; -} - -void *memmove(void *dst, const void *src, uint n) -{ - const char *s = (const char *)src; - char *d = (char *)dst; - if (s < d && s + n > d) - { - s += n; - d += n; - while (n-- > 0) - *--d = *--s; - } - else - { - while (n-- > 0) - *d++ = *s++; - } - return dst; -} - -void *memcpy(void *dst, const void *src, uint n) -{ - return memmove(dst, src, n); -} - -void strcpy(char *dst, const char *src) -{ - while (*src) - *dst++ = *src++; - *dst = 0; -} - -int strlen(const char *s) -{ - int n = 0; - while (s[n]) - n++; - return n; -} - -int strcmp(const char *s1, const char *s2) -{ - while (*s1 && (*s1 == *s2)) - { - s1++; - s2++; - } - return *(const unsigned char *)s1 - *(const unsigned char *)s2; -} - -int strcasecmp(const char *s1, const char *s2) -{ - while (*s1) - { - if(*s1 == *s2 || *s1 + 32 == *s2 || *s1 == *s2 + 32){ - s1++; - s2++; - } - else break; - } - return *(const unsigned char *)s1 - *(const unsigned char *)s2; -} \ No newline at end of file diff --git a/src/ulib/assert.c b/src/ulib/assert.c deleted file mode 100644 index c60643a..0000000 --- a/src/ulib/assert.c +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "stdio.h" -#include "stdlib.h" - -void __assert_fail(const char *expr, const char *file, int line, const char *func) -{ - fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); - abort(); -} \ No newline at end of file diff --git a/src/ulib/cxx.cc b/src/ulib/cxx.cc deleted file mode 100644 index d8f510d..0000000 --- a/src/ulib/cxx.cc +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdlib.h" - -void *operator new(unsigned long n) -{ - return malloc(n); -} - -void *operator new[](unsigned long n) -{ - return malloc(n); -} - -void operator delete(void *p) -{ - free(p); -} - -void operator delete[](void *p) -{ - free(p); -} - -void operator delete(void *p, unsigned long) -{ - free(p); -} - -void operator delete[](void *p, unsigned long) -{ - free(p); -} \ No newline at end of file diff --git a/src/ulib/iostream.cpp b/src/ulib/iostream.cpp deleted file mode 100644 index 4d721c1..0000000 --- a/src/ulib/iostream.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/iostream" - -namespace std -{ - istream cin(stdin); - ostream cout(stdout); - ostream cerr(stderr); -} // namespace std diff --git a/src/ulib/stdio.c b/src/ulib/stdio.c deleted file mode 100644 index e81f69a..0000000 --- a/src/ulib/stdio.c +++ /dev/null @@ -1,1056 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/string.h" -#include "ulib/stdlib.h" - -/* Include STB Sprintf Implementation */ -#define STB_SPRINTF_IMPLEMENTATION -#include "ulib/stb_sprintf.h" - -const int STDIN_FD = 0; -const int STDOUT_FD = 1; -const int STDERR_FD = 2; - - - -extern int open(const char *path, int flags); -extern int close(int fd); -extern int read(int fd, void *buf, uint64 count); -extern int write(int fd, const void *buf, uint64 count); -extern int lseek(int fd, int offset, int whence); - -static int isspace(int c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -/* Core Formatting Implementation */ - -static int _ul_to_str_invert(char *buf, uint64 val, int base, int uppercase) -{ - int i = 0; - const char *digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; - if (val == 0) - { - buf[i++] = '0'; - return i; - } - while (val != 0) - { - buf[i++] = digits[val % base]; - val /= base; - } - return i; -} - -typedef struct -{ - char *buf; - uint64 limit; - uint64 written; - FILE *stream; -} _OutContext; - -static void _out_char(_OutContext *ctx, char c) -{ - if (ctx->stream) - { - fputc(c, ctx->stream); - ctx->written++; - } - else - { - if (ctx->limit > 0 && ctx->written < ctx->limit - 1) - { - ctx->buf[ctx->written] = c; - } - ctx->written++; - } -} - -static int _vprintf_core(_OutContext *ctx, const char *format, va_list ap) -{ - const char *p = format; - char num_buf[32]; - - while (*p) - { - if (*p != '%') - { - _out_char(ctx, *p++); - continue; - } - p++; - - int flag_left = 0, flag_zero = 0, flag_plus = 0, flag_space = 0, flag_hash = 0; - while (1) - { - if (*p == '-') - flag_left = 1; - else if (*p == '0') - flag_zero = 1; - else if (*p == '+') - flag_plus = 1; - else if (*p == ' ') - flag_space = 1; - else if (*p == '#') - flag_hash = 1; - else - break; - p++; - } - - int width = 0; - if (*p == '*') - { - width = va_arg(ap, int); - if (width < 0) - { - flag_left = 1; - width = -width; - } - p++; - } - else - { - while (*p >= '0' && *p <= '9') - { - width = width * 10 + (*p - '0'); - p++; - } - } - - int precision = -1; - if (*p == '.') - { - p++; - if (*p == '*') - { - precision = va_arg(ap, int); - p++; - } - else - { - precision = 0; - while (*p >= '0' && *p <= '9') - { - precision = precision * 10 + (*p - '0'); - p++; - } - } - } - - int len_mod = 0; - if (*p == 'l') - { - len_mod = 1; - p++; - if (*p == 'l') - { - len_mod = 2; - p++; - } - } - else if (*p == 'z') - { - len_mod = 2; - p++; - } - - char spec = *p++; - if (!spec) - break; - - if (spec == 'd' || spec == 'i' || spec == 'u' || spec == 'x' || spec == 'X' || spec == 'p') - { - uint64 val; - int is_signed = (spec == 'd' || spec == 'i'); - int base = (spec == 'x' || spec == 'X' || spec == 'p') ? 16 : 10; - - if (spec == 'p') - val = (uint64)va_arg(ap, void *); - else if (len_mod == 2) - val = is_signed ? (uint64)va_arg(ap, int64) : va_arg(ap, uint64); - else if (len_mod == 1) - val = is_signed ? (uint64)va_arg(ap, long) : (uint64)va_arg(ap, unsigned long); - else - val = is_signed ? (uint64)((int64)va_arg(ap, int)) : (uint64)va_arg(ap, uint32); - - char sign_char = 0; - if (is_signed) - { - int64 sval = (int64)val; - if (sval < 0) - { - sign_char = '-'; - val = (uint64)(-sval); - } - else if (flag_plus) - sign_char = '+'; - else if (flag_space) - sign_char = ' '; - } - - int digit_len = _ul_to_str_invert(num_buf, val, base, (spec == 'X')); - if (precision >= 0) - flag_zero = 0; - int prec_zeros = (precision > digit_len) ? precision - digit_len : 0; - if (precision == 0 && val == 0) - digit_len = 0; - - int prefix_len = sign_char ? 1 : 0; - char *prefix_str = NULL; - if (spec == 'p' || (flag_hash && val != 0 && (spec == 'x' || spec == 'X'))) - { - prefix_str = (spec == 'X') ? "0X" : "0x"; - prefix_len += 2; - } - - int padding = (width > prefix_len + prec_zeros + digit_len) ? width - (prefix_len + prec_zeros + digit_len) : 0; - - if (!flag_left && !flag_zero) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - if (sign_char) - _out_char(ctx, sign_char); - if (prefix_str) - { - _out_char(ctx, prefix_str[0]); - _out_char(ctx, prefix_str[1]); - } - int total_zeros = prec_zeros + ((flag_zero && !flag_left) ? padding : 0); - for (int i = 0; i < total_zeros; i++) - _out_char(ctx, '0'); - for (int i = digit_len - 1; i >= 0; i--) - _out_char(ctx, num_buf[i]); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else if (spec == 'f' || spec == 'F' || spec == 'e' || spec == 'E' || spec == 'g' || spec == 'G') - { - char fmt_tmp[32]; - int f_idx = 0; - fmt_tmp[f_idx++] = '%'; - if (flag_left) - fmt_tmp[f_idx++] = '-'; - if (flag_zero) - fmt_tmp[f_idx++] = '0'; - if (flag_plus) - fmt_tmp[f_idx++] = '+'; - if (flag_space) - fmt_tmp[f_idx++] = ' '; - if (flag_hash) - fmt_tmp[f_idx++] = '#'; - if (width > 0) - f_idx += sprintf(&fmt_tmp[f_idx], "%d", width); - if (precision >= 0) - f_idx += sprintf(&fmt_tmp[f_idx], ".%d", precision); - fmt_tmp[f_idx++] = spec; - fmt_tmp[f_idx] = '\0'; - double f_val = va_arg(ap, double); - char f_buf[128]; - stbsp_snprintf(f_buf, sizeof(f_buf), fmt_tmp, f_val); - for (int i = 0; f_buf[i] != '\0'; i++) - _out_char(ctx, f_buf[i]); - } - else if (spec == 's') - { - const char *s = va_arg(ap, char *); - if (!s) - s = "(null)"; - int len = 0; - const char *tmp = s; - while (*tmp && (precision < 0 || len < precision)) - { - tmp++; - len++; - } - int padding = (width > len) ? width - len : 0; - if (!flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - for (int i = 0; i < len; i++) - _out_char(ctx, s[i]); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else if (spec == 'c') - { - char c = (char)va_arg(ap, int); - int padding = (width > 1) ? width - 1 : 0; - if (!flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - _out_char(ctx, c); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else - { - _out_char(ctx, '%'); - if (spec != '%') - _out_char(ctx, spec); - } - } - return (int)ctx->written; -} - -int vsnprintf(char *str, uint64 size, const char *format, va_list ap) -{ - _OutContext ctx; - ctx.buf = str; - ctx.limit = size; - ctx.written = 0; - ctx.stream = NULL; - _vprintf_core(&ctx, format, ap); - if (size > 0) - { - if (ctx.written < size) - str[ctx.written] = '\0'; - else - str[size - 1] = '\0'; - } - return (int)ctx.written; -} -int snprintf(char *str, uint64 size, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int ret = vsnprintf(str, size, format, ap); - va_end(ap); - return ret; -} -int sprintf(char *str, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int ret = vsnprintf(str, (uint64)-1, format, ap); - va_end(ap); - return ret; -} -int printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _OutContext ctx; - ctx.buf = NULL; - ctx.limit = 0; - ctx.written = 0; - ctx.stream = stdout; - _vprintf_core(&ctx, format, ap); - va_end(ap); - return (int)ctx.written; -} - -/* Core Function Implementation */ - -typedef struct -{ - const char *buf; - int fd; - uint64 pos; - int ungotten; -} _InContext; - -static int _in_char(_InContext *ctx) -{ - if (ctx->ungotten >= 0) - { - int c = ctx->ungotten; - ctx->ungotten = -1; - return c; - } - if (ctx->fd == -1) - { - if (ctx->buf[ctx->pos] == '\0') - return -1; - return (unsigned char)ctx->buf[ctx->pos++]; - } - char c; - if (read(ctx->fd, &c, 1) == 1) - return (unsigned char)c; - return -1; -} - -static void _unget_char(_InContext *ctx, int c) -{ - if (c != -1) - ctx->ungotten = c; -} -static void _skip_space(_InContext *ctx) -{ - int c; - while ((c = _in_char(ctx)) != -1) - { - if (!isspace(c)) - { - _unget_char(ctx, c); - break; - } - } -} - -static double _simple_strtod(const char *str, char **endptr) -{ - double val = 0.0; - int sign = 1; - if (*str == '-') - { - sign = -1; - str++; - } - else if (*str == '+') - str++; - while (*str >= '0' && *str <= '9') - { - val = val * 10.0 + (*str - '0'); - str++; - } - if (*str == '.') - { - str++; - double div = 10.0; - while (*str >= '0' && *str <= '9') - { - val += (*str - '0') / div; - div *= 10.0; - str++; - } - } - if (*str == 'e' || *str == 'E') - { - str++; - int esign = 1; - if (*str == '-') - { - esign = -1; - str++; - } - else if (*str == '+') - str++; - int eval = 0; - while (*str >= '0' && *str <= '9') - { - eval = eval * 10 + (*str - '0'); - str++; - } - double p = 1.0; - while (eval--) - p *= 10.0; - if (esign == 1) - val *= p; - else - val /= p; - } - if (endptr) - *endptr = (char *)str; - return sign * val; -} - -static int _vscanf_core(_InContext *ctx, const char *format, va_list ap) -{ - int assigned = 0; - const char *p = format; - while (*p) - { - if (isspace(*p)) - { - _skip_space(ctx); - while (isspace(*p)) - p++; - continue; - } - if (*p != '%') - { - _skip_space(ctx); - int c = _in_char(ctx); - if (c != *p) - { - _unget_char(ctx, c); - return assigned; - } - p++; - continue; - } - p++; - int suppress = 0; - if (*p == '*') - { - suppress = 1; - p++; - } - int width = -1; - while (*p >= '0' && *p <= '9') - { - if (width == -1) - width = 0; - width = width * 10 + (*p - '0'); - p++; - } - int len_mod = 0; - if (*p == 'l') - { - len_mod = 1; - p++; - if (*p == 'l') - { - len_mod = 2; - p++; - } - } - else if (*p == 'h') - { - p++; - if (*p == 'h') - p++; - } - char spec = *p++; - if (!spec) - break; - - if (spec == 'd' || spec == 'i' || spec == 'u' || spec == 'x') - { - _skip_space(ctx); - char num_buf[64]; - int i = 0, c = _in_char(ctx); - if (c == '-' || c == '+') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - int base = (spec == 'x') ? 16 : (spec == 'i' ? 0 : 10); - while (c != -1 && i < 63) - { - int digit = (c >= '0' && c <= '9'); - int hex = (base == 16 || base == 0) && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); - int x = (c == 'x' || c == 'X'); - if (base == 0 && i == 1 && num_buf[0] == '0' && x) - base = 16; - if (width > 0 && i >= width) - break; - if (digit || hex || x) - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - else - break; - } - num_buf[i] = '\0'; - _unget_char(ctx, c); - if (i == 0) - return assigned; - if (!suppress) - { - int64 val = strtoll(num_buf, NULL, base); - if (len_mod == 2) - *va_arg(ap, int64 *) = val; - else if (len_mod == 1) - *va_arg(ap, long *) = (long)val; - else - *va_arg(ap, int *) = (int)val; - assigned++; - } - } - else if (spec == 'f' || spec == 'F' || spec == 'e' || spec == 'E' || spec == 'g' || spec == 'G') - { - _skip_space(ctx); - char num_buf[64]; - int i = 0, c = _in_char(ctx); - if (c == '-' || c == '+') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - while (c != -1 && i < 63) - { - if ((c >= '0' && c <= '9') || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - else - break; - } - num_buf[i] = '\0'; - _unget_char(ctx, c); - if (i == 0) - return assigned; - if (!suppress) - { - double val = _simple_strtod(num_buf, NULL); - if (len_mod == 1) - *va_arg(ap, double *) = val; - else - *va_arg(ap, float *) = (float)val; - assigned++; - } - } - else if (spec == 's') - { - _skip_space(ctx); - char *buf = suppress ? NULL : va_arg(ap, char *); - int i = 0, c = _in_char(ctx); - while (c != -1 && !isspace(c)) - { - if (width > 0 && i >= width) - break; - if (!suppress) - buf[i] = (char)c; - i++; - c = _in_char(ctx); - } - if (!suppress) - buf[i] = '\0'; - _unget_char(ctx, c); - if (i > 0 && !suppress) - assigned++; - } - else if (spec == 'c') - { - int count = (width > 0) ? width : 1; - char *buf = suppress ? NULL : va_arg(ap, char *); - for (int i = 0; i < count; i++) - { - int c = _in_char(ctx); - if (c == -1) - return assigned; - if (!suppress) - buf[i] = (char)c; - } - if (!suppress) - assigned++; - } - } - return assigned; -} - -int sscanf(const char *str, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = str; - ctx.fd = -1; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} -int scanf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = NULL; - ctx.fd = STDIN_FD; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} - -/* FILE Stream Implementation */ - -#define O_RDONLY 00 -#define O_WRONLY 01 -#define O_RDWR 02 -#define O_CREAT 0100 -#define O_TRUNC 01000 -#define O_APPEND 02000 - - -static FILE _stdin = {.fd = 0, .buf_mode = 1}; -static FILE _stdout = {.fd = 1, .buf_mode = 1}; -static FILE _stderr = {.fd = 2, .buf_mode = 2}; - -FILE *stdin = &_stdin; -FILE *stdout = &_stdout; -FILE *stderr = &_stderr; - -FILE *fopen(const char *filename, const char *mode) -{ - int flags = 0; - if (strcmp(mode, "r") == 0) - flags = O_RDONLY; - else if (strcmp(mode, "w") == 0) - flags = O_WRONLY | O_CREAT | O_TRUNC; - else if (strcmp(mode, "a") == 0) - flags = O_WRONLY | O_CREAT | O_APPEND; - else if (strcmp(mode, "r+") == 0) - flags = O_RDWR; - else - return NULL; - - int64 fd = open(filename, flags); - if (fd < 0) - return NULL; - - FILE *f = (FILE *)malloc(sizeof(FILE)); - if (!f) - { - close(fd); - return NULL; - } - - memset(f, 0, sizeof(FILE)); - f->fd = (int)fd; - f->flags = flags; - - if (fd == 1) - f->buf_mode = 1; - else if (fd == 2) - f->buf_mode = 2; - else - f->buf_mode = 0; - return f; -} - -int fclose(FILE *stream) -{ - if (!stream) - return -1; - fflush(stream); - if (stream != stdin && stream != stdout && stream != stderr) - { - close(stream->fd); - free(stream); - } - return 0; -} - -int fflush(FILE *stream) -{ - if (!stream) - return EOF; - - if (stream->buf_write_pos > 0) - { - int64 ret = write(stream->fd, stream->buffer, stream->buf_write_pos); - if (ret < stream->buf_write_pos) - { - stream->error = 1; - stream->buf_write_pos = 0; - return EOF; - } - stream->buf_write_pos = 0; - } - return 0; -} - -int fprintf(FILE *stream, const char *format, ...) -{ - if (!stream) - return -1; - va_list ap; - va_start(ap, format); - _OutContext ctx; - ctx.buf = NULL; - ctx.limit = 0; - ctx.written = 0; - ctx.stream = stream; - _vprintf_core(&ctx, format, ap); - va_end(ap); - return (int)ctx.written; -} - -int fscanf(FILE *stream, const char *format, ...) -{ - if (!stream) - return -1; - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = NULL; - ctx.fd = stream->fd; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} - -int fputc(int c, FILE *stream) -{ - if (!stream) - return EOF; - if (stream->buf_mode == 2) - { - char ch = (char)c; - if (write(stream->fd, &ch, 1) != 1) - { - stream->error = 1; - return EOF; - } - return c; - } - - stream->buffer[stream->buf_write_pos++] = (char)c; - - if (stream->buf_write_pos >= BUFSIZ) - { - fflush(stream); - } - else if (stream->buf_mode == 1 && c == '\n') - { - fflush(stream); - } - - return c; -} - -int fputs(const char *s, FILE *stream) -{ - if (!stream) - return -1; - while (*s) - { - if (fputc(*s++, stream) == EOF) - return EOF; - } - return 0; -} - -int fgetc(FILE *stream) -{ - if (!stream) - return EOF; - - if (stream->buf_write_pos > 0) - { - fflush(stream); - } - - if (stream->buf_read_pos < stream->buf_read_cnt) - { - return (unsigned char)stream->buffer[stream->buf_read_pos++]; - } - - int64 ret = read(stream->fd, stream->buffer, BUFSIZ); - if (ret <= 0) - { - if (ret == 0) - stream->eof = 1; - else - stream->error = 1; - return EOF; - } - - stream->buf_read_cnt = (int)ret; - stream->buf_read_pos = 0; - return (unsigned char)stream->buffer[stream->buf_read_pos++]; -} - -char *fgets(char *str, int n, FILE *stream) -{ - if (!stream || n <= 0) - return NULL; - int i = 0, c; - while (i < n - 1) - { - c = fgetc(stream); - if (c == -1) - { - if (i == 0) - return NULL; - break; - } - str[i++] = (char)c; - if (c == '\n') - break; - } - str[i] = '\0'; - return str; -} - -uint64 fread(void *ptr, uint64 size, uint64 nmemb, FILE *stream) -{ - if (!stream || size == 0 || nmemb == 0) - return 0; - - uint64 total_bytes = size * nmemb; - uint64 bytes_read = 0; - char *dst = (char *)ptr; - - if (stream->buf_write_pos > 0) - fflush(stream); - - while (bytes_read < total_bytes) - { - if (stream->buf_read_pos < stream->buf_read_cnt) - { - uint64 available = stream->buf_read_cnt - stream->buf_read_pos; - uint64 remaining = total_bytes - bytes_read; - uint64 to_copy = (available < remaining) ? available : remaining; - - memcpy(dst + bytes_read, stream->buffer + stream->buf_read_pos, to_copy); - - stream->buf_read_pos += to_copy; - bytes_read += to_copy; - } - else - { - uint64 remaining = total_bytes - bytes_read; - - if (remaining >= BUFSIZ) - { - int64 ret = read(stream->fd, dst + bytes_read, remaining); - if (ret <= 0) - { - if (ret == 0) - stream->eof = 1; - else - stream->error = 1; - return bytes_read / size; - } - bytes_read += ret; - } - else - { - stream->buf_read_pos = 0; - stream->buf_read_cnt = 0; - int64 ret = read(stream->fd, stream->buffer, BUFSIZ); - - if (ret <= 0) - { - if (ret == 0) - stream->eof = 1; - else - stream->error = 1; - return bytes_read / size; - } - stream->buf_read_cnt = (int)ret; - } - } - } - return bytes_read / size; -} - -uint64 fwrite(const void *ptr, uint64 size, uint64 nmemb, FILE *stream) -{ - if (!stream || !ptr || size == 0 || nmemb == 0) - return 0; - uint64 total_bytes = size * nmemb; - const char *src = (const char *)ptr; - uint64 bytes_written = 0; - - if (stream->buf_mode == 2) - { - while (bytes_written < total_bytes) - { - int64 ret = write(stream->fd, src + bytes_written, total_bytes - bytes_written); - if (ret <= 0) - { - stream->error = 1; - break; - } - bytes_written += ret; - } - return bytes_written / size; - } - - while (bytes_written < total_bytes) - { - uint64 space_left = BUFSIZ - stream->buf_write_pos; - uint64 remaining = total_bytes - bytes_written; - - if (remaining <= space_left) - { - memcpy(stream->buffer + stream->buf_write_pos, src + bytes_written, remaining); - stream->buf_write_pos += remaining; - bytes_written += remaining; - if (stream->buf_write_pos == BUFSIZ) - fflush(stream); - } - else - { - memcpy(stream->buffer + stream->buf_write_pos, src + bytes_written, space_left); - stream->buf_write_pos += space_left; - bytes_written += space_left; - fflush(stream); - } - } - - return bytes_written / size; -} - -int fseek(FILE *stream, long offset, int whence) -{ - if (!stream) - return -1; - - if (stream->buf_write_pos > 0) - { - fflush(stream); - } - stream->buf_read_pos = 0; - stream->buf_read_cnt = 0; - stream->eof = 0; - - if (lseek(stream->fd, offset, whence) < 0) - { - stream->error = 1; - return -1; - } - return 0; -} -long ftell(FILE *stream) -{ - if (!stream) - return -1L; - int64 ret = lseek(stream->fd, 0, SEEK_CUR); - if (ret < 0) - { - stream->error = 1; - return -1L; - } - return (long)ret; -} -void rewind(FILE *stream) -{ - if (stream) - { - fseek(stream, 0, SEEK_SET); - stream->error = 0; - } -} - -int feof(FILE *stream) -{ - return (stream) ? stream->eof : 1; -} -int ferror(FILE *stream) -{ - return (stream) ? stream->error : 1; -} -void clearerr(FILE *stream) -{ - if (stream) - { - stream->error = 0; - stream->eof = 0; - } -} - -int ungetc(int c, FILE *stream) -{ - if (!stream || c == EOF) - return EOF; - - if (stream->buf_read_pos > 0) - { - stream->buf_read_pos--; - stream->buffer[stream->buf_read_pos] = (char)c; - stream->eof = 0; - return c; - } - return EOF; -} \ No newline at end of file diff --git a/src/ulib/stdlib.c b/src/ulib/stdlib.c deleted file mode 100644 index 8b22b6f..0000000 --- a/src/ulib/stdlib.c +++ /dev/null @@ -1,543 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "ulib/ctypes.h" - -extern int sys_exit(int status); -extern void *sbrk(long increment); - -#undef errno -int errno = 0; - -#define ATEXIT_MAX 32 -static void (*__atexit_funcs[ATEXIT_MAX])(void); -static int __atexit_func_count = 0; - -int atexit(void (*function)(void)) -{ - if (__atexit_func_count >= ATEXIT_MAX) - return -1; - __atexit_funcs[__atexit_func_count++] = function; - return 0; -} - -int exit(int status) -{ - while (__atexit_func_count > 0) - { - (__atexit_funcs[--__atexit_func_count])(); - } - sys_exit(status); - - while (1) - ; - return 0; -} - -void abort(void) -{ - exit(127); -} - -char *getenv(const char *name) -{ - /* None */ - return NULL; -} - -int system(const char *command) -{ - /* None */ - return -1; -} - -/* Memory Management */ -#define ALIGNMENT 16 -#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) - -typedef struct header -{ - size_t size; - struct header *next; -} header_t; - -static header_t base; -static header_t *freep = NULL; - - -#define LOCK() -#define UNLOCK() - -void free(void *ptr) -{ - header_t *bp, *p; - - if (!ptr) - return; - - - bp = (header_t *)ptr - 1; - - LOCK(); - - - for (p = freep; !(bp > p && bp < p->next); p = p->next) - { - if (p >= p->next && (bp > p || bp < p->next)) - break; - } - - if ((char *)bp + bp->size == (char *)p->next) - { - bp->size += p->next->size; - bp->next = p->next->next; - } - else - { - bp->next = p->next; - } - - if ((char *)p + p->size == (char *)bp) - { - p->size += bp->size; - p->next = bp->next; - } - else - { - p->next = bp; - } - - freep = p; - UNLOCK(); -} - -static header_t *morecore(size_t nu) -{ - char *cp; - header_t *up; - - if (nu < 4096) - nu = 4096; - - nu = ALIGN(nu); - - cp = (char *)sbrk(nu); - if (cp == (void *)-1) - return NULL; - - up = (header_t *)cp; - up->size = nu; - - free((void *)(up + 1)); - return freep; -} - -void *malloc(size_t size) -{ - header_t *p, *prevp; - - if (size == 0) - return NULL; - - size = ALIGN(size + sizeof(header_t)); - - LOCK(); - - if ((prevp = freep) == NULL) - { - base.next = freep = prevp = &base; - base.size = 0; - } - - for (p = prevp->next;; prevp = p, p = p->next) - { - if (p->size >= size) - { - if (p->size == size) - { - prevp->next = p->next; - } - else - { - p->size -= size; - - p = (header_t *)((char *)p + p->size); - - p->size = size; - } - freep = prevp; - UNLOCK(); - return (void *)(p + 1); - } - - if (p == freep) - { - if ((p = morecore(size)) == NULL) - { - UNLOCK(); - errno = ENOMEM; - return NULL; - } - } - } -} - -void *calloc(size_t nmemb, size_t size) -{ - size_t total; - if (__builtin_mul_overflow(nmemb, size, &total)) - { - errno = ENOMEM; - return NULL; - } - void *p = malloc(total); - if (p) - memset(p, 0, total); - return p; -} - -void *realloc(void *ptr, size_t size) -{ - if (!ptr) - return malloc(size); - if (size == 0) - { - free(ptr); - return NULL; - } - - header_t *bp = (header_t *)ptr - 1; - size_t new_size = ALIGN(size + sizeof(header_t)); - - if (bp->size >= new_size) - return ptr; - - void *new_ptr = malloc(size); - if (!new_ptr) - return NULL; - - memcpy(new_ptr, ptr, bp->size - sizeof(header_t)); - free(ptr); - return new_ptr; -} - -/* String Conversion*/ - -unsigned long long strtoull(const char *nptr, char **endptr, int base) -{ - const char *s = nptr; - unsigned long long acc; - unsigned long long cutoff; - int c; - int neg = 0, any, cutlim; - - if (base < 0 || base == 1 || base > 36) - { - if (endptr) - *endptr = (char *)nptr; - errno = 0; /* EINVAL */ - return 0; - } - - do - { - c = *s++; - } while (isspace(c)); - - if (c == '-') - { - neg = 1; - c = *s++; - } - else if (c == '+') - { - c = *s++; - } - - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = (c == '0' ? 8 : 10); - - cutoff = ULLONG_MAX / (unsigned long long)base; - cutlim = ULLONG_MAX % (unsigned long long)base; - - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - - if (c >= base) - break; - - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else - { - any = 1; - acc *= base; - acc += c; - } - } - - if (any < 0) - { - acc = ULLONG_MAX; - errno = ERANGE; - } - else if (neg) - acc = -acc; - - if (endptr != 0) - *endptr = (char *)(any ? s - 1 : nptr); - - return acc; -} - -long long strtoll(const char *nptr, char **endptr, int base) -{ - const char *s = nptr; - unsigned long long acc; - int c, neg = 0; - - do - { - c = *s++; - } while (isspace(c)); - if (c == '-') - neg = 1; - - acc = strtoull(nptr, endptr, base); - - if (errno == ERANGE && acc == ULLONG_MAX) - return neg ? LLONG_MIN : LLONG_MAX; - - if (!neg && acc > (unsigned long long)LLONG_MAX) - { - errno = ERANGE; - return LLONG_MAX; - } - if (neg && acc > (unsigned long long)LLONG_MAX + 1) - { - errno = ERANGE; - return LLONG_MIN; - } - - return neg ? -(long long)acc : (long long)acc; -} - -unsigned long strtoul(const char *nptr, char **endptr, int base) -{ - unsigned long long ret = strtoull(nptr, endptr, base); - if (ret > ULONG_MAX) - { - errno = ERANGE; - return ULONG_MAX; - } - return (unsigned long)ret; -} - -long strtol(const char *nptr, char **endptr, int base) -{ - long long ret = strtoll(nptr, endptr, base); - if (ret > LONG_MAX) - { - errno = ERANGE; - return LONG_MAX; - } - if (ret < LONG_MIN) - { - errno = ERANGE; - return LONG_MIN; - } - return (long)ret; -} - -int atoi(const char *nptr) { return (int)strtol(nptr, NULL, 10); } -long atol(const char *nptr) { return strtol(nptr, NULL, 10); } -long long atoll(const char *nptr) { return strtoll(nptr, NULL, 10); } - -double strtod(const char *nptr, char **endptr) -{ - double val = 0.0; - int sign = 1; - const char *s = nptr; - - while (isspace(*s)) - s++; - if (*s == '-') - { - sign = -1; - s++; - } - else if (*s == '+') - s++; - - while (isdigit(*s)) - { - val = val * 10.0 + (*s - '0'); - s++; - } - if (*s == '.') - { - double factor = 1.0; - s++; - while (isdigit(*s)) - { - factor *= 0.1; - val += (*s - '0') * factor; - s++; - } - } - - if (endptr) - *endptr = (char *)s; - return val * sign; -} - -double atof(const char *nptr) { return strtod(nptr, NULL); } -float strtof(const char *nptr, char **endptr) { return (float)strtod(nptr, endptr); } - -/* Sort & Search */ - -static void swap_bytes(char *a, char *b, size_t size) -{ - char temp; - while (size--) - { - temp = *a; - *a++ = *b; - *b++ = temp; - } -} - -void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) -{ - if (nmemb < 2 || size == 0) - return; - - char *base_ptr = (char *)base; - char *pivot = base_ptr + (nmemb - 1) * size; - char *i = base_ptr; - char *j = base_ptr; - - /* Partition */ - for (; j < pivot; j += size) - { - if (compar(j, pivot) < 0) - { - if (i != j) - swap_bytes(i, j, size); - i += size; - } - } - swap_bytes(i, pivot, size); - - /* Recurse */ - size_t left_count = (i - base_ptr) / size; - qsort(base, left_count, size, compar); - qsort(i + size, nmemb - left_count - 1, size, compar); -} - -void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) -{ - size_t l = 0, u = nmemb; - while (l < u) - { - size_t idx = (l + u) / 2; - const void *p = (void *)((const char *)base + (idx * size)); - int cmp = compar(key, p); - if (cmp < 0) - u = idx; - else if (cmp > 0) - l = idx + 1; - else - return (void *)p; - } - return NULL; -} - -/* Math & Mics */ - -int abs(int j) { return (j < 0) ? -j : j; } -long labs(long j) { return (j < 0) ? -j : j; } -long long llabs(long long j) { return (j < 0) ? -j : j; } - -div_t div(int numer, int denom) -{ - div_t res = {numer / denom, numer % denom}; - return res; -} -ldiv_t ldiv(long numer, long denom) -{ - ldiv_t res = {numer / denom, numer % denom}; - return res; -} -lldiv_t lldiv(long long numer, long long denom) -{ - lldiv_t res = {numer / denom, numer % denom}; - return res; -} - -static unsigned long next = 1; -int rand(void) -{ - next = next * 1103515245 + 12345; - return (unsigned int)(next / 65536) % 32768; -} -void srand(unsigned int seed) { next = seed; } - -/* Stub */ -int mblen(const char *s, size_t n) { return (s && *s && n) ? 1 : 0; } -int mbtowc(wchar_t *pwc, const char *s, size_t n) -{ - if (!s) - return 0; - if (n == 0) - return -1; - if (pwc) - *pwc = (wchar_t)*s; - return (*s != 0); -} -int wctomb(char *s, wchar_t wchar) -{ - if (!s) - return 0; - *s = (char)wchar; - return 1; -} -size_t mbstowcs(wchar_t *dest, const char *src, size_t n) -{ - size_t i = 0; - while (src[i] && i < n) - { - dest[i] = (wchar_t)src[i]; - i++; - } - if (i < n) - dest[i] = 0; - return i; -} -size_t wcstombs(char *dest, const wchar_t *src, size_t n) -{ - size_t i = 0; - while (src[i] && i < n) - { - dest[i] = (char)src[i]; - i++; - } - if (i < n) - dest[i] = 0; - return i; -} \ No newline at end of file diff --git a/src/ulib/string.c b/src/ulib/string.c deleted file mode 100644 index c3dbe9a..0000000 --- a/src/ulib/string.c +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/string.h" -#include "ulib/stdlib.h" - - -/* Memory Manipulation Functions */ - -void *memset(void *dst, int c, size_t n) -{ - char *cdst = (char *)dst; - for (size_t i = 0; i < n; i++) - cdst[i] = (char)c; - return dst; -} - -void *memmove(void *vdst, const void *vsrc, size_t n) -{ - char *dst = (char *)vdst; - const char *src = (const char *)vsrc; - if (dst == src) - return vdst; - - if (src > dst) - { - while (n--) - *dst++ = *src++; - } - else - { - dst += n; - src += n; - while (n-- > 0) - *--dst = *--src; - } - return vdst; -} - -void *memcpy(void *vdst, const void *vsrc, size_t n) -{ - return memmove(vdst, vsrc, n); -} - -int memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *p1 = (const unsigned char *)s1; - const unsigned char *p2 = (const unsigned char *)s2; - while (n--) - { - if (*p1 != *p2) - return *p1 - *p2; - p1++; - p2++; - } - return 0; -} - -void *memchr(const void *s, int c, size_t n) -{ - const unsigned char *p = (const unsigned char *)s; - while (n--) - { - if (*p == (unsigned char)c) - return (void *)p; - p++; - } - return NULL; -} - -/* String Manipulation Functions */ - -size_t strlen(const char *s) -{ - const char *p = s; - while (*p) - p++; - return (size_t)(p - s); -} - -char *strcpy(char *dst, const char *src) -{ - char *os = dst; - while ((*dst++ = *src++) != 0) - ; - return os; -} - -char *strncpy(char *dst, const char *src, size_t n) -{ - char *os = dst; - size_t i; - - for (i = 0; i < n && src[i] != '\0'; i++) - dst[i] = src[i]; - - for (; i < n; i++) - dst[i] = '\0'; - - return os; -} - -char *strcat(char *dst, const char *src) -{ - char *os = dst; - while (*dst) - dst++; - while ((*dst++ = *src++) != 0) - ; - return os; -} - -char *strncat(char *dst, const char *src, size_t n) -{ - char *os = dst; - size_t dest_len = strlen(dst); - size_t i; - - dst += dest_len; - - for (i = 0; i < n && src[i] != '\0'; i++) - dst[i] = src[i]; - - dst[i] = '\0'; - - return os; -} - -int strcmp(const char *p, const char *q) -{ - while (*p && *p == *q) - { - p++; - q++; - } - return (int)((unsigned char)*p - (unsigned char)*q); -} - -int strncmp(const char *s1, const char *s2, size_t n) -{ - if (n == 0) - return 0; - - while (n-- > 0 && *s1 && *s1 == *s2) - { - if (n == 0 || *s1 == '\0') - break; - s1++; - s2++; - } - return (int)((unsigned char)*s1 - (unsigned char)*s2); -} - -char *strchr(const char *s, int c) -{ - while (*s != (char)c) - { - if (!*s++) - return NULL; - } - return (char *)s; -} - -char *strrchr(const char *s, int c) -{ - const char *last = NULL; - do - { - if (*s == (char)c) - last = s; - } while (*s++); - - return (char *)last; -} - - -char *strstr(const char *haystack, const char *needle) -{ - size_t n_len = strlen(needle); - if (n_len == 0) - return (char *)haystack; - - for (; *haystack; haystack++) - { - if (*haystack != *needle) - continue; - - if (strncmp(haystack, needle, n_len) == 0) - return (char *)haystack; - } - return NULL; -} - -char *strdup(const char *s) -{ - size_t len = strlen(s) + 1; - char *new_str = (char *)malloc(len); - if (new_str == NULL) - return NULL; - - return (char *)memcpy(new_str, s, len); -} - -size_t strlcpy(char *dst, const char *src, size_t size) -{ - size_t src_len = strlen(src); - - if (size > 0) - { - size_t copy_len = (src_len >= size) ? size - 1 : src_len; - memcpy(dst, src, copy_len); - dst[copy_len] = '\0'; - } - - return src_len; -} - -size_t strlcat(char *dst, const char *src, size_t size) -{ - size_t dst_len = 0; - size_t src_len = strlen(src); - - while (dst_len < size && dst[dst_len] != '\0') - dst_len++; - - if (dst_len == size) - return size + src_len; - - size_t space_left = size - dst_len; - size_t copy_len = (src_len >= space_left) ? space_left - 1 : src_len; - - memcpy(dst + dst_len, src, copy_len); - dst[dst_len + copy_len] = '\0'; - - return dst_len + src_len; -} - - -size_t strspn(const char *s, const char *accept) -{ - const char *p = s; - const char *a; - - while (*p) - { - for (a = accept; *a; a++) - { - if (*p == *a) - break; - } - if (*a == '\0') - return (size_t)(p - s); - p++; - } - return (size_t)(p - s); -} - -size_t strcspn(const char *s, const char *reject) -{ - const char *p = s; - const char *r; - - while (*p) - { - for (r = reject; *r; r++) - { - if (*p == *r) - return (size_t)(p - s); - } - p++; - } - return (size_t)(p - s); -} - -char *strpbrk(const char *s, const char *accept) -{ - const char *a; - while (*s) - { - for (a = accept; *a; a++) - { - if (*s == *a) - return (char *)s; - } - s++; - } - return NULL; -} - -char *strtok(char *str, const char *delim) -{ - static char *olds; - char *token; - - if (str == NULL) - str = olds; - - str += strspn(str, delim); - if (*str == '\0') - { - olds = str; - return NULL; - } - - token = str; - str = strpbrk(token, delim); - - if (str == NULL) - { - olds = strchr(token, '\0'); - } - else - { - *str = '\0'; - olds = str + 1; - } - - return token; -} - -char *strerror(int errnum) -{ - - switch (errnum) - { - case 0: - return "Success"; - // case EINVAL: return "Invalid argument"; - case ENOMEM: return "Out of memory"; - - default: - return "Unknown error"; - } -} \ No newline at end of file diff --git a/src/ulib/syscalls.c b/src/ulib/syscalls.c deleted file mode 100644 index 676bf18..0000000 --- a/src/ulib/syscalls.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard Qin - * Libc Syscall Shims - */ - -#include "common/types.h" -#include "user/user.h" - -// Define external raw syscalls from usys.S -extern int sys_openat(int dfd, const char *filename, int flags, int mode); -extern int sys_mknodat(int dfd, const char *filename, int mode, int dev); -extern int sys_mkdirat(int dfd, const char *path, int mode); -extern int sys_unlinkat(int dfd, const char *path, int flags); -extern int sys_linkat(int olddfd, const char *oldpath, int newdfd, const char *newpath, int flags); -extern int sys_chdir(const char *path); -extern int sys_dup(int oldfd); -extern int sys_fstat(int fd, void *statbuf); -extern int sys_read(int fd, void *buf, int count); -extern int sys_write(int fd, const void *buf, int count); -extern int sys_close(int fd); -extern int sys_pipe2(int pipefd[2], int flags); -extern int sys_clone(unsigned long flags, void *stack, int *ptid, void *tls, int *ctid); -extern int sys_execve(const char *path, char *const argv[], char *const envp[]); -extern int sys_wait4(int pid, int *status, int options, void *rusage); -extern int sys_exit(int status); -extern int sys_getpid(); -extern int sys_brk(int n); -extern int sys_kill(int pid, int sig); -extern int sys_nanosleep(void *req, void *rem); -extern int sys_reboot(int magic1, int magic2, int cmd, void *arg); -extern int sys_lseek(int fd, int offset, int whence); -extern void sys_putc(char c); -extern int sys_disk_test(); - -// --- POSIX Implementation --- - -int open(const char *path, int flags) -{ - return sys_openat(AT_FDCWD, path, flags, 0); -} - -int mknod(const char *path, short major, short minor) -{ - // Pack major/minor into simplified dev_t (major << 20 | minor) - int dev = (major << 20) | (minor & 0xFFFFF); - return sys_mknodat(AT_FDCWD, path, 0, dev); -} - -int mkdir(const char *path) -{ - return sys_mkdirat(AT_FDCWD, path, 0); -} - -int unlink(const char *path) -{ - return sys_unlinkat(AT_FDCWD, path, 0); -} - -int link(const char *oldpath, const char *newpath) -{ - return sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); -} - -int chdir(const char *path) -{ - return sys_chdir(path); -} - -int fork() -{ - return sys_clone(0, 0, 0, 0, 0); -} - -int exec(char *path, char **argv) -{ - return sys_execve(path, argv, 0); -} - -int wait(uint64 status_addr) -{ - return sys_wait4(-1, (int *)status_addr, 0, 0); -} - -int pipe(int p[]) -{ - return sys_pipe2(p, 0); -} - -int read(int fd, void *buf, int n) -{ - return sys_read(fd, buf, n); -} - -int write(int fd, const void *buf, int n) -{ - return sys_write(fd, buf, n); -} - -int close(int fd) -{ - return sys_close(fd); -} - -int fstat(int fd, void *st) -{ - return sys_fstat(fd, st); -} - -int dup(int fd) -{ - return sys_dup(fd); -} - -int getpid() -{ - return sys_getpid(); -} - -char *sbrk(int n) -{ - return (char *)(long)sys_brk(n); -} - -int kill(int pid) -{ - return sys_kill(pid, 0); -} - -int sleep(int ticks) -{ - return sys_nanosleep((void *)(long)ticks, 0); -} - -int shutdown() -{ - return sys_reboot(0, 0, 0, 0); -} - -void putc(char c) -{ - sys_putc(c); -} - -int disk_test() -{ - return sys_disk_test(); -} - -int lseek(int fd, int offset, int whence) -{ - return sys_lseek(fd, offset, whence); -} \ No newline at end of file diff --git a/src/user/cat.cc b/src/user/cat.cc deleted file mode 100644 index b518d77..0000000 --- a/src/user/cat.cc +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "common/fcntl.h" - -char buf[512]; - -void cat(int fd) -{ - int n; - while ((n = read(fd, buf, sizeof(buf))) > 0) - { - if (write(1, buf, n) != n) - { - printf("cat: write error\n"); - exit(1); - } - } - if (n < 0) - { - printf("cat: read error\n"); - exit(1); - } -} - -int main(int argc, char *argv[]) -{ - int fd, i; - - if (argc <= 1) - { - cat(0); - exit(0); - } - - for (i = 1; i < argc; i++) - { - if ((fd = open(argv[i], O_RDONLY)) < 0) - { - printf("cat: cannot open %s\n", argv[i]); - exit(1); - } - cat(fd); - close(fd); - } - exit(0); -} \ No newline at end of file diff --git a/src/user/cp.cc b/src/user/cp.cc deleted file mode 100644 index ca35e82..0000000 --- a/src/user/cp.cc +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" -#include "common/fcntl.h" - -char buf[512]; - -int main(int argc, char *argv[]) -{ - int fd_src, fd_dst, n; - - if (argc != 3) - { - printf("Usage: cp src dst\n"); - exit(1); - } - - if ((fd_src = open(argv[1], O_RDONLY)) < 0) - { - printf("cp: cannot open source %s\n", argv[1]); - exit(1); - } - - if ((fd_dst = open(argv[2], O_WRONLY | O_CREATE | O_TRUNC)) < 0) - { - printf("cp: cannot create destination %s\n", argv[2]); - close(fd_src); - exit(1); - } - - while ((n = read(fd_src, buf, sizeof(buf))) > 0) - { - if (write(fd_dst, buf, n) != n) - { - printf("cp: write error\n"); - exit(1); - } - } - - if (n < 0) - { - printf("cp: read error\n"); - } - - close(fd_src); - close(fd_dst); - exit(0); -} \ No newline at end of file diff --git a/src/user/echo.cc b/src/user/echo.cc deleted file mode 100644 index cc9dc2a..0000000 --- a/src/user/echo.cc +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "user/user.h" -#include "ulib/stdio.h" -#include "ulib/string.h" - -int main(int argc, char* argv[]) -{ - int i; - - for (i = 1; i < argc; i++) - { - write(1, argv[i], strlen(argv[i])); - if (i + 1 < argc) - { - write(1, " ", 1); - } - else - { - write(1, "\n", 1); - } - } - exit(0); -} \ No newline at end of file diff --git a/src/user/entry.S b/src/user/entry.S deleted file mode 100644 index 41e0964..0000000 --- a/src/user/entry.S +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -.section .text -.global _start - -_start: - call main - - call exit - -1: j 1b \ No newline at end of file diff --git a/src/user/grep.cc b/src/user/grep.cc deleted file mode 100644 index 1e1c42d..0000000 --- a/src/user/grep.cc +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "common/fcntl.h" - -char buf[1024]; - -void grep(char *pattern, int fd) -{ - int n, m; - char *p, *q; - - m = 0; - while ((n = read(fd, buf + m, sizeof(buf) - m - 1)) > 0) - { - m += n; - buf[m] = '\0'; - p = buf; - while ((q = strchr(p, '\n')) != 0) - { - *q = 0; - if (strstr(p, pattern) != 0) - { - printf("%s\n", p); - } - p = q + 1; - } - if (p == buf) - m = 0; - if (m > 0) - { - m -= p - buf; - memmove(buf, p, m); - } - } -} - -int main(int argc, char *argv[]) -{ - int fd, i; - char *pattern; - - if (argc < 2) - { - printf("Usage: grep pattern [file...]\n"); - exit(1); - } - pattern = argv[1]; - - if (argc == 2) - { - grep(pattern, 0); // stdin - exit(0); - } - - for (i = 2; i < argc; i++) - { - if ((fd = open(argv[i], O_RDONLY)) < 0) - { - printf("grep: cannot open %s\n", argv[i]); - exit(1); - } - grep(pattern, fd); - close(fd); - } - exit(0); -} \ No newline at end of file diff --git a/src/user/init.cc b/src/user/init.cc deleted file mode 100644 index 376e697..0000000 --- a/src/user/init.cc +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "drivers/uart_color.h" - -int main() -{ - char *argv[] = {(char *)"sh", 0}; - - printf(ANSI_BLUE "\n[Init] Starting Lume OS Shell..." ANSI_RESET); - printf("\n"); - - while (1) - { - // printf("fork start\n"); - int pid = fork(); - // printf("fork suceess, pid=%i\n", pid); - - if (pid < 0) - { - printf("[Init] fork failed!\n"); - exit(1); - } - - if (pid == 0) - { - - char sh_path[] = "/sh"; - exec(sh_path, argv); - - printf("[Init] exec sh failed\n"); - return 0; - exit(1); - } - else - { - // break; - int status; - int wpid; - while (1) - { - wpid = wait((uint64)&status); - - if (wpid == pid) - { - printf("Shell Exit"); - break; - } - if (wpid < 0) - { - printf("[Init] wait error or no child\n"); - - break; - } - } - } - } - return 0; -} \ No newline at end of file diff --git a/src/user/kill.cc b/src/user/kill.cc deleted file mode 100644 index d38cdd6..0000000 --- a/src/user/kill.cc +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" - -int main(int argc, char *argv[]) -{ - int i; - - if (argc < 2) - { - printf("Usage: kill pid...\n"); - exit(1); - } - for (i = 1; i < argc; i++) - { - int pid = atoi(argv[i]); - if (kill(pid) < 0) - { - printf("kill: failed to kill %d\n", pid); - } - } - exit(0); -} \ No newline at end of file diff --git a/src/user/ln.cc b/src/user/ln.cc deleted file mode 100644 index a21ddf9..0000000 --- a/src/user/ln.cc +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" - -int main(int argc, char *argv[]) -{ - if (argc != 3) - { - printf("Usage: ln old new\n"); - exit(1); - } - if (link(argv[1], argv[2]) < 0) - { - printf("link %s %s failed\n", argv[1], argv[2]); - exit(1); - } - exit(0); -} \ No newline at end of file diff --git a/src/user/ls.cc b/src/user/ls.cc deleted file mode 100644 index c44c799..0000000 --- a/src/user/ls.cc +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "common/fcntl.h" - - -struct FAT32_DirEnt -{ - char name[11]; - uint8 attr; - uint8 lcase; - uint8 ctime_cs; - uint16 ctime; - uint16 cdate; - uint16 adate; - uint16 fstClusHI; - uint16 wtime; - uint16 wdate; - uint16 fstClusLO; - uint32 fileSize; -} __attribute__((packed)); - -#define ATTR_DIRECTORY 0x10 -#define ATTR_LONG_NAME 0x0F - -void fmt_name(char *dst, const char *src) -{ - int i; - char *d = dst; - - for (i = 0; i < 8; i++) - { - if (src[i] == ' ') - break; - *d++ = src[i]; - } - - if (src[8] != ' ') - { - *d++ = '.'; - for (i = 8; i < 11; i++) - { - if (src[i] == ' ') - break; - *d++ = src[i]; - } - } - *d = 0; - - for (d = dst; *d; d++) - { - if (*d >= 'A' && *d <= 'Z') - *d += 32; - } -} - -void ls(const char *path) -{ - int fd; - struct FAT32_DirEnt de; - char name_buf[16]; - - if ((fd = open(path, O_RDONLY)) < 0) - { - printf("ls: cannot open %s\n", path); - return; - } - - while (read(fd, &de, sizeof(de)) == sizeof(de)) - { - if (de.name[0] == 0) - { - break; - } - - if ((unsigned char)de.name[0] == 0xE5) - { - continue; - } - - if ((de.attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) - { - continue; - } - - fmt_name(name_buf, de.name); - - printf("%s %d\t%s\n", - (de.attr & ATTR_DIRECTORY) ? "" : " ", - de.fileSize, - name_buf); - } - - close(fd); -} - -int main(int argc, char *argv[]) -{ - if (argc < 2) - { - ls("."); - } - else - { - for (int i = 1; i < argc; i++) - { - ls(argv[i]); - } - } - exit(0); -} \ No newline at end of file diff --git a/src/user/mkdir.cc b/src/user/mkdir.cc deleted file mode 100644 index 6da8b49..0000000 --- a/src/user/mkdir.cc +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "user/user.h" - -int main(int argc, char* argv[]) -{ - if (argc < 2) - { - printf("Usage: mkdir ...\n"); - exit(1); - } - - for (int i = 1; i < argc; i++) - { - if (mkdir(argv[i]) < 0) - { - printf("mkdir: cannot create directory '%s'\n", argv[i]); - } - } - - exit(0); -} \ No newline at end of file diff --git a/src/user/mv.cc b/src/user/mv.cc deleted file mode 100644 index a196145..0000000 --- a/src/user/mv.cc +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" - -int main(int argc, char *argv[]) -{ - if (argc != 3) - { - printf("Usage: mv old new\n"); - exit(1); - } - - if (link(argv[1], argv[2]) < 0) - { - printf("mv: failed to link %s to %s\n", argv[1], argv[2]); - exit(1); - } - - if (unlink(argv[1]) < 0) - { - printf("mv: failed to unlink %s\n", argv[1]); - exit(1); - } - - exit(0); -} \ No newline at end of file diff --git a/src/user/rm.cc b/src/user/rm.cc deleted file mode 100644 index 4777ade..0000000 --- a/src/user/rm.cc +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" - -int main(int argc, char *argv[]) -{ - int i; - - if (argc < 2) - { - printf("Usage: rm files...\n"); - exit(1); - } - - for (i = 1; i < argc; i++) - { - if (unlink(argv[i]) < 0) - { - printf("rm: %s failed to delete\n", argv[i]); - exit(1); - } - } - exit(0); -} \ No newline at end of file diff --git a/src/user/sh.cc b/src/user/sh.cc deleted file mode 100644 index 47aad9e..0000000 --- a/src/user/sh.cc +++ /dev/null @@ -1,423 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "common/fcntl.h" -#include "drivers/uart_color.h" - -constexpr int MAX_ARGS = 10; -const char *WHITESPACE = " \t\r\n\v"; -const char *SYMBOLS = "<|>&;()"; - -void panic(const char *s) -{ - printf("shell panic: %s\n", s); - exit(1); -} - -int fork_or_panic() -{ - int pid = fork(); - if (pid == -1) - panic("fork"); - return pid; -} - -struct Command -{ - virtual ~Command() = default; - - virtual void run() = 0; -}; - -struct ExecCommand : public Command -{ - char *argv[MAX_ARGS]; - - ExecCommand() - { - memset(argv, 0, sizeof(argv)); - } - - void run() override - { - if (argv[0] == nullptr) - exit(1); - - exec(argv[0], argv); - - printf("exec %s failed\n", argv[0]); - exit(1); - } -}; - -struct RedirCommand : public Command -{ - Command *sub_cmd; - char *file; - char *efile; // file name end pointer (used by parser) - int mode; - int fd; - - RedirCommand(Command *c, char *f, char *ef, int m, int fd_in) - : sub_cmd(c), file(f), efile(ef), mode(m), fd(fd_in) {} - - ~RedirCommand() { delete sub_cmd; } - - void run() override - { - close(fd); - - int newfd = open(file, mode); - - if (newfd < 0) - { - printf("open %s failed\n", file); - exit(1); - } - - if (newfd != fd) - { - - if (dup(newfd) != fd) - { - printf("Redirection failed: could not move fd %d to %d\n", newfd, fd); - exit(1); - } - close(newfd); - } - - sub_cmd->run(); - } -}; - -struct PipeCommand : public Command -{ - Command *left; - Command *right; - - PipeCommand(Command *l, Command *r) : left(l), right(r) {} - ~PipeCommand() - { - delete left; - delete right; - } - - void run() override - { - int p[2]; - if (pipe(p) < 0) - panic("pipe"); - - if (fork_or_panic() == 0) - { - // Left child: write to pipe - close(1); // close stdout - dup(p[1]); // dup write-end to stdout - close(p[0]); - close(p[1]); - left->run(); - } - - if (fork_or_panic() == 0) - { - // Right child: read from pipe - close(0); // close stdin - dup(p[0]); // dup read-end to stdin - close(p[0]); - close(p[1]); - right->run(); - } - - close(p[0]); - close(p[1]); - wait(0); - wait(0); - exit(0); - } -}; - -struct ListCommand : public Command -{ - Command *left; - Command *right; - - ListCommand(Command *l, Command *r) : left(l), right(r) {} - ~ListCommand() - { - delete left; - delete right; - } - - void run() override - { - if (fork_or_panic() == 0) - { - left->run(); - } - wait(0); - right->run(); - } -}; - -struct BackCommand : public Command -{ - Command *sub_cmd; - - BackCommand(Command *c) : sub_cmd(c) {} - ~BackCommand() { delete sub_cmd; } - - void run() override - { - if (fork_or_panic() == 0) - { - sub_cmd->run(); - } - // Parent doesn't wait - exit(0); - } -}; - -class Parser -{ -public: - static Command *parse(char *s) - { - char *es = s + strlen(s); - Command *cmd = parse_line(&s, es); - peek(&s, es, ""); - if (s != es) - { - printf("leftovers: %s\n", s); - // panic("syntax"); // strict syntax check - } - terminate_strings(cmd); - return cmd; - } - -private: - // Helper: NUL-terminate strings found during parsing - static void terminate_strings(Command *cmd) - { - if (!cmd) - return; - } - - static char get_token(char **ps, char *es, char **q, char **eq) - { - char *s; - int ret; - - s = *ps; - while (s < es && strchr(WHITESPACE, *s)) - s++; - if (q) - *q = s; - ret = *s; - switch (*s) - { - case 0: - break; - case '|': - case '(': - case ')': - case ';': - case '&': - case '<': - s++; - break; - case '>': - s++; - if (*s == '>') - { - ret = '+'; - s++; - } - break; - default: - ret = 'a'; - while (s < es && !strchr(WHITESPACE, *s) && !strchr(SYMBOLS, *s)) - s++; - break; - } - if (eq) - *eq = s; - - while (s < es && strchr(WHITESPACE, *s)) - s++; - *ps = s; - return ret; - } - - static int peek(char **ps, char *es, const char *toks) - { - char *s = *ps; - while (s < es && strchr(WHITESPACE, *s)) - s++; - *ps = s; - return *s && strchr(toks, *s); - } - - // Recursive Descent Parsers - - static Command *parse_line(char **ps, char *es) - { - Command *cmd = parse_pipe(ps, es); - while (peek(ps, es, "&")) - { - get_token(ps, es, 0, 0); - cmd = new BackCommand(cmd); - } - if (peek(ps, es, ";")) - { - get_token(ps, es, 0, 0); - cmd = new ListCommand(cmd, parse_line(ps, es)); - } - return cmd; - } - - static Command *parse_pipe(char **ps, char *es) - { - Command *cmd = parse_exec(ps, es); - if (peek(ps, es, "|")) - { - get_token(ps, es, 0, 0); - cmd = new PipeCommand(cmd, parse_pipe(ps, es)); - } - return cmd; - } - - static Command *parse_exec(char **ps, char *es) - { - char *q, *eq; - int tok, argc; - ExecCommand *cmd = new ExecCommand(); - Command *ret = cmd; - - argc = 0; - ret = parse_redirs(ret, ps, es); - while (!peek(ps, es, "|)&;")) - { - if ((tok = get_token(ps, es, &q, &eq)) == 0) - break; - if (tok != 'a') - panic("syntax"); - - cmd->argv[argc] = q; - *eq = 0; // Temp - - argc++; - if (argc >= MAX_ARGS) - panic("too many args"); - ret = parse_redirs(ret, ps, es); - } - cmd->argv[argc] = 0; - return ret; - } - - static Command *parse_redirs(Command *cmd, char **ps, char *es) - { - int tok; - char *q, *eq; - - while (peek(ps, es, "<>")) - { - tok = get_token(ps, es, 0, 0); - if (get_token(ps, es, &q, &eq) != 'a') - panic("missing file for redirection"); - - *eq = 0; // Null terminate filename immediately - - switch (tok) - { - case '<': - cmd = new RedirCommand(cmd, q, eq, O_RDONLY, 0); - break; - case '>': - cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1); - break; - case '+': // >> - cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE, 1); // Append not fully supported in simple OS yet? - break; - } - } - return cmd; - } -}; - -int getcmd(char *buf, int nbuf) -{ - write(1, "$ ", 2); - memset(buf, 0, nbuf); - - int n = read(0, buf, nbuf - 1); - - if (n < 0) - return -1; - - buf[n] = 0; - return 0; -} - -int main() -{ - static char buf[100]; - - - printf(ANSI_GREEN "\n[Lume Shell] Welcome! \n" ANSI_RESET); - printf(ANSI_YELLOW "[Lume Shell] Start your journey of exploration!" ANSI_RESET); - printf("\n"); - - while (getcmd(buf, sizeof(buf)) >= 0) - { - int len = strlen(buf); - if (len > 0 && buf[len - 1] == '\n') - { - buf[len - 1] = 0; - } - - if (buf[0] == 'c' && buf[1] == 'd' && (buf[2] == ' ' || buf[2] == '\n' || buf[2] == 0)) - { - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = 0; - - char *path = buf + 3; - if (buf[2] == '\n' || buf[2] == 0) - { - printf("cd: argument missing\n"); - continue; - } - - if (chdir(path) < 0) - { - printf("cannot cd %s\n", path); - } - continue; - } - if (strcmp(buf, "shutdown") == 0 || strcmp(buf, "poweroff") == 0) - { - printf(ANSI_BLUE "System shutting down..." ANSI_RESET); - printf("\n"); - shutdown(); - - continue; - } - - if (fork_or_panic() == 0) - { - Command *cmd = Parser::parse(buf); - if (cmd) - { - cmd->run(); - delete cmd; - } - exit(0); - } - wait(0); - } - return 0; -} \ No newline at end of file diff --git a/src/user/touch.cc b/src/user/touch.cc deleted file mode 100644 index 2f9f9f6..0000000 --- a/src/user/touch.cc +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "user/user.h" -#include "common/fcntl.h" - -int main(int argc, char *argv[]) -{ - int i, fd; - - if (argc < 2) - { - printf("Usage: touch files...\n"); - exit(1); - } - - for (i = 1; i < argc; i++) - { - fd = open(argv[i], O_CREATE | O_RDWR); - if (fd < 0) - { - printf("touch: cannot touch %s\n", argv[i]); - exit(1); - } - close(fd); - } - exit(0); -} \ No newline at end of file diff --git a/src/user/user.ld b/src/user/user.ld deleted file mode 100644 index f0a4b27..0000000 --- a/src/user/user.ld +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -OUTPUT_ARCH( "riscv" ) -ENTRY( _start ) - -SECTIONS -{ - . = 0x0; - - .text : { - *(.text.entry) - *(.text .text.*) - } - - .rodata : { - . = ALIGN(16); - *(.srodata .srodata.*) - . = ALIGN(16); - *(.rodata .rodata.*) - } - - .data : { - . = ALIGN(16); - *(.sdata .sdata.*) - . = ALIGN(16); - *(.data .data.*) - } - - .bss : { - . = ALIGN(16); - *(.sbss .sbss.*) - . = ALIGN(16); - *(.bss .bss.*) - } -} \ No newline at end of file diff --git a/src/user/usys.S b/src/user/usys.S deleted file mode 100644 index 1e373d3..0000000 --- a/src/user/usys.S +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2026 Richard Qin - -#include "kernel/syscall.h" - -#define SYSCALL_NAME(name, sysname) \ - .global name; \ - name: \ - li a7, SYS_ ## sysname; \ - ecall; \ - ret - -SYSCALL_NAME(sys_openat, openat) -SYSCALL_NAME(sys_mknodat, mknodat) -SYSCALL_NAME(sys_mkdirat, mkdirat) -SYSCALL_NAME(sys_unlinkat, unlinkat) -SYSCALL_NAME(sys_linkat, linkat) -SYSCALL_NAME(sys_chdir, chdir) -SYSCALL_NAME(sys_dup, dup) -SYSCALL_NAME(sys_fstat, fstat) -SYSCALL_NAME(sys_read, read) -SYSCALL_NAME(sys_write, write) -SYSCALL_NAME(sys_close, close) -SYSCALL_NAME(sys_pipe2, pipe2) -SYSCALL_NAME(sys_clone, clone) -SYSCALL_NAME(sys_execve, execve) -SYSCALL_NAME(sys_wait4, wait4) -SYSCALL_NAME(sys_exit, exit) -SYSCALL_NAME(sys_getpid, getpid) -SYSCALL_NAME(sys_brk, brk) -SYSCALL_NAME(sys_kill, kill) -SYSCALL_NAME(sys_nanosleep, nanosleep) -SYSCALL_NAME(sys_reboot, reboot) -SYSCALL_NAME(sys_lseek, lseek) - -# === Custom / Debug Syscalls === -SYSCALL_NAME(sys_putc, putc) -SYSCALL_NAME(sys_disk_test, disk_test) \ No newline at end of file diff --git a/src/user/wc.cc b/src/user/wc.cc deleted file mode 100644 index fbe9735..0000000 --- a/src/user/wc.cc +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2026 Richard QIn - */ -#include "ulib/stdio.h" -#include "ulib/stdlib.h" -#include "ulib/string.h" -#include "user/user.h" -#include "common/fcntl.h" - -char buf[512]; - -void wc(int fd, char *name) -{ - int i, n; - int l, w, c, inword; - - l = w = c = 0; - inword = 0; - while ((n = read(fd, buf, sizeof(buf))) > 0) - { - for (i = 0; i < n; i++) - { - c++; - if (buf[i] == '\n') - l++; - if (strchr(" \r\t\n\v", buf[i])) - inword = 0; - else if (!inword) - { - w++; - inword = 1; - } - } - } - printf("%d %d %d %s\n", l, w, c, name); -} - -int main(int argc, char *argv[]) -{ - int fd, i; - - if (argc <= 1) - { - wc(0, ""); - exit(0); - } - - for (i = 1; i < argc; i++) - { - if ((fd = open(argv[i], O_RDONLY)) < 0) - { - printf("wc: cannot open %s\n", argv[i]); - exit(1); - } - wc(fd, argv[i]); - close(fd); - } - exit(0); -} \ No newline at end of file -- cgit v1.2.3