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; +} diff --git a/arch/riscv/hal.c b/arch/riscv/hal.c index 04ecc7d..57e008b 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) */ @@ -759,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; } 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;