Skip to content

Commit 7ce46f3

Browse files
committed
Handle U-mode ecall for syscall dispatch
Adds exception handler for U-mode ecall instructions to dispatch system calls. Defines ISR frame register indices as an enum and uses them to extract syscall number and arguments from the saved register context, returning 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.
1 parent f36e7c5 commit 7ce46f3

File tree

1 file changed

+68
-5
lines changed

1 file changed

+68
-5
lines changed

arch/riscv/hal.c

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,45 @@
4242
*/
4343
#define ISR_STACK_FRAME_SIZE 128
4444

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+
};
83+
4584
/* Global variable to hold the new stack pointer for pending context switch.
4685
* When a context switch is needed, hal_switch_stack() saves the current SP
4786
* and stores the new SP here. The ISR epilogue then uses this value.
@@ -321,19 +360,43 @@ uint32_t do_trap(uint32_t cause, uint32_t epc, uint32_t isr_sp)
321360
} else { /* Synchronous Exception */
322361
uint32_t code = MCAUSE_GET_CODE(cause);
323362

363+
/* Handle ecall from U-mode - system calls */
364+
if (code == MCAUSE_ECALL_UMODE) {
365+
/* Advance mepc past the ecall instruction (4 bytes) */
366+
uint32_t new_epc = epc + 4;
367+
write_csr(mepc, new_epc);
368+
369+
/* Extract syscall arguments from ISR frame */
370+
uint32_t *f = (uint32_t *) isr_sp;
371+
372+
int syscall_num = f[FRAME_A7];
373+
void *arg1 = (void *) f[FRAME_A0];
374+
void *arg2 = (void *) f[FRAME_A1];
375+
void *arg3 = (void *) f[FRAME_A2];
376+
377+
/* Dispatch to syscall handler */
378+
extern int syscall(int num, void *arg1, void *arg2, void *arg3);
379+
int retval = syscall(syscall_num, arg1, arg2, arg3);
380+
381+
/* Store return value and updated PC */
382+
f[FRAME_A0] = (uint32_t) retval;
383+
f[FRAME_EPC] = new_epc;
384+
385+
return isr_sp;
386+
}
387+
324388
/* Handle ecall from M-mode - used for yielding in preemptive mode */
325389
if (code == MCAUSE_ECALL_MMODE) {
326390
/* Advance mepc past the ecall instruction (4 bytes) */
327391
uint32_t new_epc = epc + 4;
328392
write_csr(mepc, new_epc);
329393

330394
/* 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!
395+
* The ISR epilogue will restore mepc from the frame. If we don't
396+
* update the frame, mret will jump back to the ecall instruction!
334397
*/
335-
uint32_t *isr_frame = (uint32_t *) isr_sp;
336-
isr_frame[31] = new_epc;
398+
uint32_t *f = (uint32_t *) isr_sp;
399+
f[FRAME_EPC] = new_epc;
337400

338401
/* Invoke dispatcher for context switch - parameter 0 = from ecall,
339402
* don't increment ticks.

0 commit comments

Comments
 (0)