summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-14 22:47:15 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-14 22:47:15 +0800
commitac9741e12222e72bad3414bc6f588e70a3d130cc (patch)
tree6aace9f63a2ea54c7c3fd1e49e98ff81b638296f /src
parent1e862099a13266da57ff7c6de11c1a11c42a8112 (diff)
downloadlume-ac9741e12222e72bad3414bc6f588e70a3d130cc.tar.gz
lume-ac9741e12222e72bad3414bc6f588e70a3d130cc.tar.xz
feat: implement FDT-based memory discovery and add comprehensive debug logging to exec syscalls
Diffstat (limited to 'src')
-rw-r--r--src/drivers/plic.cc40
-rw-r--r--src/drivers/uart.cc22
-rw-r--r--src/drivers/virtio_dist.cc10
-rw-r--r--src/fs/fs.cc28
-rw-r--r--src/kernel/fdt.cc246
-rw-r--r--src/kernel/main.cc11
-rw-r--r--src/kernel/mm/pmm.cc14
-rw-r--r--src/kernel/mm/vm.cc13
-rw-r--r--src/kernel/proc/exec.cc56
-rw-r--r--src/kernel/syscall.cc377
-rw-r--r--src/kernel/trap/handler.cc21
-rw-r--r--src/ulib/syscalls.c153
-rw-r--r--src/user/init.cc2
-rw-r--r--src/user/sh.cc6
-rw-r--r--src/user/usys.S57
15 files changed, 734 insertions, 322 deletions
diff --git a/src/drivers/plic.cc b/src/drivers/plic.cc
index f9e306b..a975c44 100644
--- a/src/drivers/plic.cc
+++ b/src/drivers/plic.cc
@@ -1,18 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * 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"
-// Base Constants
-constexpr uint64 PLIC_BASE = 0x0c000000L;
-constexpr uint64 PLIC_PRIORITY = PLIC_BASE + 0x0;
-constexpr uint64 PLIC_PENDING = PLIC_BASE + 0x1000;
+// 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)
-// Helper Macros to calculate addresses
#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)
@@ -27,12 +27,15 @@ namespace PLIC
{
void init()
{
- // Set Priority for UART (IRQ 10) and VirtIO (IRQ 1)
- // Must use volatile write
- *REG32(PLIC_PRIORITY + 10 * 4) = 1;
- for (int i = 1; i <= 8; i++)
+ // 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++)
{
- *REG32(PLIC_PRIORITY + i * 4) = 1;
+ if (g_devices.virtio[i].irq > 0)
+ *REG32(PLIC_PRIORITY + g_devices.virtio[i].irq * 4) = 1;
}
}
@@ -40,8 +43,19 @@ namespace PLIC
{
int hart = static_cast<int>(r_tp());
- // Enable UART(10) and VirtIO(1) for this Hart (S-Mode)
- *REG32(PLIC_SENABLE_ADDR(hart)) = (1 << 10) | 0x1FE;
+ // 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;
diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc
index 96ae182..397a402 100644
--- a/src/drivers/uart.cc
+++ b/src/drivers/uart.cc
@@ -40,29 +40,29 @@ namespace Drivers
uart_rx.w = 0;
// Disable interrupts and configure
- *(volatile uint8 *)(UART0 + IER) = 0x00;
+ *(volatile uint8 *)(uart_base() + IER) = 0x00;
// Enter baud rate setting mode (LCR_DLAB) = 0x80;
- *(volatile uint8 *)(UART0 + LCR) = 0x80;
- *(volatile uint8 *)(UART0 + 0) = 0x03; // DLL: 38.4K baud
- *(volatile uint8 *)(UART0 + 1) = 0x00; // DLM
+ *(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 *)(UART0 + LCR) = 0x03;
+ *(volatile uint8 *)(uart_base() + LCR) = 0x03;
// Reset and enable FIFO
- *(volatile uint8 *)(UART0 + FCR) = 0x07;
+ *(volatile uint8 *)(uart_base() + FCR) = 0x07;
// Enable Receive Data Available Interrupt
- *(volatile uint8 *)(UART0 + IER) = 0x01;
+ *(volatile uint8 *)(uart_base() + IER) = 0x01;
}
void uart_putc(char c)
{
uart_tx_lock.acquire();
- while ((*(volatile uint8 *)(UART0 + LSR) & LSR_TX_IDLE) == 0)
+ while ((*(volatile uint8 *)(uart_base() + LSR) & LSR_TX_IDLE) == 0)
;
- *(volatile uint8 *)(UART0 + THR) = c;
+ *(volatile uint8 *)(uart_base() + THR) = c;
uart_tx_lock.release();
}
@@ -113,10 +113,10 @@ namespace Drivers
while (1)
{
- if ((*(volatile uint8 *)(UART0 + LSR) & LSR_RX_READY) == 0)
+ if ((*(volatile uint8 *)(uart_base() + LSR) & LSR_RX_READY) == 0)
break;
- char c = *(volatile uint8 *)(UART0 + RHR);
+ char c = *(volatile uint8 *)(uart_base() + RHR);
uart_rx.buf[uart_rx.w % UART_RX_BUF_SIZE] = c;
uart_rx.w++;
diff --git a/src/drivers/virtio_dist.cc b/src/drivers/virtio_dist.cc
index b2acd8e..8292874 100644
--- a/src/drivers/virtio_dist.cc
+++ b/src/drivers/virtio_dist.cc
@@ -3,6 +3,7 @@
* 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"
@@ -67,11 +68,14 @@ namespace VirtIO
{
disk.lock.init("virtio_disk");
- // 1. Probing for VirtIO-MMIO device
+ // 1. Probe VirtIO devices discovered by FDT
bool found = false;
- // Probe common VirtIO addresses in QEMU virt machine
- for (uint64 addr = 0x10001000; addr < 0x10009000; addr += 0x1000)
+ 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);
diff --git a/src/fs/fs.cc b/src/fs/fs.cc
index b93f363..fc8f555 100644
--- a/src/fs/fs.cc
+++ b/src/fs/fs.cc
@@ -7,7 +7,7 @@
#include "drivers/uart.h"
#include "kernel/spinlock.h"
#include "kernel/proc.h"
-#include "fs/fat32.h"
+// #include "fs/fat32.h" // Decoupled
#include "lib/string.h"
static Inode *global_root_inode = nullptr;
@@ -53,6 +53,18 @@ void Inode::getattr(struct kstat *st)
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");
@@ -138,9 +150,17 @@ namespace VFS
{
if (global_root_inode == nullptr)
{
- Drivers::uart_puts("[VFS] Lazy init: Mounting FAT32...\n");
- fat32_fs.init();
- mount_root(fat32_fs.root());
+ // 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;
diff --git a/src/kernel/fdt.cc b/src/kernel/fdt.cc
index e9f8422..ae09c84 100644
--- a/src/kernel/fdt.cc
+++ b/src/kernel/fdt.cc
@@ -1,13 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * 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 "drivers/uart.h"
-#include "kernel/config.h"
+#include "kernel/fdt.h"
#include "lib/string.h"
-inline uint32_t bswap(uint32_t x)
+// 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);
@@ -34,74 +45,229 @@ struct fdt_header
#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_init(uint64 dtb)
+void fdt_parse(uint64 dtb)
{
- if (dtb == 0) return;
+ // Clear registry
+ memset(&g_devices, 0, sizeof(g_devices));
+
+ if (dtb == 0)
+ return;
- struct fdt_header* header = (struct fdt_header*)dtb;
+ 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));
+ 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);
+ uint32 token = bswap(*(uint32 *)struct_ptr);
struct_ptr += 4;
- if(token == FDT_END)break;
- if(token == FDT_NOP)continue;
+ if (token == FDT_END)
+ break;
+ if (token == FDT_NOP)
+ continue;
- if(token == FDT_BEGIN_NODE)
+ if (token == FDT_BEGIN_NODE)
{
- while (*struct_ptr != 0)struct_ptr++;
+ // 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);
+ 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)
+ 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);
+ uint32 len = bswap(*(uint32 *)struct_ptr);
struct_ptr += 4;
- uint32 nameoff = bswap(*(uint32*)struct_ptr);
+ uint32 nameoff = bswap(*(uint32 *)struct_ptr);
struct_ptr += 4;
- char* name = strings_ptr + nameoff;
- uint8* data = struct_ptr;
+ char *name = strings_ptr + nameoff;
+ uint8 *data = struct_ptr;
struct_ptr += len;
- struct_ptr = (uint8*)(((uint64)struct_ptr + 3) & ~3);
+ struct_ptr = (uint8 *)(((uint64)struct_ptr + 3) & ~3);
- if(strcmp(name, "reg") == 0 && len >= 8)
+ if (strcmp(name, "reg") == 0 && len >= 8)
{
- uint32 hi = bswap(*(uint32*)data);
- uint32 lo = bswap(*(uint32*)(data + 4));
+ // 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(strcmp(name, "compatible") == 0)
- {
- if (g_uart_base == 0)
+ if (len >= 16)
{
- for(uint32 i = 0; i < len; i++)
- {
- if (data[i] == 'n' && data[i + 1] == 's' && data[i + 2] == '1')
- {
- g_uart_base = current_reg_addr;
- break;
- }
- }
+ 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/main.cc b/src/kernel/main.cc
index 22cffd6..6a19915 100644
--- a/src/kernel/main.cc
+++ b/src/kernel/main.cc
@@ -20,16 +20,20 @@
#include "fs/fat32.h"
#include "lib/string.h"
-extern void fdt_init(uint64 dtb);
+#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_init(dtb);
+ fdt_parse(dtb);
Drivers::uart_init();
Drivers::uart_puts("\n[Lume OS] Booting...\n");
@@ -47,6 +51,9 @@ extern "C" void kernel_main(uint64 hartid, uint64 dtb)
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
diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc
index 2d0c44f..d3d99ba 100644
--- a/src/kernel/mm/pmm.cc
+++ b/src/kernel/mm/pmm.cc
@@ -6,6 +6,7 @@
#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"
@@ -13,6 +14,9 @@
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
@@ -74,12 +78,20 @@ namespace PMM
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: 128MB\n" ANSI_RESET);
+ 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;
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc
index 47b80e9..be2f2f2 100644
--- a/src/kernel/mm/vm.cc
+++ b/src/kernel/mm/vm.cc
@@ -8,6 +8,7 @@
#include "common/types.h"
#include "lib/string.h"
#include "drivers/uart.h"
+#include "kernel/fdt.h"
extern "C"
{
@@ -421,9 +422,15 @@ namespace VM
{
kernel_pagetable = uvmcreate();
- kvmmap(0x10000000, 0x10000000, 0x10000, PTE_R | PTE_W);
- kvmmap(0x0c000000, 0x0c000000, 0x400000, PTE_R | PTE_W);
- kvmmap(0x02000000, 0x02000000, 0x10000, PTE_R | PTE_W); // CLINT
+ // 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);
}
diff --git a/src/kernel/proc/exec.cc b/src/kernel/proc/exec.cc
index e5294d9..8d8c467 100644
--- a/src/kernel/proc/exec.cc
+++ b/src/kernel/proc/exec.cc
@@ -11,7 +11,6 @@
#include "lib/string.h"
#include "drivers/uart.h"
#include "kernel/trap.h"
-#include "drivers/uart.h"
extern char trampoline[];
@@ -74,7 +73,10 @@ static int loadseg(uint64 *pagetable, uint64 va, Inode *ip, uint64 offset, uint6
{
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)
@@ -82,7 +84,10 @@ static int loadseg(uint64 *pagetable, uint64 va, Inode *ip, uint64 offset, uint6
// 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;
}
@@ -91,29 +96,48 @@ namespace Exec
{
int exec(char *path, char **argv)
{
- // Get Inode
+ // 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;
@@ -124,7 +148,10 @@ namespace Exec
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)
@@ -139,10 +166,13 @@ namespace Exec
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); // protected pagetable
+ VM::uvmunmap(vm_guard.pagetable, sz, 1, 0);
uint64 sp = sz1;
uint64 stackbase = sp - stack_data_pages * PGSIZE;
@@ -157,10 +187,16 @@ namespace Exec
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;
@@ -169,25 +205,32 @@ namespace Exec
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;
- // setup Trapframe
p->tf->a0 = argc;
p->tf->a1 = sp;
p->tf->sp = sp;
p->tf->epc = elf.entry;
- // update process name
char *s = path, *last = path;
while (*s)
{
@@ -195,7 +238,7 @@ namespace Exec
last = s + 1;
s++;
}
- // memmove(p->name, last, sizeof(p->name));
+
size_t len = 0;
while (last[len] && len < sizeof(p->name) - 1)
{
@@ -210,7 +253,6 @@ namespace Exec
// release old pagetable
VM::uvmfree(oldpagetable, oldsz);
-
asm volatile("fence.i");
return 0; // iguard unlocks and releases IP upon destruction
diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc
index b891ada..0979c24 100644
--- a/src/kernel/syscall.cc
+++ b/src/kernel/syscall.cc
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
*/
#include "kernel/syscall.h"
#include "common/types.h"
@@ -17,12 +17,13 @@
#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
{
@@ -30,7 +31,6 @@ namespace ProcManager
int wait(uint64_t addr);
}
-
static uint64_t argraw(int n)
{
Proc *p = myproc();
@@ -69,26 +69,18 @@ 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() { 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;
};
@@ -107,16 +99,17 @@ static int fdalloc(struct file *f)
return -1;
}
-static uint64 sys_open()
+// sys_openat(int dfd, const char *filename, int flags, mode_t mode)
+static uint64 sys_openat()
{
char path[128];
- int omode;
+ int dfd, omode, mode_unused;
int fd;
struct file *f;
Inode *ip;
- if (argstr(0, path, 128) < 0 || argint(1, &omode) < 0)
- return -1;
+ 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)
{
@@ -139,9 +132,7 @@ static uint64 sys_open()
}
if (ip == nullptr)
- {
- return -1;
- }
+ return -ENOENT;
VFS::ilock(ip);
if ((omode & O_TRUNC) && ip->type == T_FILE)
@@ -154,7 +145,7 @@ static uint64 sys_open()
if (f == nullptr)
{
VFS::iput(ip);
- return -1;
+ return -ENFILE;
}
fd = fdalloc(f);
@@ -163,7 +154,7 @@ static uint64 sys_open()
f->ref = 0;
f->type = FD_NONE;
VFS::iput(ip);
- return -1;
+ return -EMFILE;
}
f->type = FD_INODE;
@@ -175,30 +166,33 @@ static uint64 sys_open()
return fd;
}
-static uint64 sys_mkdir()
+// sys_mkdirat(int dfd, const char *pathname, mode_t mode)
+static uint64 sys_mkdirat()
{
char path[128];
- if (argstr(0, path, 128) < 0)
- return -1;
+ 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 -1; // the dir is exist
+ return -EEXIST;
}
char name[128];
Inode *dp = VFS::nameiparent(path, name);
if (dp == nullptr)
- return -1;
+ return -ENOENT;
VFS::ilock(dp);
ip = dp->create(name, T_DIR, 0, 0);
VFS::iunlockput(dp);
if (ip == nullptr)
- return -1;
+ return -EIO;
VFS::iput(ip);
return 0;
@@ -208,24 +202,24 @@ static uint64 sys_chdir()
{
char path[128];
if (argstr(0, path, 128) < 0)
- return -1;
+ return -EFAULT;
Inode *ip = VFS::namei(path);
if (ip == nullptr)
- return -1;
+ return -ENOENT;
VFS::ilock(ip);
if (ip->type != T_DIR)
{
VFS::iunlockput(ip);
- return -1;
+ return -ENOTDIR;
}
VFS::iunlock(ip);
struct Proc *p = myproc();
- VFS::iput(p->cwd); // release old cwd
- p->cwd = ip; // switch to new cwd
-
+ if (p->cwd)
+ VFS::iput(p->cwd);
+ p->cwd = ip;
return 0;
}
@@ -233,18 +227,18 @@ static uint64 sys_dup()
{
int oldfd;
if (argint(0, &oldfd) < 0)
- return -1;
+ return -EINVAL;
struct Proc *p = myproc();
if (oldfd < 0 || oldfd >= NOFILE || p->ofile[oldfd] == nullptr)
- return -1;
+ return -EBADF;
struct file *f = FileTable::dup(p->ofile[oldfd]);
int newfd = fdalloc(f);
if (newfd < 0)
{
- FileTable::close(f); // fdalloc failed
- return -1;
+ FileTable::close(f);
+ return -EMFILE;
}
return newfd;
}
@@ -255,75 +249,86 @@ static uint64 sys_fstat()
uint64 stat_addr;
if (argint(0, &fd) < 0 || argint(1, (int *)&stat_addr) < 0)
- return -1;
+ return -EINVAL;
struct Proc *p = myproc();
if (fd < 0 || fd >= NOFILE || p->ofile[fd] == nullptr)
- return -1;
+ return -EBADF;
- return FileTable::stat(p->ofile[fd], stat_addr);
+ if (FileTable::stat(p->ofile[fd], stat_addr) < 0)
+ return -EIO;
+
+ return 0;
}
-static uint64 sys_mknod()
+// sys_mknodat(int dfd, const char *filename, mode_t mode, dev_t dev)
+static uint64 sys_mknodat()
{
char path[128];
- int major, minor;
+ int dfd, mode, dev;
- if (argstr(0, path, 128) < 0 || argint(1, &major) < 0 || argint(2, &minor) < 0)
- return -1;
+ 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 -1;
+ return -EEXIST;
}
char name[128];
Inode *dp = VFS::nameiparent(path, name);
if (dp == nullptr)
- return -1;
+ 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 -1;
+ return -EIO;
VFS::iput(ip);
return 0;
}
-
-
static uint64 sys_close()
{
int fd;
if (argint(0, &fd) < 0)
- return -1;
+ return -EINVAL;
struct Proc *p = myproc();
if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
- return -1;
+ return -EBADF;
FileTable::close(p->ofile[fd]);
p->ofile[fd] = 0;
return 0;
}
-static uint64 sys_pipe()
+static uint64 sys_pipe2()
{
- uint64 fdarray; // int fd[2]
+ uint64 fdarray;
+ int flags;
struct file *rf, *wf;
int fd0, fd1;
struct Proc *p = myproc();
- if (argint(0, (int *)&fdarray) < 0)
- return -1;
+ if (argint(0, (int *)&fdarray) < 0 || argint(1, &flags) < 0)
+ return -EFAULT;
- if(Pipe::create_pair(&rf, &wf) < 0)
- return -1;
+ if (Pipe::create_pair(&rf, &wf) < 0)
+ return -ENFILE;
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0)
{
@@ -331,7 +336,7 @@ static uint64 sys_pipe()
p->ofile[fd0] = nullptr;
FileTable::close(rf);
FileTable::close(wf);
- return -1;
+ return -EMFILE;
}
if (VM::copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(int)) < 0 ||
@@ -341,56 +346,58 @@ static uint64 sys_pipe()
p->ofile[fd1] = nullptr;
FileTable::close(rf);
FileTable::close(wf);
- return -1;
+ return -EFAULT;
}
return 0;
}
-static uint64 sys_link()
-{
- Drivers::uart_puts("Not supported now");
- return -1;
-}
-
-static uint64 sys_unlink()
+static uint64 sys_unlinkat()
{
char path[128], name[128];
- if (argstr(0, path, 128) < 0)
- return -1;
+ 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 -1;
+ return -ENOENT;
VFS::ilock(dp);
int ret = dp->unlink(name);
VFS::iunlockput(dp);
- return ret;
+ return (ret < 0) ? -EIO : 0;
}
-static uint64 sys_exec()
+// 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 -1;
- }
+ 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 -1;
- }
+ {
+ return -EFAULT;
+ }
if (uarg_str_ptr == 0)
{
@@ -400,16 +407,15 @@ static uint64 sys_exec()
kargv.args[i] = (char *)Slab::kmalloc(KernelArgv::MAX_ARG_LEN);
if (kargv.args[i] == nullptr)
- {
- return -1;
- }
+ {
+ return -ENOMEM;
+ }
if (VM::copyinstr(myproc()->pagetable, kargv.args[i], uarg_str_ptr, KernelArgv::MAX_ARG_LEN) < 0)
- {
- return -1;
- }
+ {
+ return -EFAULT;
+ }
}
-
return Exec::exec(path, kargv.args);
}
@@ -417,20 +423,29 @@ static uint64 sys_exit()
{
int n;
if (argint(0, &n) < 0)
- return static_cast<uint64>(-1);
+ return -EINVAL;
ProcManager::exit(n);
return 0;
}
-static uint64 sys_fork()
+static uint64 sys_clone()
{
return static_cast<uint64>(fork());
}
-static uint64 sys_wait()
+static uint64 sys_wait4()
{
- uint64 p = argraw(0);
- return static_cast<uint64>(ProcManager::wait(p));
+ 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()
@@ -452,20 +467,14 @@ static uint64 sys_write()
uint64 p;
int fd;
- if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0)
- return -1;
-
- struct Proc *proc = myproc();
+ if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0)
+ return -EINVAL;
p = argraw(1);
- // Drivers::uart_puts("DEBUG: sys_write fd=");
- // Drivers::uart_put_int(fd);
- // Drivers::uart_puts(" len=");
- // Drivers::uart_put_int(n);
- // Drivers::uart_puts("\n");
+ struct Proc *proc = myproc();
- if (fd == 1 && proc->ofile[fd] == nullptr) // stdout
+ if (fd == 1 && proc->ofile[fd] == nullptr)
{
constexpr int MAX_WRITE_BUF = 128;
char buf[MAX_WRITE_BUF];
@@ -478,10 +487,7 @@ static uint64 sys_write()
len = MAX_WRITE_BUF;
if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64>(len)) < 0)
- {
- Drivers::uart_puts("sys_write: copyin failed\n");
- return static_cast<uint64>(-1);
- }
+ return -EFAULT;
for (int j = 0; j < len; j++)
{
@@ -491,8 +497,9 @@ static uint64 sys_write()
}
return static_cast<uint64>(n);
}
+
if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0)
- return static_cast<uint64>(-1);
+ return -EBADF;
return FileTable::write(f, p, n);
}
@@ -504,50 +511,39 @@ static uint64_t sys_read()
uint64 p;
int fd;
- // get param: fd, buf, len
- if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0)
- return -1;
-
+ if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0)
+ return -EINVAL;
+
p = argraw(1);
- struct Proc* proc = myproc();
+ 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 -1;
+ return -EBADF;
return FileTable::read(f, p, n);
-
- return -1;
}
-static uint64 sys_sbrk()
+static uint64 sys_brk()
{
int n;
if (argint(0, &n) < 0)
- return -1;
+ return -EINVAL;
uint64 addr = myproc()->sz;
if (ProcManager::growproc(n) < 0)
- return -1;
+ return -ENOMEM;
return addr;
}
-static uint64 sys_uptime()
-{
- return Timer::get_ticks();
-}
-
static uint64 sys_kill()
{
int pid;
if (argint(0, &pid) < 0)
- return -1;
-
+ return -EINVAL;
return ProcManager::kill(pid);
}
@@ -557,24 +553,20 @@ static uint64 sys_sleep()
uint64 ticks0;
if (argint(0, &n) < 0)
- return -1;
+ 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 -1;
+ return -EINTR;
}
-
ProcManager::sleep(Timer::get_tick_chan(), lk);
}
-
lk->release();
return 0;
}
@@ -591,20 +583,18 @@ static uint64 sys_lseek()
{
int fd, offset, whence;
if (argint(0, &fd) < 0 || argint(1, &offset) < 0 || argint(2, &whence) < 0)
- return -1;
+ return -EINVAL;
struct Proc *p = myproc();
if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0)
- return -1;
+ return -EBADF;
return FileTable::lseek(p->ofile[fd], offset, whence);
}
-static uint64 sys_shutdown()
+static uint64 sys_reboot()
{
SBI::sbi_shutdown();
- while (1)
- ;
return 0;
}
@@ -612,98 +602,95 @@ void syscall()
{
Proc *p = myproc();
int num = p->tf->a7;
- uint64 ret = static_cast<uint64>(-1);
-
- /* Just For Debug */
- // Drivers::uart_puts("Syscall: ");
- // Drivers::print_hex(num);
- // Drivers::uart_puts("\n");
+ uint64 ret = static_cast<uint64>(-ENOSYS);
switch (num)
{
- case SYS_open:
- ret = sys_open();
+ case SYS_mknodat:
+ ret = sys_mknodat();
break;
- case SYS_close:
- ret = sys_close();
+ case SYS_mkdirat:
+ ret = sys_mkdirat();
break;
- case SYS_write:
- ret = sys_write();
+ case SYS_unlinkat:
+ ret = sys_unlinkat();
break;
- case SYS_read:
- ret = sys_read();
+ case SYS_linkat:
+ ret = sys_linkat();
break;
- case SYS_putc:
- ret = sys_putc();
- break;
- case SYS_fork:
- ret = sys_fork();
- break;
- case SYS_exec:
- ret = sys_exec();
- if (ret != static_cast<uint64>(-1))
- return;
+ case SYS_chdir:
+ ret = sys_chdir();
break;
- case SYS_exit:
- ret = sys_exit();
+ case SYS_openat:
+ ret = sys_openat();
break;
- case SYS_wait:
- ret = sys_wait();
+ case SYS_dup:
+ ret = sys_dup();
break;
- case SYS_getpid:
- ret = sys_getpid();
+ case SYS_close:
+ ret = sys_close();
break;
- case SYS_sbrk:
- ret = sys_sbrk();
- break;
- case SYS_disk_test:
- ret = sys_disk_test();
+ case SYS_pipe2:
+ ret = sys_pipe2();
break;
case SYS_lseek:
ret = sys_lseek();
break;
- case SYS_dup:
- ret = sys_dup();
+ case SYS_read:
+ ret = sys_read();
+ break;
+ case SYS_write:
+ ret = sys_write();
break;
case SYS_fstat:
ret = sys_fstat();
break;
- case SYS_chdir:
- ret = sys_chdir();
+ case SYS_exit:
+ ret = sys_exit();
+ break;
+ case SYS_exit_group:
+ ret = sys_exit();
+ break;
+ case SYS_kill:
+ ret = sys_kill();
break;
- case SYS_mkdir:
- ret = sys_mkdir();
+ case SYS_getpid:
+ ret = sys_getpid();
break;
- case SYS_mknod:
- ret = sys_mknod();
+ case SYS_brk:
+ ret = sys_brk();
break;
- case SYS_pipe:
- ret = sys_pipe();
+ case SYS_clone:
+ ret = sys_clone();
break;
- case SYS_unlink:
- ret = sys_unlink();
+ case SYS_execve:
+ ret = sys_execve();
+ if (ret == 0)
+ return;
break;
- case SYS_link:
- Drivers::uart_puts("Unimplemented syscall\n");
- ret = sys_link();
+ case SYS_wait4:
+ ret = sys_wait4();
break;
- case SYS_uptime:
- ret = sys_uptime();
+
+ // Custom / Debug
+ case SYS_reboot:
+ ret = sys_reboot();
break;
- case SYS_sleep:
- ret = sys_sleep();
+ case SYS_putc:
+ ret = sys_putc();
break;
- case SYS_kill:
- ret = sys_kill();
+ case SYS_disk_test:
+ ret = sys_disk_test();
break;
- case SYS_shutdown:
- ret = sys_shutdown();
+ case SYS_nanosleep:
+ ret = sys_sleep();
break;
+
default:
Drivers::uart_puts("Unknown Syscall ID: ");
Drivers::print_hex(num);
Drivers::uart_puts("\n");
- ret = static_cast<uint64>(-1);
+ ret = -ENOSYS;
break;
}
diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc
index 11af409..b7bd5f0 100644
--- a/src/kernel/trap/handler.cc
+++ b/src/kernel/trap/handler.cc
@@ -11,6 +11,7 @@
#include "kernel/timer.h"
#include "drivers/plic.h"
#include "drivers/virtio.h"
+#include "kernel/fdt.h"
#include "lib/string.h"
@@ -66,17 +67,23 @@ namespace Trap
// Supervisor External Interrupt (IRQ 9)
int irq = PLIC::claim();
- if (irq == 10)
+ if (irq == (int)g_devices.uart.irq)
{
Drivers::uart_intr();
- // Debug
- // Drivers::uart_puts("[Interrupt] UART Input detected!\n");
}
- else if (irq >= 1 && irq <= 8)
+ else
{
- VirtIO::intr();
- // Debug
- // Drivers::uart_puts("[Interrupt] VirtIO disk finished!\n");
+ // 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)
diff --git a/src/ulib/syscalls.c b/src/ulib/syscalls.c
new file mode 100644
index 0000000..676bf18
--- /dev/null
+++ b/src/ulib/syscalls.c
@@ -0,0 +1,153 @@
+// 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/init.cc b/src/user/init.cc
index f1a6e29..376e697 100644
--- a/src/user/init.cc
+++ b/src/user/init.cc
@@ -12,7 +12,7 @@ int main()
{
char *argv[] = {(char *)"sh", 0};
- printf(ANSI_BLUE"\n[Init] Starting Lume OS Shell..."ANSI_RESET);
+ printf(ANSI_BLUE "\n[Init] Starting Lume OS Shell..." ANSI_RESET);
printf("\n");
while (1)
diff --git a/src/user/sh.cc b/src/user/sh.cc
index 1bf9ebb..47aad9e 100644
--- a/src/user/sh.cc
+++ b/src/user/sh.cc
@@ -368,8 +368,8 @@ 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(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)
@@ -400,7 +400,7 @@ int main()
}
if (strcmp(buf, "shutdown") == 0 || strcmp(buf, "poweroff") == 0)
{
- printf(ANSI_BLUE"System shutting down..."ANSI_RESET);
+ printf(ANSI_BLUE "System shutting down..." ANSI_RESET);
printf("\n");
shutdown();
diff --git a/src/user/usys.S b/src/user/usys.S
index 885d45c..1e373d3 100644
--- a/src/user/usys.S
+++ b/src/user/usys.S
@@ -3,13 +3,6 @@
#include "kernel/syscall.h"
-#define SYSCALL(name) \
- .global name; \
- name: \
- li a7, SYS_ ## name; \
- ecall; \
- ret
-
#define SYSCALL_NAME(name, sysname) \
.global name; \
name: \
@@ -17,29 +10,29 @@
ecall; \
ret
-SYSCALL_NAME(sys_exit, exit)
+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)
-SYSCALL(fork)
-SYSCALL(wait)
-SYSCALL(pipe)
-SYSCALL(read)
-SYSCALL(write)
-SYSCALL(close)
-SYSCALL(kill)
-SYSCALL(exec)
-SYSCALL(open)
-SYSCALL(mknod)
-SYSCALL(unlink)
-SYSCALL(fstat)
-SYSCALL(link)
-SYSCALL(mkdir)
-SYSCALL(chdir)
-SYSCALL(dup)
-SYSCALL(getpid)
-SYSCALL(sbrk)
-SYSCALL(sleep)
-SYSCALL(uptime)
-SYSCALL(putc)
-SYSCALL(disk_test)
-SYSCALL(lseek)
-SYSCALL(shutdown) \ No newline at end of file
+# === Custom / Debug Syscalls ===
+SYSCALL_NAME(sys_putc, putc)
+SYSCALL_NAME(sys_disk_test, disk_test) \ No newline at end of file