3636
3737/* Defines the size of the full trap frame saved by the ISR in 'boot.c'.
3838 * The _isr routine saves 32 registers (30 GPRs + mcause + mepc), resulting
39- * in a 128 -byte frame. This space MUST be reserved at the top of every task's
39+ * in a 144 -byte frame. This space MUST be reserved at the top of every task's
4040 * stack (as a "red zone") to guarantee that an interrupt, even at peak stack
4141 * usage, will not corrupt memory outside the task's stack bounds.
4242 */
43- #define ISR_STACK_FRAME_SIZE 128
43+ #define ISR_STACK_FRAME_SIZE 144
44+
45+ /* ISR frame register indices (as 32-bit word offsets from isr_sp).
46+ * This layout matches the stack frame created by _isr in boot.c.
47+ * Indices are in word offsets (divide byte offset by 4).
48+ */
49+ enum {
50+ FRAME_RA = 0 , /* x1 - Return Address */
51+ FRAME_GP = 1 , /* x3 - Global Pointer */
52+ FRAME_TP = 2 , /* x4 - Thread Pointer */
53+ FRAME_T0 = 3 , /* x5 - Temporary register 0 */
54+ FRAME_T1 = 4 , /* x6 - Temporary register 1 */
55+ FRAME_T2 = 5 , /* x7 - Temporary register 2 */
56+ FRAME_S0 = 6 , /* x8 - Saved register 0 / Frame Pointer */
57+ FRAME_S1 = 7 , /* x9 - Saved register 1 */
58+ FRAME_A0 = 8 , /* x10 - Argument/Return 0 */
59+ FRAME_A1 = 9 , /* x11 - Argument/Return 1 */
60+ FRAME_A2 = 10 , /* x12 - Argument 2 */
61+ FRAME_A3 = 11 , /* x13 - Argument 3 */
62+ FRAME_A4 = 12 , /* x14 - Argument 4 */
63+ FRAME_A5 = 13 , /* x15 - Argument 5 */
64+ FRAME_A6 = 14 , /* x16 - Argument 6 */
65+ FRAME_A7 = 15 , /* x17 - Argument 7 / Syscall Number */
66+ FRAME_S2 = 16 , /* x18 - Saved register 2 */
67+ FRAME_S3 = 17 , /* x19 - Saved register 3 */
68+ FRAME_S4 = 18 , /* x20 - Saved register 4 */
69+ FRAME_S5 = 19 , /* x21 - Saved register 5 */
70+ FRAME_S6 = 20 , /* x22 - Saved register 6 */
71+ FRAME_S7 = 21 , /* x23 - Saved register 7 */
72+ FRAME_S8 = 22 , /* x24 - Saved register 8 */
73+ FRAME_S9 = 23 , /* x25 - Saved register 9 */
74+ FRAME_S10 = 24 , /* x26 - Saved register 10 */
75+ FRAME_S11 = 25 , /* x27 - Saved register 11 */
76+ FRAME_T3 = 26 , /* x28 - Temporary register 3 */
77+ FRAME_T4 = 27 , /* x29 - Temporary register 4 */
78+ FRAME_T5 = 28 , /* x30 - Temporary register 5 */
79+ FRAME_T6 = 29 , /* x31 - Temporary register 6 */
80+ FRAME_MCAUSE = 30 , /* Machine Cause CSR */
81+ FRAME_EPC = 31 , /* Machine Exception PC (mepc) */
82+ FRAME_MSTATUS = 32 /* Machine Status CSR */
83+ };
4484
4585/* Global variable to hold the new stack pointer for pending context switch.
4686 * When a context switch is needed, hal_switch_stack() saves the current SP
@@ -238,6 +278,21 @@ void hal_hardware_init(void)
238278 _stdout_install (__putchar );
239279 _stdin_install (__getchar );
240280 _stdpoll_install (__kbhit );
281+
282+ /* Grant U-mode access to all memory for validation purposes.
283+ * By default, RISC-V PMP denies all access to U-mode, which would cause
284+ * instruction access faults immediately upon task switch. This minimal
285+ * setup allows U-mode tasks to execute and serves as a placeholder until
286+ * the full PMP driver is integrated.
287+ */
288+ uint32_t pmpaddr = -1UL ; /* Cover entire address space */
289+ uint8_t pmpcfg = 0x0F ; /* TOR, R, W, X enabled */
290+
291+ asm volatile (
292+ "csrw pmpaddr0, %0\n"
293+ "csrw pmpcfg0, %1\n"
294+ :
295+ : "r" (pmpaddr ), "r" (pmpcfg ));
241296}
242297
243298/* Halts the system in an unrecoverable state */
@@ -321,19 +376,46 @@ uint32_t do_trap(uint32_t cause, uint32_t epc, uint32_t isr_sp)
321376 } else { /* Synchronous Exception */
322377 uint32_t code = MCAUSE_GET_CODE (cause );
323378
379+ /* Handle ecall from U-mode - system calls */
380+ if (code == MCAUSE_ECALL_UMODE ) {
381+ /* Advance mepc past the ecall instruction (4 bytes) */
382+ uint32_t new_epc = epc + 4 ;
383+ write_csr (mepc , new_epc );
384+
385+ /* Extract syscall arguments from ISR frame */
386+ uint32_t * f = (uint32_t * ) isr_sp ;
387+
388+ int syscall_num = f [FRAME_A7 ];
389+ void * arg1 = (void * ) f [FRAME_A0 ];
390+ void * arg2 = (void * ) f [FRAME_A1 ];
391+ void * arg3 = (void * ) f [FRAME_A2 ];
392+
393+ /* Dispatch to syscall implementation via direct table lookup.
394+ * Must use do_syscall here instead of syscall() to avoid recursive
395+ * traps, as the user-space syscall() may be overridden with ecall.
396+ */
397+ extern int do_syscall (int num , void * arg1 , void * arg2 , void * arg3 );
398+ int retval = do_syscall (syscall_num , arg1 , arg2 , arg3 );
399+
400+ /* Store return value and updated PC */
401+ f [FRAME_A0 ] = (uint32_t ) retval ;
402+ f [FRAME_EPC ] = new_epc ;
403+
404+ return isr_sp ;
405+ }
406+
324407 /* Handle ecall from M-mode - used for yielding in preemptive mode */
325408 if (code == MCAUSE_ECALL_MMODE ) {
326409 /* Advance mepc past the ecall instruction (4 bytes) */
327410 uint32_t new_epc = epc + 4 ;
328411 write_csr (mepc , new_epc );
329412
330413 /* Also update mepc in the ISR frame on the stack!
331- * The ISR epilogue will restore mepc from the frame (offset 31*4 =
332- * 124 bytes). If we don't update the frame, mret will jump back to
333- * the ecall instruction!
414+ * The ISR epilogue will restore mepc from the frame. If we don't
415+ * update the frame, mret will jump back to the ecall instruction!
334416 */
335- uint32_t * isr_frame = (uint32_t * ) isr_sp ;
336- isr_frame [ 31 ] = new_epc ;
417+ uint32_t * f = (uint32_t * ) isr_sp ;
418+ f [ FRAME_EPC ] = new_epc ;
337419
338420 /* Invoke dispatcher for context switch - parameter 0 = from ecall,
339421 * don't increment ticks.
@@ -355,6 +437,19 @@ uint32_t do_trap(uint32_t cause, uint32_t epc, uint32_t isr_sp)
355437 uint32_t nibble = (epc >> i ) & 0xF ;
356438 _putchar (nibble < 10 ? '0' + nibble : 'A' + nibble - 10 );
357439 }
440+
441+ /* Debug: print mstatus from frame */
442+ trap_puts (" mstatus=0x" );
443+ uint32_t * f = (uint32_t * ) isr_sp ;
444+ uint32_t mstatus_at_trap = f [FRAME_MSTATUS ];
445+ for (int i = 28 ; i >= 0 ; i -= 4 ) {
446+ uint32_t nibble = (mstatus_at_trap >> i ) & 0xF ;
447+ _putchar (nibble < 10 ? '0' + nibble : 'A' + nibble - 10 );
448+ }
449+ trap_puts (" MPP=" );
450+ uint32_t mpp = (mstatus_at_trap >> 11 ) & 0x3 ;
451+ _putchar ('0' + mpp );
452+
358453 trap_puts ("\r\n" );
359454
360455 hal_panic ();
@@ -409,7 +504,9 @@ extern uint32_t _gp, _end;
409504 * 0: ra, 4: gp, 8: tp, 12: t0, ... 116: t6
410505 * 120: mcause, 124: mepc
411506 */
412- void * hal_build_initial_frame (void * stack_top , void (* task_entry )(void ))
507+ void * hal_build_initial_frame (void * stack_top ,
508+ void (* task_entry )(void ),
509+ int user_mode )
413510{
414511#define INITIAL_STACK_RESERVE \
415512 256 /* Reserve space below stack_top for task startup */
@@ -432,11 +529,16 @@ void *hal_build_initial_frame(void *stack_top, void (*task_entry)(void))
432529 /* Initialize critical registers for proper task startup:
433530 * - frame[1] = gp: Global pointer, required for accessing global variables
434531 * - frame[2] = tp: Thread pointer, required for thread-local storage
435- * - frame[31 ] = mepc: Task entry point, where mret will jump to
532+ * - frame[32 ] = mepc: Task entry point, where mret will jump to
436533 */
437- frame [1 ] = (uint32_t ) & _gp ; /* gp - global pointer */
438- frame [2 ] = tp_val ; /* tp - thread pointer */
439- frame [31 ] = (uint32_t ) task_entry ; /* mepc - entry point */
534+ frame [1 ] = (uint32_t ) & _gp ; /* gp - global pointer */
535+ frame [2 ] = tp_val ; /* tp - thread pointer */
536+
537+ uint32_t mstatus_val = MSTATUS_MIE | MSTATUS_MPIE |
538+ (user_mode ? MSTATUS_MPP_USER : MSTATUS_MPP_MACH );
539+ frame [FRAME_MSTATUS ] = mstatus_val ; /* mstatus - enable interrupts */
540+
541+ frame [FRAME_EPC ] = (uint32_t ) task_entry ; /* mepc - entry point */
440542
441543 return (void * ) frame ;
442544}
@@ -696,8 +798,9 @@ static void __attribute__((naked, used)) __dispatch_init(void)
696798 "lw gp, 12*4(a0)\n"
697799 "lw tp, 13*4(a0)\n"
698800 "lw sp, 14*4(a0)\n"
699- "lw ra, 15*4(a0)\n"
700- "ret\n" ); /* Jump to the task's entry point */
801+ "lw t0, 15*4(a0)\n"
802+ "csrw mepc, t0\n" /* Load task entry point into mepc */
803+ "mret\n" ); /* Jump to the task's entry point */
701804}
702805
703806/* Transfers control from the kernel's main thread to the first task */
@@ -721,12 +824,19 @@ __attribute__((noreturn)) void hal_dispatch_init(jmp_buf env)
721824}
722825
723826/* Builds an initial 'jmp_buf' context for a brand-new task.
724- * @ctx : Pointer to the 'jmp_buf' to initialize (must be valid).
725- * @sp : Base address of the task's stack (must be valid).
726- * @ss : Total size of the stack in bytes (must be > ISR_STACK_FRAME_SIZE).
727- * @ra : The task's entry point function, used as the initial return address.
827+ * @ctx : Pointer to the 'jmp_buf' to initialize (must be valid).
828+ * @sp : Base address of the task's stack (must be valid).
829+ * @ss : Total size of the stack in bytes (must be >
830+ * ISR_STACK_FRAME_SIZE).
831+ * @ra : The task's entry point function, used as the initial return
832+ * address.
833+ * @user_mode : Non-zero to initialize for user mode, zero for machine mode.
728834 */
729- void hal_context_init (jmp_buf * ctx , size_t sp , size_t ss , size_t ra )
835+ void hal_context_init (jmp_buf * ctx ,
836+ size_t sp ,
837+ size_t ss ,
838+ size_t ra ,
839+ int user_mode )
730840{
731841 if (unlikely (!ctx || !sp || ss < (ISR_STACK_FRAME_SIZE + 64 ) || !ra ))
732842 hal_panic (); /* Invalid parameters - cannot safely initialize context */
@@ -759,12 +869,13 @@ void hal_context_init(jmp_buf *ctx, size_t sp, size_t ss, size_t ra)
759869 /* Set the essential registers for a new task:
760870 * - SP is set to the prepared top of the task's stack.
761871 * - RA is set to the task's entry point.
762- * - mstatus is set to enable interrupts and ensure machine mode.
872+ * - mstatus is set to enable interrupts and configure privilege mode.
763873 *
764874 * When this context is first restored, the ret instruction will effectively
765875 * jump to this entry point, starting the task.
766876 */
767877 (* ctx )[CONTEXT_SP ] = (uint32_t ) stack_top ;
768878 (* ctx )[CONTEXT_RA ] = (uint32_t ) ra ;
769- (* ctx )[CONTEXT_MSTATUS ] = MSTATUS_MIE | MSTATUS_MPP_MACH ;
879+ (* ctx )[CONTEXT_MSTATUS ] = MSTATUS_MIE | MSTATUS_MPIE |
880+ (user_mode ? MSTATUS_MPP_USER : MSTATUS_MPP_MACH );
770881}
0 commit comments