summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
commite90b72ec3082588b296956730bd2930cf8d5d671 (patch)
tree36ff6916af9b4176ea5a9662219d11e721f0b691 /src
parent1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff)
downloadlume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz
lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'src')
-rw-r--r--src/boot/entry.S47
-rw-r--r--src/drivers/plic.cc77
-rw-r--r--src/drivers/uart.cc204
-rw-r--r--src/drivers/virtio_dist.cc382
-rw-r--r--src/fs/fat32.cc806
-rw-r--r--src/fs/file.cc358
-rw-r--r--src/fs/fs.cc268
-rw-r--r--src/kernel/bio.cc139
-rw-r--r--src/kernel/config.cc13
-rw-r--r--src/kernel/cxx.cc78
-rw-r--r--src/kernel/fdt.cc273
-rw-r--r--src/kernel/initcode.S11
-rw-r--r--src/kernel/main.cc79
-rw-r--r--src/kernel/mm/pmm.cc305
-rw-r--r--src/kernel/mm/slab.cc259
-rw-r--r--src/kernel/mm/vm.cc459
-rw-r--r--src/kernel/proc/exec.cc260
-rw-r--r--src/kernel/proc/proc.cc654
-rw-r--r--src/kernel/proc/swtch.S37
-rw-r--r--src/kernel/sbi.cc52
-rw-r--r--src/kernel/spinlock.cc199
-rw-r--r--src/kernel/syscall.cc698
-rw-r--r--src/kernel/timer.cc66
-rw-r--r--src/kernel/trap/handler.cc217
-rw-r--r--src/kernel/trap/trampoline.S101
-rw-r--r--src/kernel/trap/trap.S90
-rw-r--r--src/lib/string.cc88
-rw-r--r--src/ulib/assert.c12
-rw-r--r--src/ulib/cxx.cc35
-rw-r--r--src/ulib/iostream.cpp12
-rw-r--r--src/ulib/stdio.c1056
-rw-r--r--src/ulib/stdlib.c543
-rw-r--r--src/ulib/string.c335
-rw-r--r--src/ulib/syscalls.c153
-rw-r--r--src/user/cat.cc52
-rw-r--r--src/user/cp.cc52
-rw-r--r--src/user/echo.cc26
-rw-r--r--src/user/entry.S12
-rw-r--r--src/user/grep.cc72
-rw-r--r--src/user/init.cc64
-rw-r--r--src/user/kill.cc27
-rw-r--r--src/user/ln.cc22
-rw-r--r--src/user/ls.cc116
-rw-r--r--src/user/mkdir.cc25
-rw-r--r--src/user/mv.cc30
-rw-r--r--src/user/rm.cc28
-rw-r--r--src/user/sh.cc423
-rw-r--r--src/user/touch.cc31
-rw-r--r--src/user/user.ld36
-rw-r--r--src/user/usys.S38
-rw-r--r--src/user/wc.cc60
51 files changed, 0 insertions, 9480 deletions
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<volatile uint32 *>(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<int>(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<int>(r_tp());
- return *REG32(PLIC_SCLAIM_ADDR(hart));
- }
-
- void complete(int irq)
- {
- int hart = static_cast<int>(r_tp());
- *REG32(PLIC_SCLAIM_ADDR(hart)) = static_cast<uint32>(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<volatile uint32 *>(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<struct VRingDesc *>(base_addr);
- disk.avail = reinterpret_cast<struct VRingAvail *>(base_addr + NUM_DESCS * 16);
- disk.used = reinterpret_cast<struct VRingUsed *>(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<uint64>(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<<k)] exactly corresponds to physical address + (1<<k)*PGSIZE
- struct Page *buddy = page + (1 << current_order);
-
- // Add the buddy to a lower-level linked list
- list_add(buddy, current_order);
- }
-
- // Mark as Occupied
- page->flags = PG_used;
- page->order = order; // Record the orders that have been assigned
- page->refcnt = 1;
-
- pmm_lock.release();
- return (void *)page_to_pa(page);
- }
- current_order++;
- }
- pmm_lock.release();
- Drivers::uart_puts("PMM: OOM alloc_pages\n");
- return nullptr;
- }
-
- void free_pages(void *pa, int order)
- {
- if (!pa)
- return;
- struct Page *page = pa_to_page((uint64)pa);
- if (!page)
- return;
- pmm_lock.acquire();
-
- if (!(page->flags & PG_used))
- {
- Drivers::uart_puts("PMM: Double free warning\n");
- pmm_lock.release();
- return;
- }
-
- // Mark as basic status
- page->flags = 0;
- page->refcnt = 0;
-
- // try merge
- uint64 page_idx = page - mem_map;
-
- while (order < MAX_ORDER - 1)
- {
- // calculate Buddy index: index ^ (1 << order)
- uint64 buddy_idx = page_idx ^ (1 << order);
- struct Page *buddy = &mem_map[buddy_idx];
-
- // Check if the Buddy can be merged:
- // 1. Must be within the memory range
- // 2. Must be free (flags == 0)
- // 3. Must be at the current order (to prevent merging already split small blocks)
- if (buddy_idx >= total_pages || (buddy->flags & PG_used) || (buddy->flags & PG_reserved) || buddy->order != order)
- {
- break;
- }
-
- // Can be merged!
- // Remove Buddy from the free list
- list_del(buddy, order);
-
- // Update the current block to the merged block
- // The starting address of the merged block is the smaller one between index and buddy_index
- if (buddy_idx < page_idx)
- {
- page = buddy;
- page_idx = buddy_idx;
- }
-
- order++;
- }
-
- // Insert into the final order linked list
- list_add(page, order);
-
- pmm_lock.release();
- }
-
- void *alloc_page()
- {
- void *p = alloc_pages(0);
- if (p)
- {
- memset(p, 0, PGSIZE);
- }
- return p;
- }
-
- void free_page(void *pa)
- {
- free_pages(pa, 0);
- }
-
- void print_free_lists()
- {
- // Debug print the number of free blocks at each level
- Drivers::uart_puts("PMM Stats: [ ");
- for (int i = 0; i < MAX_ORDER; i++)
- {
- int count = 0;
- struct Page *p = free_area[i];
- while (p)
- {
- count++;
- p = p->next;
- }
- if (count > 0)
- {
- Drivers::uart_puts("Order");
- // Drivers::uart_put_int(i);
- Drivers::uart_puts(":");
- // Drivers::uart_put_int(count);
- Drivers::uart_puts(" ");
- }
- }
- Drivers::uart_puts("]\n");
- }
-} // namespace PMM
diff --git a/src/kernel/mm/slab.cc b/src/kernel/mm/slab.cc
deleted file mode 100644
index 3bb6b1b..0000000
--- a/src/kernel/mm/slab.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/slab.h"
-#include "kernel/pmm.h"
-#include "kernel/spinlock.h"
-#include "kernel/riscv.h"
-#include "drivers/uart.h"
-#include "lib/string.h"
-
-#define PG_slab 0x04
-
-// Supported object size (must be a multiple of 8 and <= 2048)
-const uint64 kmalloc_sizes[] = {
- 16, 32, 64, 128, 256, 512, 1024, 2048};
-const int NUM_CACHES = 8;
-
-struct SlabHeader
-{
- struct SlabHeader *next; // Next slab in the linked list
- uint16 free_idx; // Index of the head of the free list (0xFFFF means none)
- uint16 used_count; // Number of allocated objects
- // Followed immediately by object data...
- // The free list of objects is embedded in the first 2 bytes of the object itself (stores the index of the next object)
- uint32 padding;
-};
-
-struct KmemCache
-{
- Spinlock lock;
- uint64 obj_size;
- uint64 obj_count_per_slab;
- struct SlabHeader *slab_list; // Slab list with free objects
- const char *name;
-};
-
-struct KmemCache caches[NUM_CACHES];
-
-// Virtual address -> struct Page*
-static struct Page *virt_to_page(void *ptr)
-{
- uint64 pa = (uint64)ptr;
- return PMM::pa_to_page(pa);
-}
-
-// Slab Implementation
-
-namespace Slab
-{
-
- void init()
- {
- for (int i = 0; i < NUM_CACHES; i++)
- {
- caches[i].lock.init("slab_lock");
- caches[i].obj_size = kmalloc_sizes[i];
- caches[i].name = "kmalloc";
-
- // Calculate how many objects can fit on a page
- // Excluding the overhead of the SlabHeader
- uint64 available = PGSIZE - sizeof(struct SlabHeader);
- caches[i].obj_count_per_slab = available / caches[i].obj_size;
- caches[i].slab_list = nullptr;
- }
- Drivers::uart_puts("[Slab] Initialized kmalloc caches.\n");
- }
-
- // Allocate a new slab page for the cache
- // Must hold cache->lock
- static struct SlabHeader *grow_cache(struct KmemCache *c)
- {
- void *p = PMM::alloc_page();
- if (!p)
- return nullptr;
-
- // Mark this page as a Slab page
- struct Page *page = virt_to_page(p);
- if (page)
- {
- page->flags |= PG_slab;
- int cache_idx = c - caches;
- page->order = (uint8)cache_idx;
- }
-
- struct SlabHeader *slab = (struct SlabHeader *)p;
- slab->next = nullptr;
- slab->used_count = 0;
- slab->free_idx = 0;
- slab->padding = 0;
-
- // Initialize the free list of objects
- // The starting position of each object stores the index of the next object
- // Starting position of the object data area
- char *base = (char *)(slab + 1);
-
- for (uint i = 0; i < c->obj_count_per_slab - 1; i++)
- {
- // The content of the i-th object is i+1
- uint16 *ptr = (uint16 *)(base + i * c->obj_size);
- *ptr = i + 1;
- }
- // The last object points to 0xFFFF
- uint16 *ptr = (uint16 *)(base + (c->obj_count_per_slab - 1) * c->obj_size);
- *ptr = 0xFFFF;
-
- return slab;
- }
-
- void *kmalloc(uint64 size)
- {
- if (size == 0)
- return nullptr;
-
- // Large objects go directly through PMM
- if (size > 2048)
- {
- // calculate order
- int order = 0;
- uint64 req = size;
- uint64 pages = (size + PGSIZE - 1) / PGSIZE;
- (void)req;
-
- // calculate order: 2^order >= pages
- while ((1UL << order) < pages)
- {
- order++;
- }
- if (order > MAX_ORDER)
- return nullptr;
-
- void *p = PMM::alloc_pages(order);
- // Here, page->flags defaults to PG_used, not PG_slab
- // kfree needs to be able to recognize it
- return p;
- }
-
- int idx = 0;
- while (idx < NUM_CACHES && kmalloc_sizes[idx] < size)
- {
- idx++;
- }
-
- struct KmemCache *c = &caches[idx];
- c->lock.acquire();
-
- if (!c->slab_list)
- {
- c->slab_list = grow_cache(c);
- if (!c->slab_list)
- {
- c->lock.release();
- return nullptr;
- }
- }
-
- struct SlabHeader *slab = c->slab_list;
-
- int obj_idx = slab->free_idx;
- char *base = (char *)(slab + 1);
- void *ptr = base + obj_idx * c->obj_size;
-
- uint16 *link = (uint16 *)ptr;
- slab->free_idx = *link;
- slab->used_count++;
-
- if (slab->free_idx == 0xFFFF)
- {
- if (slab->next)
- {
- c->slab_list = slab->next;
- slab->next = nullptr;
- }
- else
- {
- c->slab_list = nullptr;
- }
- }
-
- c->lock.release();
-
- memset(ptr, 0, size);
- return ptr;
- }
-
- void kfree(void *ptr)
- {
- if (!ptr)
- return;
-
- struct Page *page = virt_to_page(ptr);
- if (!page)
- return;
-
- if (!page || !(page->flags & PG_slab))
- {
- PMM::free_pages(ptr, page->order);
- return;
- }
-
- int cache_idx = page->order;
- if (cache_idx >= NUM_CACHES)
- {
- Drivers::uart_puts("Slab: Corrupted page metadata\n");
- return;
- }
-
- struct KmemCache *c = &caches[cache_idx];
- c->lock.acquire();
-
- struct SlabHeader *slab = (struct SlabHeader *)PGROUNDDOWN((uint64)ptr);
-
- if ((uint64)ptr < (uint64)(slab + 1) || (uint64)ptr >= (uint64)slab + PGSIZE)
- {
- Drivers::uart_puts("Slab: kfree invalid pointer\n");
- c->lock.release();
- return;
- }
-
- char *base = (char *)(slab + 1);
- int obj_idx = ((uint64)ptr - (uint64)base) / c->obj_size;
-
- uint16 *link = (uint16 *)ptr;
- *link = slab->free_idx;
- slab->free_idx = (uint16)obj_idx;
-
- slab->used_count--;
-
- if (slab->used_count == 0)
- {
- struct SlabHeader **pp = &c->slab_list;
- // bool found = false;
- while (*pp)
- {
- if (*pp == slab)
- {
- *pp = slab->next;
- // found = true;
- break;
- }
- pp = &(*pp)->next;
- }
-
- page->flags &= ~PG_slab;
- PMM::free_page(slab);
- }
- else
- {
-
- if (slab->used_count == c->obj_count_per_slab - 1)
- {
- slab->next = c->slab_list;
- c->slab_list = slab;
- }
- }
-
- c->lock.release();
- }
-} \ No newline at end of file
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc
deleted file mode 100644
index be2f2f2..0000000
--- a/src/kernel/mm/vm.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/mm.h"
-#include "kernel/pmm.h"
-#include "kernel/riscv.h"
-#include "common/types.h"
-#include "lib/string.h"
-#include "drivers/uart.h"
-#include "kernel/fdt.h"
-
-extern "C"
-{
- extern char kernel_end[];
- extern char trampoline[];
-}
-
-namespace VM
-{
-
- uint64 *kernel_pagetable;
-
- static void page_ref_inc(uint64 pa)
- {
- struct Page *p = PMM::pa_to_page(pa);
- if (p)
- {
- __atomic_add_fetch(&p->refcnt, 1, __ATOMIC_RELAXED);
- }
- }
-
- static bool page_ref_dec(uint64 pa)
- {
- struct Page *p = PMM::pa_to_page(pa);
- if (p)
- {
- if (__atomic_sub_fetch(&p->refcnt, 1, __ATOMIC_RELEASE) == 0)
- {
- return true;
- }
- }
- return false;
- }
-
- static uint64 *walk(uint64 *pagetable, uint64 va, int alloc)
- {
- if (va >= MAXVA)
- return nullptr;
-
- for (int level = 2; level > 0; level--)
- {
- uint64 *pte = &pagetable[PX(level, va)];
- if (*pte & PTE_V)
- {
- pagetable = (uint64 *)PTE2PA(*pte);
- }
- else
- {
- if (!alloc || (pagetable = (uint64 *)PMM::alloc_page()) == nullptr)
- return nullptr;
-
- memset(pagetable, 0, PGSIZE);
- *pte = PA2PTE(pagetable) | PTE_V;
- }
- }
- return &pagetable[PX(0, va)];
- }
-
- int mappages(uint64 *pagetable, uint64 va, uint64 size, uint64 pa, int perm)
- {
- uint64 a, last;
- uint64 *pte;
-
- if (size == 0)
- return -1;
-
- a = PGROUNDDOWN(va);
- last = PGROUNDDOWN(va + size - 1);
-
- for (;;)
- {
- if ((pte = walk(pagetable, a, 1)) == nullptr)
- return -1;
-
- if (*pte & PTE_V)
- {
- return -1;
- }
-
- *pte = PA2PTE(pa) | perm | PTE_V;
-
- if (a == last)
- break;
- a += PGSIZE;
- pa += PGSIZE;
- }
- return 0;
- }
-
- uint64 *uvmcreate()
- {
- uint64 *pagetable = (uint64 *)PMM::alloc_page();
- if (pagetable)
- {
- memset(pagetable, 0, PGSIZE);
-
- if (mappages(pagetable, TRAMPOLINE, PGSIZE, (uint64)trampoline, PTE_R | PTE_X) < 0)
- {
- PMM::free_page(pagetable);
- return nullptr;
- }
- }
- return pagetable;
- }
-
- void uvminit(uint64 *pagetable, uchar *src, uint64 sz)
- {
- char *mem;
-
- if (sz >= PGSIZE)
- {
- Drivers::uart_puts("uvminit: initcode too big!\n");
- return;
- }
-
- mem = (char *)PMM::alloc_page();
- memset(mem, 0, PGSIZE);
-
- mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W | PTE_R | PTE_X | PTE_U);
- memmove(mem, src, sz);
- }
-
- uint64 uvmalloc(uint64 *pagetable, uint64 oldsz, uint64 newsz, int xperm)
- {
- char *mem;
- uint64 a;
-
- if (newsz < oldsz)
- return oldsz;
-
- oldsz = PGROUNDUP(oldsz);
- for (a = oldsz; a < newsz; a += PGSIZE)
- {
- mem = (char *)PMM::alloc_page();
- if (mem == nullptr)
- {
- uvmdealloc(pagetable, a, oldsz);
- return 0;
- }
- memset(mem, 0, PGSIZE);
- if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R | PTE_U | xperm) != 0)
- {
- PMM::free_page(mem);
- uvmdealloc(pagetable, a, oldsz);
- return 0;
- }
- }
- return newsz;
- }
-
- uint64 uvmdealloc(uint64 *pagetable, uint64 oldsz, uint64 newsz)
- {
- if (newsz >= oldsz)
- return oldsz;
-
- if (PGROUNDUP(newsz) < PGROUNDUP(oldsz))
- {
- int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
- uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
- }
-
- return newsz;
- }
-
- void uvmunmap(uint64 *pagetable, uint64 va, uint64 npages, int do_free)
- {
- uint64 a;
- uint64 *pte;
-
- if ((va % PGSIZE) != 0)
- return;
-
- for (a = va; a < va + npages * PGSIZE; a += PGSIZE)
- {
- if ((pte = walk(pagetable, a, 0)) == nullptr)
- continue;
-
- if ((*pte & PTE_V) == 0)
- continue;
-
- if ((PTE_FLAGS(*pte) & (PTE_R | PTE_W | PTE_X)) == 0)
- {
- continue;
- }
-
- if (do_free)
- {
- uint64 pa = PTE2PA(*pte);
- if (page_ref_dec(pa))
- {
- PMM::free_page((void *)pa);
- }
- }
- *pte = 0;
- }
- }
-
- static void freewalk(uint64 *pagetable)
- {
- for (int i = 0; i < 512; i++)
- {
- uint64 pte = pagetable[i];
- if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0)
- {
- uint64 *child = (uint64 *)PTE2PA(pte);
- freewalk(child);
- pagetable[i] = 0;
- }
- }
- PMM::free_page(pagetable);
- }
-
- void uvmfree(uint64 *pagetable, uint64 sz)
- {
- if (sz > 0)
- uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1);
- freewalk(pagetable);
- }
-
- int uvmcopy(uint64 *oldpt, uint64 *newpt, uint64 sz)
- {
- uint64 *pte;
- uint64 pa, i;
- uint flags;
-
- for (i = 0; i < sz; i += PGSIZE)
- {
- if ((pte = walk(oldpt, i, 0)) == nullptr)
- continue;
- if ((*pte & PTE_V) == 0)
- continue;
-
- pa = PTE2PA(*pte);
- flags = PTE_FLAGS(*pte);
-
- if (flags & PTE_W)
- {
- flags &= ~PTE_W;
- flags |= PTE_COW;
- *pte = PA2PTE(pa) | flags;
- }
-
- if (mappages(newpt, i, PGSIZE, pa, flags) != 0)
- {
- return -1;
- }
-
- page_ref_inc(pa);
- }
-
- sfence_vma();
- return 0;
- }
-
- int handle_cow_fault(uint64 *pagetable, uint64 va);
-
- int copyout(uint64 *pagetable, uint64 dstva, char *src, uint64 len)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
-
- while (len > 0)
- {
- va0 = PGROUNDDOWN(dstva);
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- // Note: Maybe a bug
- if (*pte & PTE_COW)
- {
- if (handle_cow_fault(pagetable, va0) < 0)
- return -1;
- // Re-walk because handle_cow_fault replaced the page mapping
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
- }
-
- pa0 = PTE2PA(*pte);
- n = PGSIZE - (dstva - va0);
- if (n > len)
- n = len;
-
- memmove((void *)(pa0 + (dstva - va0)), src, n);
-
- len -= n;
- src += n;
- dstva = va0 + PGSIZE;
- }
- return 0;
- }
-
- int copyin(uint64 *pagetable, char *dst, uint64 srcva, uint64 len)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
-
- while (len > 0)
- {
- va0 = PGROUNDDOWN(srcva);
- pte = walk(pagetable, va0, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- pa0 = PTE2PA(*pte);
- n = PGSIZE - (srcva - va0);
- if (n > len)
- n = len;
-
- memmove(dst, (void *)(pa0 + (srcva - va0)), n);
-
- len -= n;
- dst += n;
- srcva = va0 + PGSIZE;
- }
- return 0;
- }
-
- int copyinstr(uint64 *pagetable, char *dst, uint64 srcva, uint64 max)
- {
- uint64 n, va0, pa0;
- uint64 *pte;
- int got_null = 0;
- uint64 len = 0;
-
- while (len < max)
- {
- va0 = PGROUNDDOWN(srcva);
- pte = walk(pagetable, va0, 0);
-
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- pa0 = PTE2PA(*pte);
-
- n = PGSIZE - (srcva - va0);
- if (n > max - len)
- n = max - len;
-
- char *p = (char *)(pa0 + (srcva - va0));
- while (n > 0)
- {
- if (*p == '\0')
- {
- *dst = '\0';
- got_null = 1;
- break;
- }
- *dst = *p;
- n--;
- srcva++;
- dst++;
- p++;
- len++;
- }
- if (got_null)
- break;
- }
-
- if (got_null)
- return 0;
-
- return -1;
- }
-
- int handle_cow_fault(uint64 *pagetable, uint64 va)
- {
- if (va >= MAXVA)
- return -1;
-
- uint64 *pte = walk(pagetable, va, 0);
- if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return -1;
-
- if ((*pte & PTE_COW) == 0)
- return -1;
-
- uint64 pa = PTE2PA(*pte);
- uint64 flags = PTE_FLAGS(*pte);
-
- char *mem = (char *)PMM::alloc_page();
- if (mem == nullptr)
- return -1;
-
- memmove(mem, (char *)pa, PGSIZE);
-
- uint64 new_flags = (flags | PTE_W) & ~PTE_COW;
- *pte = PA2PTE((uint64)mem) | new_flags | PTE_V;
-
- if (page_ref_dec(pa))
- {
- PMM::free_page((void *)pa);
- }
-
- sfence_vma();
- return 0;
- }
-
- static void kvmmap(uint64 va, uint64 pa, uint64 sz, int perm)
- {
- if (mappages(kernel_pagetable, va, sz, pa, perm) != 0)
- {
- Drivers::uart_puts("kvmmap: failed\n");
- while (1)
- ;
- }
- }
-
- void kvminit()
- {
- kernel_pagetable = uvmcreate();
-
- // 1. Map all device MMIO regions discovered by FDT
- for (int i = 0; i < g_devices.mmio_count; i++)
- {
- uint64 base = g_devices.mmio_regions[i].base;
- uint64 size = g_devices.mmio_regions[i].size;
- kvmmap(base, base, size, PTE_R | PTE_W);
- }
-
- // 2. Map Kernel Memory (PHYSTOP is now dynamic based on FDT)
- kvmmap(KERNBASE, KERNBASE, PHYSTOP - KERNBASE, PTE_R | PTE_W | PTE_X);
- }
-
- void kvminithart()
- {
- w_satp(MAKE_SATP(kernel_pagetable));
- sfence_vma();
- Drivers::uart_puts("[Boot] MMU ENABLED! Using virtual addresses.\n");
- }
-
- uint64 walkaddr(uint64 *pagetable, uint64 va)
- {
- uint64 *pte;
- uint64 pa;
-
- if (va >= MAXVA)
- return 0;
-
- pte = walk(pagetable, va, 0);
- if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
- return 0;
-
- pa = PTE2PA(*pte);
- return pa;
- }
-} \ No newline at end of file
diff --git a/src/kernel/proc/exec.cc b/src/kernel/proc/exec.cc
deleted file mode 100644
index 8d8c467..0000000
--- a/src/kernel/proc/exec.cc
+++ /dev/null
@@ -1,260 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "common/types.h"
-#include "kernel/riscv.h"
-#include "kernel/proc.h"
-#include "kernel/mm.h"
-#include "kernel/elf.h"
-#include "fs/fs.h"
-#include "lib/string.h"
-#include "drivers/uart.h"
-#include "kernel/trap.h"
-
-extern char trampoline[];
-
-// RAII: Page Table Resource Management
-class VmGuard
-{
-public:
- uint64 *pagetable = nullptr;
- uint64 sz = 0;
-
- VmGuard() : pagetable(VM::uvmcreate()) {}
-
- ~VmGuard()
- {
- if (pagetable)
- {
- VM::uvmfree(pagetable, sz);
- }
- }
-
- // Copying is prohibited
- VmGuard(const VmGuard &) = delete;
- VmGuard &operator=(const VmGuard &) = delete;
-
- // Submit resources: Ownership transfer, destructor no longer releases
- uint64 *commit()
- {
- uint64 *pt = pagetable;
- pagetable = nullptr;
- return pt;
- }
-};
-
-// RAII: Inode Lock Management
-class InodeGuard
-{
-public:
- Inode *ip;
- InodeGuard(Inode *i) : ip(i)
- {
- if (ip)
- VFS::ilock(ip);
- }
- ~InodeGuard()
- {
- if (ip)
- {
- VFS::iunlockput(ip); // Automatically unlock and release references
- }
- }
- // Copying is prohibited
- InodeGuard(const InodeGuard &) = delete;
- InodeGuard &operator=(const InodeGuard &) = delete;
-};
-
-// laod segment
-static int loadseg(uint64 *pagetable, uint64 va, Inode *ip, uint64 offset, uint64 sz)
-{
- for (uint64 i = 0; i < sz; i += PGSIZE)
- {
- uint64 pa = VM::walkaddr(pagetable, va + i);
- if (pa == 0)
- {
- Drivers::uart_puts("[Exec Debug] loadseg: walkaddr failed\n");
- return -1;
- }
-
- uint64 n = PGSIZE - (va + i) % PGSIZE;
- if (i + n > sz)
- n = sz - i;
-
- // Read physical address (isUser=0)
- if (ip->read((char *)(pa + (va + i) % PGSIZE), offset + i, n, 0) != (int)n)
- {
- Drivers::uart_puts("[Exec Debug] loadseg: read failed\n");
- return -1;
- }
- }
- return 0;
-}
-
-namespace Exec
-{
- int exec(char *path, char **argv)
- {
- // 1. Get Inode
- Inode *raw_ip = VFS::namei(path);
- if (!raw_ip)
- {
- Drivers::uart_puts("[Exec Debug] namei failed for path: ");
- Drivers::uart_puts(path);
- Drivers::uart_puts("\n");
- return -1;
- }
- InodeGuard iguard(raw_ip);
-
- // Get ELF head
- struct elfhdr elf;
- if (raw_ip->read((char *)&elf, 0, sizeof(elf), 0) != sizeof(elf))
- {
- Drivers::uart_puts("[Exec Debug] read elf header failed\n");
- return -1;
- }
- if (elf.magic != ELF_MAGIC)
- {
- Drivers::uart_puts("[Exec Debug] invalid elf magic\n");
- return -1;
- }
-
- // Create new pagetable
- VmGuard vm_guard;
- if (!vm_guard.pagetable)
- {
- Drivers::uart_puts("[Exec Debug] uvmcreate failed\n");
- return -1;
- }
-
- // Load Program Segment
- struct proghdr ph;
- for (int i = 0; i < elf.phnum; i++)
- {
- uint64 off = elf.phoff + i * sizeof(ph);
- if (raw_ip->read((char *)&ph, off, sizeof(ph), 0) != sizeof(ph))
- {
- Drivers::uart_puts("[Exec Debug] read proghdr failed\n");
- return -1;
- }
-
- if (ph.type != ELF_PROG_LOAD)
- continue;
- if (ph.memsz < ph.filesz)
- return -1;
- if (ph.vaddr + ph.memsz < ph.vaddr)
- return -1;
-
- uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, vm_guard.sz, ph.vaddr + ph.memsz, PTE_W | PTE_X | PTE_R | PTE_U);
- if (sz1 == 0)
- {
- Drivers::uart_puts("[Exec Debug] uvmalloc failed (segment)\n");
- return -1;
- }
- vm_guard.sz = sz1;
-
- if (loadseg(vm_guard.pagetable, ph.vaddr, raw_ip, ph.off, ph.filesz) < 0)
- return -1;
- }
-
- // Prepare user stack
- uint64 sz = PGROUNDUP(vm_guard.sz);
-
- const int stack_data_pages = 16;
- const int stack_total_pages = stack_data_pages + 1;
-
- uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, sz, sz + stack_total_pages * PGSIZE, PTE_W | PTE_R | PTE_U);
- if (sz1 == 0)
- {
- Drivers::uart_puts("[Exec Debug] uvmalloc failed (stack)\n");
- return -1;
- }
- vm_guard.sz = sz1;
-
- VM::uvmunmap(vm_guard.pagetable, sz, 1, 0);
-
- uint64 sp = sz1;
- uint64 stackbase = sp - stack_data_pages * PGSIZE;
- uint64 ustack[32];
- uint64 argc = 0;
-
- // Push parameter string
- for (; argv[argc]; argc++)
- {
- if (argc >= 31)
- return -1;
- sp -= strlen(argv[argc]) + 1;
- sp -= sp % 16;
- if (sp < stackbase)
- {
- Drivers::uart_puts("[Exec Debug] stack overflow (args)\n");
- return -1;
- }
-
- if (VM::copyout(vm_guard.pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
- {
- Drivers::uart_puts("[Exec Debug] copyout arg string failed\n");
- return -1;
- }
- ustack[argc] = sp;
- }
- ustack[argc] = 0;
-
- // Push into parameter array
- sp -= (argc + 1) * sizeof(uint64);
- sp -= sp % 16;
- if (sp < stackbase)
- {
- Drivers::uart_puts("[Exec Debug] stack overflow (argv array)\n");
- return -1;
- }
- if (VM::copyout(vm_guard.pagetable, sp, (char *)ustack, (argc + 1) * sizeof(uint64)) < 0)
- {
- Drivers::uart_puts("[Exec Debug] copyout argv array failed\n");
- return -1;
- }
-
- // Commit Changes
- struct Proc *p = myproc();
- if (VM::mappages(vm_guard.pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0)
- {
- Drivers::uart_puts("[Exec Debug] mappages TRAPFRAME failed\n");
- return -1;
- }
-
- uint64 oldsz = p->sz;
- uint64 *oldpagetable = p->pagetable;
-
- p->tf->a0 = argc;
- p->tf->a1 = sp;
- p->tf->sp = sp;
- p->tf->epc = elf.entry;
-
- char *s = path, *last = path;
- while (*s)
- {
- if (*s == '/')
- last = s + 1;
- s++;
- }
-
- size_t len = 0;
- while (last[len] && len < sizeof(p->name) - 1)
- {
- p->name[len] = last[len];
- len++;
- }
- p->name[len] = '\0';
-
- // change pagetable
- p->pagetable = vm_guard.commit();
- p->sz = vm_guard.sz;
-
- // release old pagetable
- VM::uvmfree(oldpagetable, oldsz);
- asm volatile("fence.i");
-
- return 0; // iguard unlocks and releases IP upon destruction
- }
-} \ No newline at end of file
diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc
deleted file mode 100644
index 3923fe8..0000000
--- a/src/kernel/proc/proc.cc
+++ /dev/null
@@ -1,654 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/proc.h"
-#include "kernel/proc_def.h"
-#include "kernel/runqueue.h"
-#include "kernel/cpu.h"
-#include "kernel/spinlock.h"
-#include "kernel/pmm.h"
-#include "kernel/mm.h"
-#include "kernel/trap.h"
-#include "kernel/riscv.h"
-#include "kernel/slab.h"
-#include "drivers/uart.h"
-#include "fs/fs.h"
-#include "fs/file.h"
-#include "lib/string.h"
-
-// #define NPROC 64
-#define NCPU 8
-
-extern "C" void swtch(struct Context *old_ctx, struct Context *new_ctx);
-extern char uservec[], trampoline[];
-extern "C" void usertrap();
-extern "C" void userret(uint64, uint64);
-extern char initcode_start[], initcode_end[];
-
-// struct Proc procs[NPROC];
-struct Proc *proc_list_head = nullptr;
-struct Proc *initproc = nullptr;
-struct Spinlock proc_mem_lock;
-struct cpu cpus[NCPU];
-struct RunQueue runqueues[NCPU];
-
-
-static int nextpid = 1;
-
-
-struct cpu *mycpu()
-{
- int id = r_tp();
- return &cpus[id];
-}
-
-
-void RunQueue::init(const char *name)
-{
- lock.init(name);
- count = 0;
- for (int i = 0; i < N_PRIO; i++)
- {
- heads[i] = nullptr;
- tails[i] = nullptr;
- }
-}
-
-void RunQueue::enqueue(struct Proc *p)
-{
- if (p->priority < 0 || p->priority >= N_PRIO)
- p->priority = PRIO_MIN;
- p->next = nullptr;
- if (heads[p->priority] == nullptr)
- {
- heads[p->priority] = p;
- tails[p->priority] = p;
- }
- else
- {
- tails[p->priority]->next = p;
- tails[p->priority] = p;
- }
- count++;
-}
-
-struct Proc *RunQueue::dequeue()
-{
- for (int i = 0; i < N_PRIO; i++)
- {
- if (heads[i])
- {
- struct Proc *p = heads[i];
- heads[i] = p->next;
- if (!heads[i])
- tails[i] = nullptr;
- p->next = nullptr;
- count--;
- return p;
- }
- }
- return nullptr;
-}
-
-struct Proc *RunQueue::steal()
-{
- for (int i = N_PRIO - 1; i >= 0; i--)
- {
- if (heads[i])
- {
- struct Proc *p = heads[i];
- heads[i] = p->next;
- if (!heads[i])
- tails[i] = nullptr;
- p->next = nullptr;
- count--;
- return p;
- }
- }
- return nullptr;
-}
-
-// Trap Return Functions
-
-void usertrapret()
-{
- struct Proc *p = myproc();
-
- intr_off();
-
- // Set stvec to point to uservec in the trampoline
- // When an interrupt occurs in user mode, the CPU will jump here
- uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline);
- w_stvec(trampoline_uservec);
-
- // Fill in the Trapframe, used when uservec saves the kernel state
- p->tf->kernel_satp = r_satp();
- p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
- p->tf->kernel_trap = (uint64)usertrap;
- p->tf->kernel_hartid = r_tp();
-
- // Set SSTATUS
- // SPP = 0 (return to User Mode)
- // SPIE = 1 (enable interrupts)
- unsigned long x = r_sstatus();
- x &= ~SSTATUS_SPP;
- x |= SSTATUS_SPIE;
- w_sstatus(x);
-
- // Set SEPC to the user program counter
- w_sepc(p->tf->epc);
-
- // Prepare user page table SATP
- uint64 satp = MAKE_SATP(p->pagetable);
-
- // Calculate the virtual address of userret in the trampoline
- uint64 fn = TRAMPOLINE + ((uint64)userret - (uint64)trampoline);
-
- // Jump to userret, with parameters being the TRAPFRAME address and the user page table SATP
- ((void (*)(uint64, uint64))fn)(TRAPFRAME, satp);
-}
-
-
-void forkret()
-{
-
- struct cpu *c = mycpu();
- c->runqueue->lock.release();
-
- // Debug
- // Drivers::uart_puts("[Proc] forkret: jumping to user.\n");
-
- // Enter user mode
- usertrapret();
-}
-
-// ProcManager Implementation
-
-static Proc *allocproc()
-{
- struct Proc *p;
- proc_mem_lock.acquire();
-
- p = (struct Proc *)Slab::kmalloc(sizeof(struct Proc));
-
- if (!p)
- {
- proc_mem_lock.release();
- return 0;
- }
-
- memset(p, 0, sizeof(struct Proc));
-
- p->all_next = proc_list_head;
- p->all_prev = nullptr;
- if (proc_list_head)
- proc_list_head->all_prev = p;
- proc_list_head = p;
-
-
- p->state = USED;
- p->pid = nextpid++;
- p->priority = 0;
- p->killed = 0;
- p->cpu = mycpu();
- p->cwd = nullptr;
- for (int i = 0; i < NOFILE; i++)
- p->ofile[i] = nullptr;
-
- if ((p->tf = (struct Trapframe *)PMM::alloc_page()) == 0)
- {
- p->state = UNUSED;
- if (p->all_next)
- p->all_next->all_prev = p->all_prev;
- if (p->all_prev)
- p->all_prev->all_next = p->all_next;
- if (p == proc_list_head)
- proc_list_head = p->all_next;
- Slab::kfree(p);
- proc_mem_lock.release();
- return 0;
- }
-
- if ((p->kstack = PMM::alloc_page()) == 0)
- {
- PMM::free_page(p->tf);
- p->state = UNUSED;
- if (p->all_next)
- p->all_next->all_prev = p->all_prev;
- if (p->all_prev)
- p->all_prev->all_next = p->all_next;
- if (p == proc_list_head)
- proc_list_head = p->all_next;
- Slab::kfree(p);
-
- proc_mem_lock.release();
- return 0;
- }
- memset(p->kstack, 0, PGSIZE);
-
- memset(&p->context, 0, sizeof(p->context));
-
- // Set the context so that the next time this process is scheduled, it starts executing directly from forkret
- p->context.ra = (uint64)forkret;
- p->context.sp = (uint64)p->kstack + PGSIZE;
- return p;
-}
-
-static void freeproc(struct Proc *p)
-{
- if (p->tf)
- PMM::free_page(p->tf);
- p->tf = 0;
- if (p->kstack)
- PMM::free_page(p->kstack);
- p->kstack = 0;
- if (p->pagetable)
- VM::uvmfree(p->pagetable, p->sz);
- for (int i = 0; i < NOFILE; i++)
- {
- if (p->ofile[i])
- {
- FileTable::close(p->ofile[i]);
- p->ofile[i] = nullptr;
- }
- }
- if (p->cwd)
- {
- VFS::iput(p->cwd);
- p->cwd = nullptr;
- }
-
- if (p->all_prev)
- p->all_prev->all_next = p->all_next;
- else
- proc_list_head = p->all_next;
-
- if (p->all_next)
- p->all_next->all_prev = p->all_prev;
-
- Slab::kfree(p);
-}
-
-int fork()
-{
- struct Proc *np;
- struct Proc *p = myproc();
-
- if ((np = allocproc()) == 0)
- return -1;
-
- np->pagetable = VM::uvmcreate();
- np->sz = p->sz;
- if (VM::uvmcopy(p->pagetable, np->pagetable, p->sz) < 0)
- {
- freeproc(np);
- proc_mem_lock.release();
- return -1;
- }
-
-
- if (VM::mappages(np->pagetable, TRAPFRAME, PGSIZE, (uint64)np->tf, PTE_R | PTE_W) < 0)
- {
- freeproc(np);
- proc_mem_lock.release();
- return -1;
- }
-
- *(np->tf) = *(p->tf);
- np->tf->a0 = 0;
- strcpy(np->name, p->name);
- np->parent = p;
- np->priority = p->priority;
-
- for (int i = 0; i < NOFILE; i++)
- {
- if (p->ofile[i])
- {
- np->ofile[i] = FileTable::dup(p->ofile[i]);
- }
- }
-
- if (p->cwd)
- {
- np->cwd = VFS::idup(p->cwd);
- }
-
- proc_mem_lock.release();
-
- struct cpu *c = mycpu();
- c->runqueue->lock.acquire();
- np->state = RUNNABLE;
- c->runqueue->enqueue(np);
- c->runqueue->lock.release();
-
- return np->pid;
-}
-
-namespace ProcManager
-{
-
- void init()
- {
- proc_mem_lock.init("proc_mem");
-
- proc_list_head = nullptr;
-
- for (int i = 0; i < NCPU; i++)
- {
- cpus[i].runqueue = &runqueues[i];
- cpus[i].runqueue->init("runqueue");
- }
- }
-
- void scheduler()
- {
- struct Proc *p;
- struct cpu *c = mycpu();
- c->proc = 0;
- Drivers::uart_puts("[Proc] Scheduler started (Per-CPU).\n");
-
- for (;;)
- {
- intr_on();
-
- // Get from the local queue
- c->runqueue->lock.acquire();
- p = c->runqueue->dequeue();
- c->runqueue->lock.release();
-
- // Work Stealing
- if (!p)
- {
- for (int i = 0; i < NCPU; i++)
- {
- if ((uint64)i == r_tp())
- continue;
-
- struct cpu *victim = &cpus[i];
- victim->runqueue->lock.acquire();
- if (victim->runqueue->count > 0)
- p = victim->runqueue->steal();
- victim->runqueue->lock.release();
- if (p)
- break;
- }
- }
-
- if (p)
- {
- p->state = RUNNING;
- c->proc = p;
-
- c->runqueue->lock.acquire();
- swtch(&c->context, &p->context);
- c->runqueue->lock.release();
-
- c->proc = 0;
- }
- }
- }
-
- void yield()
- {
- struct Proc *p = myproc();
- struct cpu *c = mycpu();
- c->runqueue->lock.acquire();
- if (p && p->state == RUNNING)
- {
- p->state = RUNNABLE;
- if (p->priority < PRIO_MIN)
- p->priority++;
- c->runqueue->enqueue(p);
- swtch(&p->context, &c->context);
- }
- c->runqueue->lock.release();
- }
-
- void user_init()
- {
- struct Proc *p = allocproc();
- if (!p)
- return;
-
- initproc = p;
-
- p->pagetable = VM::uvmcreate();
-
- uint64 initcode_sz = initcode_end - initcode_start;
- Drivers::uart_puts("[Proc] initcode size: ");
- Drivers::uart_put_int(initcode_sz);
- Drivers::uart_puts(" bytes\n");
-
- uint64 code_pages = PGROUNDUP(initcode_sz) / PGSIZE;
-
- for (uint64 i = 0; i < code_pages; i++)
- {
- void *mem = PMM::alloc_page();
- if (!mem)
- {
- Drivers::uart_puts("user_init: out of memory for code\n");
- return;
- }
- memset(mem, 0, PGSIZE);
-
- uint64 src_offset = i * PGSIZE;
- uint64 copy_len = PGSIZE;
- if (src_offset + copy_len > initcode_sz)
- {
- copy_len = initcode_sz - src_offset;
- }
- memmove(mem, (void *)(initcode_start + src_offset), copy_len);
-
- if (VM::mappages(p->pagetable, i * PGSIZE, PGSIZE, (uint64)mem, PTE_R | PTE_W | PTE_X | PTE_U) < 0)
- {
- Drivers::uart_puts("user_init: mappages code failed\n");
- return;
- }
- }
-
- uint64 stack_va = (code_pages + 1) * PGSIZE;
-
- void *stack = PMM::alloc_page();
- if (!stack)
- return;
- memset(stack, 0, PGSIZE);
-
- if (VM::mappages(p->pagetable, stack_va, PGSIZE, (uint64)stack, PTE_R | PTE_W | PTE_U) < 0)
- return;
-
- if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0)
- return;
-
- p->tf->epc = 0;
- p->tf->sp = stack_va + PGSIZE;
- p->sz = stack_va + PGSIZE;
- strcpy(p->name, "initcode");
-
- p->cwd = nullptr;
-
- proc_mem_lock.release();
-
- struct cpu *c = &cpus[0];
- c->runqueue->lock.acquire();
- p->state = RUNNABLE;
- c->runqueue->enqueue(p);
- c->runqueue->lock.release();
-
- Drivers::uart_puts("[Proc] user_init success. PID: 1\n");
- asm volatile("fence.i");
- }
-
- void sleep(void *chan, Spinlock *lk)
- {
- struct Proc *p = myproc();
- struct cpu *c = mycpu();
-
- if (lk && lk != &proc_mem_lock)
- lk->release();
-
- c->runqueue->lock.acquire();
- p->chan = chan;
- p->state = SLEEPING;
- swtch(&p->context, &c->context);
- p->chan = 0;
- c->runqueue->lock.release();
-
- if (lk && lk != &proc_mem_lock)
- lk->acquire();
- }
-
- void wakeup(void *chan)
- {
- for (struct Proc *p = proc_list_head; p != nullptr; p = p->all_next)
- {
- if (p->state == SLEEPING && p->chan == chan)
- {
- struct cpu *c = mycpu();
- c->runqueue->lock.acquire();
- p->state = RUNNABLE;
- c->runqueue->enqueue(p);
- c->runqueue->lock.release();
- }
- }
- }
-
- void exit(int status)
- {
- struct Proc *p = myproc();
- if (p == initproc)
- while (1)
- ;
-
- wakeup(p->parent);
-
- proc_mem_lock.acquire();
-
- for (struct Proc *pp = proc_list_head; pp != nullptr; pp = pp->all_next)
- {
- if (pp->parent == p)
- {
- pp->parent = initproc;
- wakeup(initproc);
- }
- }
-
- proc_mem_lock.release();
-
- p->xstate = status;
-
- struct cpu *c = mycpu();
- c->runqueue->lock.acquire();
- p->state = ZOMBIE;
- swtch(&p->context, &c->context);
- while (1)
- ;
- }
-
- int wait(uint64 addr)
- {
-
- struct Proc *np;
- int havekids, pid;
- struct Proc *p = myproc();
- for (;;)
- {
- havekids = 0;
- proc_mem_lock.acquire();
-
- for (np = proc_list_head; np != nullptr; np = np->all_next)
- {
- if (np->parent == p)
- {
- havekids = 1;
- if (np->state == ZOMBIE)
- {
-
- struct cpu *child_cpu = np->cpu;
- if (child_cpu)
- {
- proc_mem_lock.release();
- child_cpu->runqueue->lock.acquire();
- child_cpu->runqueue->lock.release();
- proc_mem_lock.acquire();
- }
-
- pid = np->pid;
- if (addr != 0 && VM::copyout(p->pagetable, addr, (char *)&np->xstate, sizeof(np->xstate)) < 0)
- {
- proc_mem_lock.release();
- return -1;
- }
- freeproc(np);
- proc_mem_lock.release();
- return pid;
- }
- }
- }
- proc_mem_lock.release();
-
- if (!havekids || p->state == ZOMBIE)
- return -1;
- sleep(p, &proc_mem_lock);
- }
- }
-
- int kill(int pid)
- {
- Proc* p;
- proc_mem_lock.acquire();
- for (p = proc_list_head; p != nullptr; p = p->all_next)
- {
- if (p->pid == pid)
- {
- p->killed = 1;
-
- if (p->state == SLEEPING)
- {
- p->state = RUNNABLE;
-
- struct cpu *c = mycpu();
- c->runqueue->lock.acquire();
- c->runqueue->enqueue(p);
- c->runqueue->lock.release();
- }
-
- proc_mem_lock.release();
- return 0;
- }
- }
- proc_mem_lock.release();
- return -1;
- }
-
- int growproc(int n)
- {
- uint64 sz;
- struct Proc *p = myproc();
-
- sz = p->sz;
-
- if (n > 0)
- {
- // Call VM::uvmalloc to allocate memory
- // Parameters: page table, old size, new size, permissions (PTE_W)
- if ((sz = VM::uvmalloc(p->pagetable, sz, sz + n, PTE_W | PTE_R | PTE_U)) == 0)
- {
- return -1;
- }
- }
- else if (n < 0)
- {
- sz = VM::uvmdealloc(p->pagetable, sz, sz + n);
- }
-
- p->sz = sz;
- return 0;
- }
-
- void create_kernel_thread(void (*func)(), const char *name)
- {
- (void)func;
- (void)name;
- }
-} \ No newline at end of file
diff --git a/src/kernel/proc/swtch.S b/src/kernel/proc/swtch.S
deleted file mode 100644
index d55c03e..0000000
--- a/src/kernel/proc/swtch.S
+++ /dev/null
@@ -1,37 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2026 Richard Qin
-
-.global swtch
-
-swtch:
- sd ra, 0(a0)
- sd sp, 8(a0)
- sd s0, 16(a0)
- sd s1, 24(a0)
- sd s2, 32(a0)
- sd s3, 40(a0)
- sd s4, 48(a0)
- sd s5, 56(a0)
- sd s6, 64(a0)
- sd s7, 72(a0)
- sd s8, 80(a0)
- sd s9, 88(a0)
- sd s10, 96(a0)
- sd s11, 104(a0)
-
- ld ra, 0(a1)
- ld sp, 8(a1)
- ld s0, 16(a1)
- ld s1, 24(a1)
- ld s2, 32(a1)
- ld s3, 40(a1)
- ld s4, 48(a1)
- ld s5, 56(a1)
- ld s6, 64(a1)
- ld s7, 72(a1)
- ld s8, 80(a1)
- ld s9, 88(a1)
- ld s10, 96(a1)
- ld s11, 104(a1)
-
- ret
diff --git a/src/kernel/sbi.cc b/src/kernel/sbi.cc
deleted file mode 100644
index 5ae7edb..0000000
--- a/src/kernel/sbi.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "common/types.h"
-#include "kernel/sbi.h"
-
-namespace SBI
-{
- struct sbiret
- {
- long error;
- long value;
- };
-
- struct sbiret sbi_call(int ext, int fid, uint64 arg0, uint64 arg1, uint64 arg2)
- {
- struct sbiret ret;
- register uint64 a0 asm("a0") = arg0;
- register uint64 a1 asm("a1") = arg1;
- register uint64 a2 asm("a2") = arg2;
- register uint64 a6 asm("a6") = fid;
- register uint64 a7 asm("a7") = ext;
-
- asm volatile(
- "ecall"
- : "=r"(a0), "=r"(a1)
- : "r"(a0), "r"(a1), "r"(a2), "r"(a6), "r"(a7)
- : "memory");
- ret.error = a0;
- ret.value = a1;
- return ret;
- }
-
- void set_timer(uint64 stime_value)
- {
- sbi_call(0x54494D45, 0, stime_value, 0, 0);
- }
-
- void sbi_shutdown()
- {
- sbi_call(0x53525354, 0, 0, 0, 0);
- sbi_call(0x08, 0, 0, 0, 0);
- while (1)
- ;
- }
-
- void sbi_reboot()
- {
- sbi_call(SBI_EID_SRST, SBI_FID_SRST_RESET, SBI_SRST_TYPE_COLD_REBOOT, SBI_SRST_REASON_NONE, 0);
- }
-} \ No newline at end of file
diff --git a/src/kernel/spinlock.cc b/src/kernel/spinlock.cc
deleted file mode 100644
index aadce21..0000000
--- a/src/kernel/spinlock.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/spinlock.h"
-#include "kernel/riscv.h"
-#include "kernel/cpu.h"
-#include "kernel/proc_def.h"
-#include "drivers/uart.h"
-
-extern struct cpu cpus[];
-
-namespace ProcManager
-{
- void sleep(void *chan, Spinlock *lk);
- void wakeup(void *chan);
-}
-
-// Interrupt Depth Management
-void push_off(void);
-void pop_off(void);
-
-// // Get the pointer of the current CPU
-// // Depends on r_tp() in riscv.h to read the tp register
-// struct cpu *mycpu()
-// {
-// int id = r_tp();
-// return &cpus[id];
-// }
-
-// Get the current process
-// Must be called with interrupts disabled, or read atomically in a safe manner
-struct Proc *myproc()
-{
- push_off();
- struct cpu *c = mycpu();
- struct Proc *p = c->proc;
- pop_off();
- return p;
-}
-
-// Spinlock Implementation
-
-void Spinlock::init(const char *lock_name)
-{
- name = lock_name;
- locked = 0;
- cpu = nullptr;
-}
-
-void Spinlock::acquire()
-{
- push_off(); // Disable interrupts: prevent deadlocks (interrupt handler requests a lock that is already held)
-
- if (holding())
- {
- Drivers::uart_puts("panic: recursive acquire ");
- Drivers::uart_puts(name);
- Drivers::uart_puts("\n");
- while (1)
- ;
- }
-
- // Atomic Exchange
- // __ATOMIC_ACQUIRE: Ensures that reads and writes after the acquire are not reordered before the acquire
- while (__atomic_exchange_n(&locked, 1, __ATOMIC_ACQUIRE))
- {
- // Busy-wait (Spinning)
- // Optimization: Read-only, no writes, reducing cache coherence traffic
- while (__atomic_load_n(&locked, __ATOMIC_RELAXED) == 1)
- {
- asm volatile("nop"); // RISC-V indicates that the CPU is in a spin state
- }
- }
-
- // Record holder
- cpu = mycpu();
-}
-
-void Spinlock::release()
-{
- if (!holding())
- {
- Drivers::uart_puts("panic: release not holding\n");
- while (1)
- ;
- }
-
- cpu = nullptr;
-
- // Atomic Store
- // __ATOMIC_RELEASE: Ensures all reads and writes before the Release are completed
- __atomic_store_n(&locked, 0, __ATOMIC_RELEASE);
-
- pop_off();
-}
-
-// Check if the current CPU holds the lock
-bool Spinlock::holding()
-{
- // Interrupt checks must be disabled, otherwise a process switch may occur causing CPU fluctuations.
- int r;
- push_off();
- r = (locked && cpu == mycpu());
- pop_off();
- return r;
-}
-
-
-// Mutex Implementation (Sleep Locks)
-
-void Mutex::init(const char *lock_name)
-{
- name = lock_name;
- locked = 0;
- pid = 0;
- lk.init("mutex_internal");
-}
-
-void Mutex::acquire()
-{
- lk.acquire(); // Acquire the internal lock to protect the locked field
-
- while (locked)
- {
- // Lock is held, preparing to sleep
- // Atomicity contract of sleep():
- // 1. Mark the current process as SLEEPING
- // 2. Release lk (so others can operate on locked)
- // 3. Switch CPU (context switch)
- // 4. After being woken up, reacquire the lk lock and return
- ProcManager::sleep(this, &lk);
- }
-
- locked = 1;
- pid = myproc()->pid;
-
- lk.release();
-}
-
-void Mutex::release()
-{
- lk.acquire();
-
- locked = 0;
- pid = 0;
-
- // Wake up all processes sleeping on this lock (chan = this)
- ProcManager::wakeup(this);
-
- lk.release();
-}
-
-bool Mutex::holding()
-{
- lk.acquire(); // Must use a lock when reading to prevent race conditions.
- bool r = locked && (pid == myproc()->pid);
- lk.release();
- return r;
-}
-
-// Interrupt Depth Management
-
-void push_off(void)
-{
- int old = intr_get();
- intr_off();
-
- struct cpu *c = mycpu();
-
- if (c->noff == 0)
- c->intena = old;
-
- c->noff += 1;
-}
-
-void pop_off(void)
-{
- struct cpu *c = mycpu();
-
- if (intr_get())
- {
- Drivers::uart_puts("panic: pop_off - interruptible\n");
- while (1)
- ;
- }
- if (c->noff < 1)
- {
- Drivers::uart_puts("panic: pop_off count\n");
- while (1)
- ;
- }
-
- c->noff -= 1;
-
- // An interrupt is only truly enabled when the nesting level returns to zero and the outermost layer allows interrupts.
- if (c->noff == 0 && c->intena)
- intr_on();
-} \ No newline at end of file
diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc
deleted file mode 100644
index 0979c24..0000000
--- a/src/kernel/syscall.cc
+++ /dev/null
@@ -1,698 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard Qin
- */
-#include "kernel/syscall.h"
-#include "common/types.h"
-#include "common/fcntl.h"
-#include "kernel/proc.h"
-#include "kernel/riscv.h"
-#include "drivers/uart.h"
-#include "drivers/virtio.h"
-#include "kernel/timer.h"
-#include "kernel/mm.h"
-#include "kernel/trap.h"
-#include "kernel/slab.h"
-#include "kernel/sbi.h"
-#include "fs/fat32.h"
-#include "fs/file.h"
-#include "lib/string.h"
-#include "lib/errno.h"
-
-extern "C++" int fork();
-namespace Exec
-{
- int exec(char *path, char **argv);
-}
-
-namespace ProcManager
-{
- void exit(int status);
- int wait(uint64_t addr);
-}
-
-static uint64_t argraw(int n)
-{
- Proc *p = myproc();
- switch (n)
- {
- case 0:
- return p->tf->a0;
- case 1:
- return p->tf->a1;
- case 2:
- return p->tf->a2;
- case 3:
- return p->tf->a3;
- case 4:
- return p->tf->a4;
- case 5:
- return p->tf->a5;
- default:
- return static_cast<uint64_t>(-1);
- }
-}
-
-static int argint(int n, int *ip)
-{
- *ip = static_cast<int>(argraw(n));
- return 0;
-}
-
-static int argstr(int n, char *buf, int max)
-{
- uint64 addr = argraw(n);
- return VM::copyinstr(myproc()->pagetable, buf, addr, max);
-}
-
-struct KernelArgv
-{
- static const int MAX_ARGS = 32;
- static const int MAX_ARG_LEN = 128;
- char *args[MAX_ARGS];
-
- KernelArgv() { memset(args, 0, sizeof(args)); }
- ~KernelArgv()
- {
- for (int i = 0; i < MAX_ARGS; i++)
- if (args[i])
- {
- Slab::kfree(args[i]);
- args[i] = nullptr;
- }
- }
- KernelArgv(const KernelArgv &) = delete;
- KernelArgv &operator=(const KernelArgv &) = delete;
-};
-
-static int fdalloc(struct file *f)
-{
- struct Proc *p = myproc();
- for (int i = 0; i < NOFILE; i++)
- {
- if (p->ofile[i] == 0)
- {
- p->ofile[i] = f;
- return i;
- }
- }
- return -1;
-}
-
-// sys_openat(int dfd, const char *filename, int flags, mode_t mode)
-static uint64 sys_openat()
-{
- char path[128];
- int dfd, omode, mode_unused;
- int fd;
- struct file *f;
- Inode *ip;
-
- if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &omode) < 0 || argint(3, &mode_unused) < 0)
- return -EINVAL;
-
- if (omode & O_CREATE)
- {
- ip = VFS::namei(path);
- if (ip == nullptr)
- {
- char name[128];
- Inode *dp = VFS::nameiparent(path, name);
- if (dp)
- {
- VFS::ilock(dp);
- ip = dp->create(name, T_FILE, 0, 0);
- VFS::iunlockput(dp);
- }
- }
- }
- else
- {
- ip = VFS::namei(path);
- }
-
- if (ip == nullptr)
- return -ENOENT;
-
- VFS::ilock(ip);
- if ((omode & O_TRUNC) && ip->type == T_FILE)
- {
- ip->truncate();
- }
- VFS::iunlock(ip);
-
- f = FileTable::alloc();
- if (f == nullptr)
- {
- VFS::iput(ip);
- return -ENFILE;
- }
-
- fd = fdalloc(f);
- if (fd < 0)
- {
- f->ref = 0;
- f->type = FD_NONE;
- VFS::iput(ip);
- return -EMFILE;
- }
-
- f->type = FD_INODE;
- f->ip = ip;
- f->off = 0;
- f->readable = !(omode & O_WRONLY);
- f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
-
- return fd;
-}
-
-// sys_mkdirat(int dfd, const char *pathname, mode_t mode)
-static uint64 sys_mkdirat()
-{
- char path[128];
- int dfd, mode;
-
- if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0)
- return -EINVAL;
-
- Inode *ip = VFS::namei(path);
- if (ip != nullptr)
- {
- VFS::iput(ip);
- return -EEXIST;
- }
-
- char name[128];
- Inode *dp = VFS::nameiparent(path, name);
- if (dp == nullptr)
- return -ENOENT;
-
- VFS::ilock(dp);
- ip = dp->create(name, T_DIR, 0, 0);
- VFS::iunlockput(dp);
-
- if (ip == nullptr)
- return -EIO;
-
- VFS::iput(ip);
- return 0;
-}
-
-static uint64 sys_chdir()
-{
- char path[128];
- if (argstr(0, path, 128) < 0)
- return -EFAULT;
-
- Inode *ip = VFS::namei(path);
- if (ip == nullptr)
- return -ENOENT;
-
- VFS::ilock(ip);
- if (ip->type != T_DIR)
- {
- VFS::iunlockput(ip);
- return -ENOTDIR;
- }
- VFS::iunlock(ip);
-
- struct Proc *p = myproc();
- if (p->cwd)
- VFS::iput(p->cwd);
- p->cwd = ip;
- return 0;
-}
-
-static uint64 sys_dup()
-{
- int oldfd;
- if (argint(0, &oldfd) < 0)
- return -EINVAL;
-
- struct Proc *p = myproc();
- if (oldfd < 0 || oldfd >= NOFILE || p->ofile[oldfd] == nullptr)
- return -EBADF;
-
- struct file *f = FileTable::dup(p->ofile[oldfd]);
- int newfd = fdalloc(f);
- if (newfd < 0)
- {
- FileTable::close(f);
- return -EMFILE;
- }
- return newfd;
-}
-
-static uint64 sys_fstat()
-{
- int fd;
- uint64 stat_addr;
-
- if (argint(0, &fd) < 0 || argint(1, (int *)&stat_addr) < 0)
- return -EINVAL;
-
- struct Proc *p = myproc();
- if (fd < 0 || fd >= NOFILE || p->ofile[fd] == nullptr)
- return -EBADF;
-
- if (FileTable::stat(p->ofile[fd], stat_addr) < 0)
- return -EIO;
-
- return 0;
-}
-
-// sys_mknodat(int dfd, const char *filename, mode_t mode, dev_t dev)
-static uint64 sys_mknodat()
-{
- char path[128];
- int dfd, mode, dev;
-
- if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0 || argint(3, &dev) < 0)
- return -EINVAL;
-
- Inode *ip = VFS::namei(path);
- if (ip != nullptr)
- {
- VFS::iput(ip);
- return -EEXIST;
- }
-
- char name[128];
- Inode *dp = VFS::nameiparent(path, name);
- if (dp == nullptr)
- return -ENOENT;
-
- // Decode dev_t (Assuming simplified minor/major for now)
- int major = (dev >> 20) & 0xFFF; // Just a guess for Linux packing, or pass raw
- int minor = dev & 0xFFFFF;
-
- // For Phase 1 compatibility with init.cc:
- // init.cc passes raw major/minor. Shim will pack them.
- // We just unpack naively or assume Shim passed us correct structure.
-
- VFS::ilock(dp);
- ip = dp->create(name, T_DEVICE, major, minor);
- VFS::iunlockput(dp);
-
- if (ip == nullptr)
- return -EIO;
-
- VFS::iput(ip);
- return 0;
-}
-
-static uint64 sys_close()
-{
- int fd;
- if (argint(0, &fd) < 0)
- return -EINVAL;
-
- struct Proc *p = myproc();
- if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
- return -EBADF;
-
- FileTable::close(p->ofile[fd]);
- p->ofile[fd] = 0;
- return 0;
-}
-
-static uint64 sys_pipe2()
-{
- uint64 fdarray;
- int flags;
- struct file *rf, *wf;
- int fd0, fd1;
- struct Proc *p = myproc();
-
- if (argint(0, (int *)&fdarray) < 0 || argint(1, &flags) < 0)
- return -EFAULT;
-
- if (Pipe::create_pair(&rf, &wf) < 0)
- return -ENFILE;
-
- if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0)
- {
- if (fd0 >= 0)
- p->ofile[fd0] = nullptr;
- FileTable::close(rf);
- FileTable::close(wf);
- return -EMFILE;
- }
-
- if (VM::copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(int)) < 0 ||
- VM::copyout(p->pagetable, fdarray + sizeof(int), (char *)&fd1, sizeof(int)) < 0)
- {
- p->ofile[fd0] = nullptr;
- p->ofile[fd1] = nullptr;
- FileTable::close(rf);
- FileTable::close(wf);
- return -EFAULT;
- }
- return 0;
-}
-
-static uint64 sys_unlinkat()
-{
- char path[128], name[128];
- int dfd, flag;
-
- if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &flag) < 0)
- return -EINVAL;
-
- Inode *dp = VFS::nameiparent(path, name);
- if (!dp)
- return -ENOENT;
-
- VFS::ilock(dp);
- int ret = dp->unlink(name);
- VFS::iunlockput(dp);
-
- return (ret < 0) ? -EIO : 0;
-}
-
-// sys_linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)
-static uint64 sys_linkat()
-{
- // FAT32 does not support hard links.
- // Return Error to allow compilation/running to proceed (ln will fail gracefully).
- return -EPERM;
-}
-
-static uint64 sys_execve()
-{
- char path[128];
- uint64 uargv_ptr;
-
- if (argstr(0, path, sizeof(path)) < 0)
- return -EFAULT;
-
- uargv_ptr = argraw(1);
- // uenvp_ptr = argraw(2); // Ignored
-
- KernelArgv kargv;
-
- for (int i = 0; i < KernelArgv::MAX_ARGS; ++i)
- {
- uint64 uarg_str_ptr;
- if (VM::copyin(myproc()->pagetable, (char *)&uarg_str_ptr, uargv_ptr + i * sizeof(uint64), sizeof(uint64)) < 0)
- {
- return -EFAULT;
- }
-
- if (uarg_str_ptr == 0)
- {
- kargv.args[i] = nullptr;
- break;
- }
-
- kargv.args[i] = (char *)Slab::kmalloc(KernelArgv::MAX_ARG_LEN);
- if (kargv.args[i] == nullptr)
- {
- return -ENOMEM;
- }
-
- if (VM::copyinstr(myproc()->pagetable, kargv.args[i], uarg_str_ptr, KernelArgv::MAX_ARG_LEN) < 0)
- {
- return -EFAULT;
- }
- }
- return Exec::exec(path, kargv.args);
-}
-
-static uint64 sys_exit()
-{
- int n;
- if (argint(0, &n) < 0)
- return -EINVAL;
- ProcManager::exit(n);
- return 0;
-}
-
-static uint64 sys_clone()
-{
- return static_cast<uint64>(fork());
-}
-
-static uint64 sys_wait4()
-{
- uint64 status_addr;
-
- // argraw(0) is pid (ignored)
- status_addr = argraw(1);
- // argraw(2) is options (ignored)
- // argraw(3) is rusage (ignored)
-
- if (status_addr == static_cast<uint64>(-1))
- return -EINVAL;
-
- return static_cast<uint64>(ProcManager::wait(status_addr));
-}
-
-static uint64 sys_getpid()
-{
- return static_cast<uint64>(myproc()->pid);
-}
-
-static uint64 sys_putc()
-{
- char c = static_cast<char>(argraw(0));
- Drivers::uart_putc(c);
- return 0;
-}
-
-static uint64 sys_write()
-{
- struct file *f;
- int n;
- uint64 p;
- int fd;
-
- if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0)
- return -EINVAL;
-
- p = argraw(1);
-
- struct Proc *proc = myproc();
-
- if (fd == 1 && proc->ofile[fd] == nullptr)
- {
- constexpr int MAX_WRITE_BUF = 128;
- char buf[MAX_WRITE_BUF];
- int i = 0;
-
- while (i < n)
- {
- int len = n - i;
- if (len > MAX_WRITE_BUF)
- len = MAX_WRITE_BUF;
-
- if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64>(len)) < 0)
- return -EFAULT;
-
- for (int j = 0; j < len; j++)
- {
- Drivers::uart_putc(buf[j]);
- }
- i += len;
- }
- return static_cast<uint64>(n);
- }
-
- if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0)
- return -EBADF;
-
- return FileTable::write(f, p, n);
-}
-
-static uint64_t sys_read()
-{
- struct file *f;
- int n;
- uint64 p;
- int fd;
-
- if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0)
- return -EINVAL;
-
- p = argraw(1);
-
- struct Proc *proc = myproc();
- if (fd == 0 && proc->ofile[fd] == nullptr)
- return Drivers::console_read(p, n);
-
- if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0)
- return -EBADF;
-
- return FileTable::read(f, p, n);
-}
-
-static uint64 sys_brk()
-{
- int n;
- if (argint(0, &n) < 0)
- return -EINVAL;
-
- uint64 addr = myproc()->sz;
- if (ProcManager::growproc(n) < 0)
- return -ENOMEM;
-
- return addr;
-}
-
-static uint64 sys_kill()
-{
- int pid;
- if (argint(0, &pid) < 0)
- return -EINVAL;
- return ProcManager::kill(pid);
-}
-
-static uint64 sys_sleep()
-{
- int n;
- uint64 ticks0;
-
- if (argint(0, &n) < 0)
- return -EINVAL;
-
- Spinlock *lk = Timer::get_lock();
- lk->acquire();
- ticks0 = Timer::get_ticks();
- while (Timer::get_ticks() - ticks0 < (uint64)n)
- {
- if (myproc()->killed)
- {
- lk->release();
- return -EINTR;
- }
- ProcManager::sleep(Timer::get_tick_chan(), lk);
- }
- lk->release();
- return 0;
-}
-
-static uint64 sys_disk_test()
-{
- // VirtIO::test_rw();
- // VirtIO::test_bio();
- fat32_test();
- return 0;
-}
-
-static uint64 sys_lseek()
-{
- int fd, offset, whence;
- if (argint(0, &fd) < 0 || argint(1, &offset) < 0 || argint(2, &whence) < 0)
- return -EINVAL;
-
- struct Proc *p = myproc();
- if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
- return -EBADF;
-
- return FileTable::lseek(p->ofile[fd], offset, whence);
-}
-
-static uint64 sys_reboot()
-{
- SBI::sbi_shutdown();
- return 0;
-}
-
-void syscall()
-{
- Proc *p = myproc();
- int num = p->tf->a7;
- uint64 ret = static_cast<uint64>(-ENOSYS);
-
- switch (num)
- {
- case SYS_mknodat:
- ret = sys_mknodat();
- break;
- case SYS_mkdirat:
- ret = sys_mkdirat();
- break;
- case SYS_unlinkat:
- ret = sys_unlinkat();
- break;
- case SYS_linkat:
- ret = sys_linkat();
- break;
- case SYS_chdir:
- ret = sys_chdir();
- break;
- case SYS_openat:
- ret = sys_openat();
- break;
- case SYS_dup:
- ret = sys_dup();
- break;
- case SYS_close:
- ret = sys_close();
- break;
- case SYS_pipe2:
- ret = sys_pipe2();
- break;
- case SYS_lseek:
- ret = sys_lseek();
- break;
- case SYS_read:
- ret = sys_read();
- break;
- case SYS_write:
- ret = sys_write();
- break;
- case SYS_fstat:
- ret = sys_fstat();
- break;
- case SYS_exit:
- ret = sys_exit();
- break;
- case SYS_exit_group:
- ret = sys_exit();
- break;
- case SYS_kill:
- ret = sys_kill();
- break;
- case SYS_getpid:
- ret = sys_getpid();
- break;
- case SYS_brk:
- ret = sys_brk();
- break;
- case SYS_clone:
- ret = sys_clone();
- break;
- case SYS_execve:
- ret = sys_execve();
- if (ret == 0)
- return;
- break;
- case SYS_wait4:
- ret = sys_wait4();
- break;
-
- // Custom / Debug
- case SYS_reboot:
- ret = sys_reboot();
- break;
- case SYS_putc:
- ret = sys_putc();
- break;
- case SYS_disk_test:
- ret = sys_disk_test();
- break;
- case SYS_nanosleep:
- ret = sys_sleep();
- break;
-
- default:
- Drivers::uart_puts("Unknown Syscall ID: ");
- Drivers::print_hex(num);
- Drivers::uart_puts("\n");
- ret = -ENOSYS;
- break;
- }
-
- p->tf->a0 = ret;
-} \ No newline at end of file
diff --git a/src/kernel/timer.cc b/src/kernel/timer.cc
deleted file mode 100644
index fc02f27..0000000
--- a/src/kernel/timer.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "common/types.h"
-#include "kernel/config.h"
-#include "kernel/spinlock.h"
-#include "kernel/proc.h"
-#include "kernel/sbi.h"
-
-#define INTERVAL 1000000
-
-namespace Timer
-{
- uint64 ticks;
- Spinlock tickslock;
-
- uint64 get_time()
- {
- uint64 time;
- asm volatile("rdtime %0" : "=r"(time));
- return time;
- }
-
- void set_next_trigger()
- {
- SBI::set_timer(get_time() + INTERVAL);
- }
-
- void init()
- {
- set_next_trigger();
-
- uint64 sie;
- asm volatile("csrr %0, sie" : "=r"(sie));
- sie |= (1L << 5);
- asm volatile("csrw sie, %0" : : "r"(sie));
- }
-
- void tick()
- {
- tickslock.acquire();
- ticks++;
- ProcManager::wakeup(&ticks);
- tickslock.release();
- set_next_trigger();
- }
-
- uint64 get_ticks()
- {
- tickslock.acquire();
- uint64 t = ticks;
- tickslock.release();
- return t;
- }
-
- Spinlock *get_lock()
- {
- return &tickslock;
- }
-
- void *get_tick_chan()
- {
- return &ticks;
- }
-} \ No newline at end of file
diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc
deleted file mode 100644
index b7bd5f0..0000000
--- a/src/kernel/trap/handler.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2026 Richard QIn
- */
-#include "kernel/trap.h"
-#include "kernel/riscv.h"
-#include "kernel/proc.h"
-#include "drivers/uart.h"
-#include "kernel/syscall.h"
-#include "kernel/mm.h"
-#include "kernel/timer.h"
-#include "drivers/plic.h"
-#include "drivers/virtio.h"
-#include "kernel/fdt.h"
-#include "lib/string.h"
-
-
-extern "C" void kernelvec();
-
-// Handle Function
-
-void panic(const char *s)
-{
- Drivers::uart_puts("\n\n!!! KERNEL PANIC !!!\n");
- Drivers::uart_puts(s);
- Drivers::uart_puts("\nSystem Halted.\n");
- while (1)
- ;
-}
-
-// Trap Implementation
-
-namespace Trap
-{
- void init()
- {
- Drivers::uart_puts("[Trap] Global init done.\n");
- }
-
- // Each CPU core needs to call this function when starting to set its own stvec
- void inithart()
- {
- w_stvec((uint64)kernelvec);
-
- // Ensure that the S-Mode interrupt enable bit (SIE) is cleared during initialization
- // Interrupt enabling will be done by the scheduler when the first process runs
- w_sstatus(r_sstatus() & ~SSTATUS_SIE);
-
- // Enable the external interrupt, clock interrupt, and software interrupt bits in S-Mode (in SIE register)
- uint64 sie = r_sie();
- sie |= SIE_SEIE | SIE_STIE | SIE_SSIE;
- w_sie(sie);
-
- Drivers::uart_puts("[Trap] Hart initialized (stvec set).\n");
- }
-
- // Device Interrupt Check
- int devintr()
- {
- uint64 scause = r_scause();
-
- bool is_interrupt = (scause & 0x8000000000000000L) != 0;
- uint64 code = scause & 0xff;
-
- if (is_interrupt && code == 9)
- {
- // Supervisor External Interrupt (IRQ 9)
- int irq = PLIC::claim();
-
- if (irq == (int)g_devices.uart.irq)
- {
- Drivers::uart_intr();
- }
- else
- {
- // Check if it's a VirtIO IRQ
- bool handled = false;
- for (int i = 0; i < g_devices.virtio_count; i++)
- {
- if (irq == (int)g_devices.virtio[i].irq)
- {
- VirtIO::intr();
- handled = true;
- break;
- }
- }
- }
-
- if (irq > 0)
- {
- PLIC::complete(irq);
- }
-
- return 1;
- }
- else if (is_interrupt && code == 5)
- {
- // Supervisor Timer Interrupt (IRQ 5)
- // Timer::set_next_trigger();
- Timer::tick();
- // w_sip(r_sip() & ~2);
- return 2;
- }
-
- return 0;
- }
-}
-
-// Exception Handling Entry
-
-extern "C" void kerneltrap(struct Trapframe *tf)
-{
- uint64 sepc = r_sepc();
- uint64 sstatus = r_sstatus();
- uint64 scause = r_scause();
-
- if ((sstatus & SSTATUS_SPP) == 0)
- panic("kerneltrap: not from supervisor mode");
-
- if (intr_get() != 0)
- panic("kerneltrap: interrupts enabled");
-
- if (Trap::devintr() == 0)
- {
- Drivers::uart_puts("\n--- KERNEL EXCEPTION ---\n");
- Drivers::uart_puts("scause: ");
- Drivers::print_hex(scause);
- Drivers::uart_puts("\n");
- Drivers::uart_puts("sepc: ");
- Drivers::print_hex(sepc);
- Drivers::uart_puts("\n");
- Drivers::uart_puts("stval: ");
- Drivers::print_hex(r_stval());
- Drivers::uart_puts("\n");
- panic("kerneltrap exception");
- }
-
- w_sepc(sepc);
- w_sstatus(sstatus);
-}
-
-extern "C" void usertrap()
-{
- // Drivers::uart_puts("[Debug] Entered usertrap!\n");
- int which_dev = 0;
-
- if ((r_sstatus() & SSTATUS_SPP) != 0)
- panic("usertrap: not from user mode");
-
- w_stvec((uint64)kernelvec);
-
- struct Proc *p = myproc();
- if (!p)
- panic("usertrap: no process");
-
- p->tf->epc = r_sepc();
-
- uint64 scause = r_scause();
- uint64 stval = r_stval();
-
- if (scause == 8) // Syscall
- {
- if (p->state == ZOMBIE)
- ProcManager::exit(-1);
- p->tf->epc += 4;
- intr_on();
- syscall();
- intr_off();
- }
- else if (scause == 15) // Store Page Fault
- {
- if (VM::handle_cow_fault(p->pagetable, PGROUNDDOWN(stval)) != 0)
- {
- uint64 pa = VM::walkaddr(p->pagetable, stval);
-
- if (pa == 0)
- {
- Drivers::uart_puts("usertrap: Segmentation Fault (unmapped) at ");
- }
- else
- {
- Drivers::uart_puts("usertrap: Protection Fault (or OOM) at ");
- }
-
- Drivers::print_hex(stval);
- Drivers::uart_puts("\n");
- p->state = ZOMBIE;
- ProcManager::exit(-1);
- }
- }
- else if ((which_dev = Trap::devintr()) != 0)
- {
- if (which_dev == 2)
- {
- ProcManager::yield();
- }
- }
- else
- {
- Drivers::uart_puts("\nusertrap(): unexpected scause ");
- Drivers::print_hex(scause);
- Drivers::uart_puts(" pid=");
- Drivers::uart_put_int(p->pid);
- Drivers::uart_puts(" sepc=");
- Drivers::print_hex(p->tf->epc);
- Drivers::uart_puts(" stval=");
- Drivers::print_hex(stval);
- Drivers::uart_puts("\n");
- p->state = ZOMBIE;
- ProcManager::exit(-1);
- }
-
- if (p->state == ZOMBIE)
- ProcManager::exit(-1);
-
- usertrapret();
-} \ No newline at end of file
diff --git a/src/kernel/trap/trampoline.S b/src/kernel/trap/trampoline.S
deleted file mode 100644
index 57d6f25..0000000
--- a/src/kernel/trap/trampoline.S
+++ /dev/null
@@ -1,101 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2026 Richard Qin
-
-.section .text
-.globl trampoline
-.globl uservec
-.globl userret
-
-.align 12
-trampoline:
-.align 4
-uservec:
-
- csrrw a0, sscratch, a0
-
- sd ra, 40(a0)
- sd sp, 48(a0)
- sd gp, 56(a0)
- sd tp, 64(a0)
- sd t0, 72(a0)
- sd t1, 80(a0)
- sd t2, 88(a0)
- sd s0, 96(a0)
- sd s1, 104(a0)
- sd a1, 120(a0)
- sd a2, 128(a0)
- sd a3, 136(a0)
- sd a4, 144(a0)
- sd a5, 152(a0)
- sd a6, 160(a0)
- sd a7, 168(a0)
- sd s2, 176(a0)
- sd s3, 184(a0)
- sd s4, 192(a0)
- sd s5, 200(a0)
- sd s6, 208(a0)
- sd s7, 216(a0)
- sd s8, 224(a0)
- sd s9, 232(a0)
- sd s10, 240(a0)
- sd s11, 248(a0)
- sd t3, 256(a0)
- sd t4, 264(a0)
- sd t5, 272(a0)
- sd t6, 280(a0)
-
- csrr t0, sscratch
- sd t0, 112(a0)
-
- ld sp, 8(a0)
- ld tp, 32(a0)
- ld t0, 16(a0)
- ld t1, 0(a0)
-
- csrw satp, t1
- sfence.vma zero, zero
-
- jr t0
-
-.align 4
-userret:
-
- csrw satp, a1
- sfence.vma zero, zero
-
- csrw sscratch, a0
-
- ld ra, 40(a0)
- ld sp, 48(a0)
- ld gp, 56(a0)
- ld tp, 64(a0)
- ld t0, 72(a0)
- ld t1, 80(a0)
- ld t2, 88(a0)
- ld s0, 96(a0)
- ld s1, 104(a0)
- ld a1, 120(a0)
- ld a2, 128(a0)
- ld a3, 136(a0)
- ld a4, 144(a0)
- ld a5, 152(a0)
- ld a6, 160(a0)
- ld a7, 168(a0)
- ld s2, 176(a0)
- ld s3, 184(a0)
- ld s4, 192(a0)
- ld s5, 200(a0)
- ld s6, 208(a0)
- ld s7, 216(a0)
- ld s8, 224(a0)
- ld s9, 232(a0)
- ld s10, 240(a0)
- ld s11, 248(a0)
- ld t3, 256(a0)
- ld t4, 264(a0)
- ld t5, 272(a0)
- ld t6, 280(a0)
-
- ld a0, 112(a0)
-
- sret \ No newline at end of file
diff --git a/src/kernel/trap/trap.S b/src/kernel/trap/trap.S
deleted file mode 100644
index 8bce53d..0000000
--- a/src/kernel/trap/trap.S
+++ /dev/null
@@ -1,90 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2026 Richard Qin
-
-.section .text
-.global kernelvec
-.global uservec
-.global userret
-.align 12
-
-kernelvec:
- addi sp, sp, -288
-
- sd ra, 40(sp)
- sd sp, 48(sp)
- sd gp, 56(sp)
- sd tp, 64(sp)
- sd t0, 72(sp)
- sd t1, 80(sp)
- sd t2, 88(sp)
- sd s0, 96(sp)
- sd s1, 104(sp)
- sd a0, 112(sp)
- sd a1, 120(sp)
- sd a2, 128(sp)
- sd a3, 136(sp)
- sd a4, 144(sp)
- sd a5, 152(sp)
- sd a6, 160(sp)
- sd a7, 168(sp)
- sd s2, 176(sp)
- sd s3, 184(sp)
- sd s4, 192(sp)
- sd s5, 200(sp)
- sd s6, 208(sp)
- sd s7, 216(sp)
- sd s8, 224(sp)
- sd s9, 232(sp)
- sd s10, 240(sp)
- sd s11, 248(sp)
- sd t3, 256(sp)
- sd t4, 264(sp)
- sd t5, 272(sp)
- sd t6, 280(sp)
-
- csrr t0, sepc
- csrr t1, sstatus
- sd t0, 24(sp) # Trapframe.epc
- sd t1, 32(sp) # Trapframe.kernel_hartid
-
- mv a0, sp
- call kerneltrap
-
- ld t0, 24(sp)
- ld t1, 32(sp)
- csrw sepc, t0
- csrw sstatus, t1
-
- ld ra, 40(sp)
- ld gp, 56(sp)
- ld tp, 64(sp)
- ld t0, 72(sp)
- ld t1, 80(sp)
- ld t2, 88(sp)
- ld s0, 96(sp)
- ld s1, 104(sp)
- ld a0, 112(sp)
- ld a1, 120(sp)
- ld a2, 128(sp)
- ld a3, 136(sp)
- ld a4, 144(sp)
- ld a5, 152(sp)
- ld a6, 160(sp)
- ld a7, 168(sp)
- ld s2, 176(sp)
- ld s3, 184(sp)
- ld s4, 192(sp)
- ld s5, 200(sp)
- ld s6, 208(sp)
- ld s7, 216(sp)
- ld s8, 224(sp)
- ld s9, 232(sp)
- ld s10, 240(sp)
- ld s11, 248(sp)
- ld t3, 256(sp)
- ld t4, 264(sp)
- ld t5, 272(sp)
- ld t6, 280(sp)
-
- addi sp, sp, 288
- sret \ No newline at end of file
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) ? "<DIR>" : " ",
- 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 <dirname> ...\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