|
42 | 42 | */ |
43 | 43 | #define ISR_STACK_FRAME_SIZE 128 |
44 | 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 | +}; |
| 83 | + |
45 | 84 | /* Global variable to hold the new stack pointer for pending context switch. |
46 | 85 | * When a context switch is needed, hal_switch_stack() saves the current SP |
47 | 86 | * 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) |
321 | 360 | } else { /* Synchronous Exception */ |
322 | 361 | uint32_t code = MCAUSE_GET_CODE(cause); |
323 | 362 |
|
| 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 | + |
324 | 388 | /* Handle ecall from M-mode - used for yielding in preemptive mode */ |
325 | 389 | if (code == MCAUSE_ECALL_MMODE) { |
326 | 390 | /* Advance mepc past the ecall instruction (4 bytes) */ |
327 | 391 | uint32_t new_epc = epc + 4; |
328 | 392 | write_csr(mepc, new_epc); |
329 | 393 |
|
330 | 394 | /* 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! |
334 | 397 | */ |
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; |
337 | 400 |
|
338 | 401 | /* Invoke dispatcher for context switch - parameter 0 = from ecall, |
339 | 402 | * don't increment ticks. |
|
0 commit comments