summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--include/drivers/uart.h8
-rw-r--r--include/fs/fs.h3
-rw-r--r--include/kernel/config.h6
-rw-r--r--include/kernel/fdt.h45
-rw-r--r--include/kernel/pmm.h11
-rw-r--r--include/kernel/syscall.h103
-rw-r--r--include/lib/errno.h168
-rw-r--r--include/ulib/errno.h168
-rw-r--r--include/user/user.h48
-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
25 files changed, 1256 insertions, 380 deletions
diff --git a/Makefile b/Makefile
index b83f88e..0722f8c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2026 Richard Qin
-TOOLCHAIN_PREFIX := riscv64-linux-gnu-
+# Try to find a suitable RISC-V toolchain prefix
+ifndef TOOLCHAIN_PREFIX
+ TOOLCHAIN_PREFIX := $(shell \
+ if command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then \
+ echo riscv64-linux-gnu-; \
+ elif command -v riscv64-unknown-gnu-gcc >/dev/null 2>&1; then \
+ echo riscv64-unknown-gnu-; \
+ elif command -v riscv64-unknown-linux-gnu-gcc >/dev/null 2>&1; then \
+ echo riscv64-unknown-linux-gnu-; \
+ elif command -v riscv64-unknown-elf-gcc >/dev/null 2>&1; then \
+ echo riscv64-unknown-elf-; \
+ else \
+ echo riscv64-linux-gnu-; \
+ fi)
+endif
+
CC := $(TOOLCHAIN_PREFIX)gcc
CXX := $(TOOLCHAIN_PREFIX)g++
LD := $(TOOLCHAIN_PREFIX)ld
@@ -22,7 +37,8 @@ ULIB_OBJS := $(BUILD_DIR)/user/entry.o \
$(BUILD_DIR)/ulib/stdlib.o \
$(BUILD_DIR)/ulib/string.o \
$(BUILD_DIR)/ulib/cxx.o \
- $(BUILD_DIR)/ulib/iostream.o
+ $(BUILD_DIR)/ulib/iostream.o \
+ $(BUILD_DIR)/ulib/syscalls.o
INITCODE_BIN := $(BUILD_DIR)/user/initcode
diff --git a/include/drivers/uart.h b/include/drivers/uart.h
index 1cdc938..a56624c 100644
--- a/include/drivers/uart.h
+++ b/include/drivers/uart.h
@@ -1,13 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
*/
#pragma once
#include "common/types.h"
#include "drivers/uart_color.h"
+#include "kernel/fdt.h"
-#define UART0 0x10000000L
+// UART register offsets (NS16550A)
#define RHR 0 // Receive Holding Register (read mode)
#define THR 0 // Transmit Holding Register (write mode)
#define IER 1 // Interrupt Enable Register
@@ -21,6 +22,9 @@
#define UART_RX_BUF_SIZE 128
+// UART base address from FDT (use inline function to avoid macro issues)
+static inline uint64 uart_base() { return g_devices.uart.base_addr; }
+
namespace Drivers
{
void uart_init();
diff --git a/include/fs/fs.h b/include/fs/fs.h
index 967858b..b511a84 100644
--- a/include/fs/fs.h
+++ b/include/fs/fs.h
@@ -99,4 +99,7 @@ namespace VFS
Inode *namei(const char *path);
// Find the parent directory inode of the path, and copy the last part of the path (the file name) into the name buffer
Inode *nameiparent(const char *path, char *name);
+ // Register a file system
+ void register_fs(FileSystem *fs);
+
} // namespace VFS
diff --git a/include/kernel/config.h b/include/kernel/config.h
index 45d85cd..49df2ff 100644
--- a/include/kernel/config.h
+++ b/include/kernel/config.h
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
*/
#pragma once
#include "common/types.h"
+#include "kernel/fdt.h"
+// Legacy compat — these are still referenced in some places
extern uint64 g_uart_base;
-extern uint64 g_clint_base;
-extern uint64 g_plic_base;
extern uint64 g_dtb_addr; \ No newline at end of file
diff --git a/include/kernel/fdt.h b/include/kernel/fdt.h
new file mode 100644
index 0000000..89cbae6
--- /dev/null
+++ b/include/kernel/fdt.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Richard Qin
+ * LumeOS - FDT Device Discovery
+ */
+
+#pragma once
+#include "common/types.h"
+
+// Single device descriptor (populated from FDT)
+struct FdtDevice {
+ uint64 base_addr; // MMIO base address
+ uint64 size; // MMIO region size
+ uint32 irq; // Interrupt number (0 = none)
+};
+
+// Device registry — populated by fdt_parse(), consumed by drivers
+struct DeviceRegistry {
+ // Memory
+ uint64 mem_base;
+ uint64 mem_size;
+
+ // Core platform devices
+ FdtDevice uart;
+ FdtDevice plic;
+ FdtDevice clint;
+
+ // VirtIO devices (multiple possible)
+ static constexpr int MAX_VIRTIO = 8;
+ FdtDevice virtio[MAX_VIRTIO];
+ int virtio_count;
+
+ // MMIO ranges for kvminit() to map
+ static constexpr int MAX_MMIO = 16;
+ struct MmioRegion {
+ uint64 base;
+ uint64 size;
+ } mmio_regions[MAX_MMIO];
+ int mmio_count;
+};
+
+extern DeviceRegistry g_devices;
+
+// Parse FDT and populate g_devices
+void fdt_parse(uint64 dtb);
diff --git a/include/kernel/pmm.h b/include/kernel/pmm.h
index 1fc3070..261786d 100644
--- a/include/kernel/pmm.h
+++ b/include/kernel/pmm.h
@@ -1,16 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
*/
#pragma once
#include "common/types.h"
#include "kernel/spinlock.h"
+#include "kernel/fdt.h" // For g_devices
// Physical Memory Layout Definition
#define KERNBASE 0x80000000
-// Set the memory size to 128MB
-#define PHYSIZE (128 * 1024 * 1024)
+
+// Dynamic memory size from FDT
+// Default to 128MB if FDT not present/parsed
+extern uint64 g_phys_size;
+
+#define PHYSIZE (g_phys_size)
#define PHYSTOP (KERNBASE + PHYSIZE)
// Buddy System Max Order
diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h
index af4c474..3594c08 100644
--- a/include/kernel/syscall.h
+++ b/include/kernel/syscall.h
@@ -1,35 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
-*/
+ * Copyright (C) 2026 Richard Qin
+ * Lume OS - Linux Compatibility Layer
+ *
+ * Strictly aligned with Linux RISC-V 64 ABI (asm-generic)
+ * Reference: linux/usr/include/asm-generic/unistd.h
+ */
#pragma once
-#define SYS_putc 1
-#define SYS_fork 2
-#define SYS_exit 3
-#define SYS_wait 4
-#define SYS_pipe 5
-#define SYS_read 6
-#define SYS_kill 7
-#define SYS_exec 8
-#define SYS_fstat 9
-#define SYS_chdir 10
-#define SYS_dup 11
-#define SYS_getpid 12
-#define SYS_sbrk 13
-#define SYS_sleep 14
-#define SYS_uptime 15
-#define SYS_open 16
-#define SYS_write 17
-#define SYS_mknod 18
-#define SYS_unlink 19
-#define SYS_link 20
-#define SYS_mkdir 21
-#define SYS_close 22
-#define SYS_disk_test 23
-#define SYS_lseek 24
-#define SYS_shutdown 25
+// File System
+#define SYS_getcwd 17
+#define SYS_dup 23
+#define SYS_dup3 24
+#define SYS_fcntl 25
+#define SYS_ioctl 29
+#define SYS_mknodat 33
+#define SYS_mkdirat 34
+#define SYS_unlinkat 35
+#define SYS_linkat 37
+#define SYS_umount2 39
+#define SYS_mount 40
+#define SYS_statfs 43
+#define SYS_ftruncate 46
+#define SYS_faccessat 48
+#define SYS_chdir 49
+#define SYS_fchmod 52
+#define SYS_fchmodat 53
+#define SYS_fchownat 54
+#define SYS_openat 56
+#define SYS_close 57
+#define SYS_vhangup 58
+#define SYS_pipe2 59
+#define SYS_getdents64 61
+#define SYS_lseek 62
+#define SYS_read 63
+#define SYS_write 64
+#define SYS_readv 65
+#define SYS_writev 66
+#define SYS_pread64 67
+#define SYS_pwrite64 68
+#define SYS_pselect6 72
+#define SYS_ppoll 73
+#define SYS_readlinkat 78
+#define SYS_fstatat 79 // newfstatat
+#define SYS_fstat 80
+
+// Process Management
+#define SYS_exit 93
+#define SYS_exit_group 94
+#define SYS_set_tid_address 96
+#define SYS_nanosleep 101
+#define SYS_kill 129
+#define SYS_rt_sigaction 134
+#define SYS_times 153
+#define SYS_uname 160
+#define SYS_gettimeofday 169
+#define SYS_getpid 172
+#define SYS_getppid 173
+#define SYS_getuid 174
+#define SYS_geteuid 175
+#define SYS_getgid 176
+#define SYS_getegid 177
+#define SYS_sysinfo 179
+#define SYS_brk 214
+#define SYS_munmap 215
+#define SYS_mremap 216
+#define SYS_clone 220
+#define SYS_execve 221
+#define SYS_mmap 222
+#define SYS_wait4 260
+#define SYS_prlimit64 261
+
+// System
+#define SYS_reboot 142 // Used for shutdown
+
+// === Custom / Debug (Non-Standard) ===
+// Placed above 1000 to avoid conflicts with Linux ABI
+#define SYS_putc 1000
+#define SYS_disk_test 1001
#ifndef __ASSEMBLER__
void syscall();
diff --git a/include/lib/errno.h b/include/lib/errno.h
new file mode 100644
index 0000000..62fd3e5
--- /dev/null
+++ b/include/lib/errno.h
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Richard Qin
+ * Lume OS - Linux Compatibility Layer
+ *
+ * This file aligns strictly with Linux RISC-V 64 ABI (asm-generic).
+ * Reference: linux/include/uapi/asm-generic/errno-base.h
+ * Reference: linux/include/uapi/asm-generic/errno.h
+ */
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* 1-34: asm-generic/errno-base.h */
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+
+/* * CRITICAL FIX: Missing definitions (35-37) from asm-generic
+ * Without these, your file system and locking code will fail compliance.
+ */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+
+#define ENOSYS 38 /* Invalid system call number */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+
+#define EDEADLOCK EDEADLK
+
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+#define ECANCELED 125 /* Operation Canceled */
+#define ENOKEY 126 /* Required key not available */
+#define EKEYEXPIRED 127 /* Key has expired */
+#define EKEYREVOKED 128 /* Key has been revoked */
+#define EKEYREJECTED 129 /* Key was rejected by service */
+#define EOWNERDEAD 130 /* Owner died */
+#define ENOTRECOVERABLE 131 /* State not recoverable */
+#define ERFKILL 132 /* Operation not possible due to RF-kill */
+#define EHWPOISON 133 /* Memory page has hardware error */
+
+extern __thread int errno;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/include/ulib/errno.h b/include/ulib/errno.h
index 19da4d1..c1691db 100644
--- a/include/ulib/errno.h
+++ b/include/ulib/errno.h
@@ -1,6 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
+ * Lume OS - Linux Compatibility Layer
+ *
+ * This file aligns strictly with Linux RISC-V 64 ABI (asm-generic).
+ * Reference: linux/include/uapi/asm-generic/errno-base.h
+ * Reference: linux/include/uapi/asm-generic/errno.h
*/
#ifndef _ERRNO_H
@@ -11,24 +16,153 @@ extern "C"
{
#endif
-extern int errno;
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+/*
+ * This error code is special: arch syscall entry code will return
+ * -ENOSYS if users try to call a syscall that doesn't exist. To keep
+ * failures of syscalls that really do exist distinguishable from
+ * failures due to attempts to use a nonexistent syscall, syscall
+ * implementations should refrain from returning -ENOSYS.
+ */
+#define ENOSYS 38 /* Invalid system call number */
+
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+
+#define EDEADLOCK EDEADLK
-// Linux/ASM-Generic
-#define EPERM 1 /* Operation not permitted */
-#define ENOENT 2 /* No such file or directory */
-#define ESRCH 3 /* No such process */
-#define EINTR 4 /* Interrupted system call */
-#define EIO 5 /* I/O error */
-#define ENXIO 6 /* No such device or address */
-#define E2BIG 7 /* Argument list too long */
-#define ENOEXEC 8 /* Exec format error */
-#define EBADF 9 /* Bad file number */
-#define ECHILD 10 /* No child processes */
-#define EAGAIN 11 /* Try again */
-#define ENOMEM 12 /* Out of memory */
-#define EACCES 13 /* Permission denied */
-#define EFAULT 14 /* Bad address */
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+#define ECANCELED 125 /* Operation Canceled */
+#define ENOKEY 126 /* Required key not available */
+#define EKEYEXPIRED 127 /* Key has expired */
+#define EKEYREVOKED 128 /* Key has been revoked */
+#define EKEYREJECTED 129 /* Key was rejected by service */
+
+/* for robust mutexes */
+#define EOWNERDEAD 130 /* Owner died */
+#define ENOTRECOVERABLE 131 /* State not recoverable */
+
+#define ERFKILL 132 /* Operation not possible due to RF-kill */
+
+#define EHWPOISON 133 /* Memory page has hardware error */
+
+extern int errno;
#ifdef __cplusplus
}
#endif
diff --git a/include/user/user.h b/include/user/user.h
index 0be036b..7af8bdd 100644
--- a/include/user/user.h
+++ b/include/user/user.h
@@ -1,11 +1,47 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2026 Richard QIn
+ * Copyright (C) 2026 Richard Qin
*/
#pragma once
+
typedef unsigned long long uint64;
-extern "C" {
+#define AT_FDCWD -100
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ // Raw Linux System Calls
+ int sys_openat(int dfd, const char *filename, int flags, int mode);
+ int sys_mknodat(int dfd, const char *filename, int mode, int dev);
+ int sys_mkdirat(int dfd, const char *path, int mode);
+ int sys_unlinkat(int dfd, const char *path, int flags);
+ int sys_linkat(int olddfd, const char *oldpath, int newdfd, const char *newpath, int flags);
+ int sys_chdir(const char *path);
+ int sys_dup(int oldfd);
+ int sys_fstat(int fd, void *statbuf);
+ int sys_read(int fd, void *buf, int count);
+ int sys_write(int fd, const void *buf, int count);
+ int sys_close(int fd);
+ int sys_pipe2(int pipefd[2], int flags);
+ int sys_clone(unsigned long flags, void *stack, int *ptid, void *tls, int *ctid);
+ int sys_execve(const char *path, char *const argv[], char *const envp[]);
+ int sys_wait4(int pid, int *status, int options, void *rusage);
+ int sys_exit(int status);
+ int sys_getpid();
+ int sys_brk(int n);
+ int sys_kill(int pid, int sig);
+ int sys_nanosleep(void *req, void *rem);
+ int sys_reboot(int magic1, int magic2, int cmd, void *arg);
+ int sys_lseek(int fd, int offset, int whence);
+
+ // Custom
+ void sys_putc(char c);
+ int sys_disk_test();
+
+ // POSIX Wrappers
int fork();
int exit(int status);
int wait(uint64 status_addr);
@@ -18,8 +54,8 @@ extern "C" {
int open(const char *, int);
int mknod(const char *, short, short);
int unlink(const char *);
- int fstat(int fd, void *st);
int link(const char *, const char *);
+ int fstat(int fd, void *st);
int mkdir(const char *);
int chdir(const char *);
int dup(int fd);
@@ -28,8 +64,12 @@ extern "C" {
int sleep(int ticks);
int uptime();
int shutdown();
+ int lseek(int fd, int offset, int whence);
// Debug
void putc(char c);
int disk_test();
-} \ No newline at end of file
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
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