From 2e83c36874bbb321de023efac30043a1ae46fa02 Mon Sep 17 00:00:00 2001 From: HeatCrab Date: Sat, 22 Nov 2025 20:49:00 +0800 Subject: [PATCH 1/4] Mark syscall dispatcher as weak symbol Allows architecture-specific syscall implementations to override the generic dispatcher at link time for privilege separation. --- kernel/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/syscall.c b/kernel/syscall.c index 6ad4493..35a8ca1 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -17,7 +17,7 @@ static const void *syscall_table[SYS_COUNT] = {SYSCALL_TABLE}; #undef _ /* Weak, generic dispatcher */ -int syscall(int num, void *a1, void *a2, void *a3) +__attribute__((weak)) int syscall(int num, void *a1, void *a2, void *a3) { if (unlikely(num <= 0 || num >= SYS_COUNT)) return -ENOSYS; From f36e7c59c9c59ab5dc0039e0b8f3c7529257e998 Mon Sep 17 00:00:00 2001 From: HeatCrab Date: Sat, 22 Nov 2025 20:52:54 +0800 Subject: [PATCH 2/4] Add ecall-based syscall trap Implements syscall interface using the ecall instruction to trap into M-mode from user space. Follows RISC-V calling convention for system call arguments and return values. Introduces a dedicated file for kernel entry mechanisms following Linux conventions. This separation clarifies the distinction between trap-based entry and generic syscall dispatch logic. --- arch/riscv/build.mk | 2 +- arch/riscv/entry.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/entry.c diff --git a/arch/riscv/build.mk b/arch/riscv/build.mk index c4dc46d..bb56d6a 100644 --- a/arch/riscv/build.mk +++ b/arch/riscv/build.mk @@ -70,7 +70,7 @@ LDFLAGS += --gc-sections ARFLAGS = r LDSCRIPT = $(ARCH_DIR)/riscv32-qemu.ld -HAL_OBJS := boot.o hal.o muldiv.o +HAL_OBJS := boot.o hal.o muldiv.o entry.o HAL_OBJS := $(addprefix $(BUILD_KERNEL_DIR)/,$(HAL_OBJS)) deps += $(HAL_OBJS:%.o=%.o.d) diff --git a/arch/riscv/entry.c b/arch/riscv/entry.c new file mode 100644 index 0000000..b3d72ea --- /dev/null +++ b/arch/riscv/entry.c @@ -0,0 +1,42 @@ +/* RISC-V Kernel Entry Points + * + * This file implements architecture-specific entry mechanisms into the kernel, + * primarily the system call trap interface using the RISC-V ecall instruction. + * + * System Call Calling Convention (RISC-V ABI): + * - a7 (x17): System call number + * - a0 (x10): Argument 1 / Return value + * - a1 (x11): Argument 2 + * - a2 (x12): Argument 3 + * + * The ecall instruction triggers an environment call exception that transfers + * control to the M-mode exception handler (hal.c), which then dispatches to + * the appropriate system call implementation via the syscall table. + */ + +#include + +/* Architecture-specific syscall implementation using ecall trap. + * This overrides the weak symbol defined in kernel/syscall.c. + */ +int syscall(int num, void *arg1, void *arg2, void *arg3) +{ + register int a0 asm("a0") = (int) arg1; + register int a1 asm("a1") = (int) arg2; + register int a2 asm("a2") = (int) arg3; + register int a7 asm("a7") = num; + + /* Execute ecall instruction to trap into M-mode. + * The M-mode exception handler will: + * 1. Save the current task context + * 2. Dispatch to the syscall handler based on a7 + * 3. Place the return value in a0 + * 4. Restore context and return to user mode via mret + */ + asm volatile("ecall" + : "+r"(a0) /* a0 is both input (arg1) and output (retval) */ + : "r"(a1), "r"(a2), "r"(a7) + : "memory"); + + return a0; +} From 03adecd2a8664621fd3a299229dc54ba3e295544 Mon Sep 17 00:00:00 2001 From: HeatCrab Date: Sat, 22 Nov 2025 21:05:55 +0800 Subject: [PATCH 3/4] Handle U-mode ecall for syscall dispatch Adds exception handler for U-mode ecall instructions to dispatch system calls. Extracts syscall number and arguments from the saved register context and returns results through the same mechanism. This design enables privilege separation by allowing user-mode tasks to request kernel services without direct access to privileged operations, addressing the security issue where tasks could bypass isolation by executing in M-mode. --- arch/riscv/hal.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/riscv/hal.c b/arch/riscv/hal.c index 04ecc7d..174d219 100644 --- a/arch/riscv/hal.c +++ b/arch/riscv/hal.c @@ -321,6 +321,31 @@ uint32_t do_trap(uint32_t cause, uint32_t epc, uint32_t isr_sp) } else { /* Synchronous Exception */ uint32_t code = MCAUSE_GET_CODE(cause); + /* Handle ecall from U-mode - system calls */ + if (code == MCAUSE_ECALL_UMODE) { + /* Advance mepc past the ecall instruction (4 bytes) */ + uint32_t new_epc = epc + 4; + write_csr(mepc, new_epc); + + uint32_t *isr_frame = (uint32_t *) isr_sp; + isr_frame[31] = new_epc; + + /* Extract syscall arguments from ISR frame */ + int syscall_num = isr_frame[15]; + void *arg1 = (void *) isr_frame[8]; + void *arg2 = (void *) isr_frame[9]; + void *arg3 = (void *) isr_frame[10]; + + /* Dispatch to syscall handler */ + extern int syscall(int num, void *arg1, void *arg2, void *arg3); + int retval = syscall(syscall_num, arg1, arg2, arg3); + + /* Store return value */ + isr_frame[8] = retval; + + return isr_sp; + } + /* Handle ecall from M-mode - used for yielding in preemptive mode */ if (code == MCAUSE_ECALL_MMODE) { /* Advance mepc past the ecall instruction (4 bytes) */ From e2eec2027e3be056db3a6c0325fbdb315ba45aae Mon Sep 17 00:00:00 2001 From: HeatCrab Date: Sat, 22 Nov 2025 21:16:37 +0800 Subject: [PATCH 4/4] Switch task initialization to user mode Tasks are now initialized to execute in U-mode rather than M-mode, enabling proper privilege isolation. The MPP field in mstatus is set to USER instead of MACH during context initialization. --- arch/riscv/hal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/hal.c b/arch/riscv/hal.c index 174d219..57e008b 100644 --- a/arch/riscv/hal.c +++ b/arch/riscv/hal.c @@ -784,12 +784,12 @@ void hal_context_init(jmp_buf *ctx, size_t sp, size_t ss, size_t ra) /* Set the essential registers for a new task: * - SP is set to the prepared top of the task's stack. * - RA is set to the task's entry point. - * - mstatus is set to enable interrupts and ensure machine mode. + * - mstatus is set to enable interrupts and ensure user mode. * * When this context is first restored, the ret instruction will effectively * jump to this entry point, starting the task. */ (*ctx)[CONTEXT_SP] = (uint32_t) stack_top; (*ctx)[CONTEXT_RA] = (uint32_t) ra; - (*ctx)[CONTEXT_MSTATUS] = MSTATUS_MIE | MSTATUS_MPP_MACH; + (*ctx)[CONTEXT_MSTATUS] = MSTATUS_MIE | MSTATUS_MPP_USER; }