4
4
*/
5
5
6
6
#include <assert.h>
7
+ #include <setjmp.h>
7
8
#include <stdbool.h>
8
9
#include <stdint.h>
9
10
#include <stdio.h>
@@ -43,7 +44,7 @@ extern struct target_ops gdbstub_ops;
43
44
44
45
/* RISC-V exception code list */
45
46
/* clang-format off */
46
- #define RV_EXCEPTION_LIST \
47
+ #define RV_TRAP_LIST \
47
48
IIF(RV32_HAS(EXT_C))(, \
48
49
_(insn_misaligned, 0) /* Instruction address misaligned */ \
49
50
) \
@@ -55,17 +56,32 @@ extern struct target_ops gdbstub_ops;
55
56
/* clang-format on */
56
57
57
58
enum {
58
- #define _(type, code) rv_exception_code ##type = code,
59
- RV_EXCEPTION_LIST
59
+ #define _(type, code) rv_trap_code_ ##type = code,
60
+ RV_TRAP_LIST
60
61
#undef _
61
62
};
62
63
63
- static void rv_exception_default_handler (riscv_t * rv )
64
+ static void rv_trap_default_handler (riscv_t * rv )
64
65
{
65
66
rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
66
67
rv -> PC = rv -> csr_mepc ; /* mret */
67
68
}
68
69
70
+ /* Trap might occurs during block emulation. For instance, page fault.
71
+ * In order to handle trap, we have to escape from block and execute
72
+ * registered trap handler. This trap_handler function helps to execute
73
+ * the registered trap handler, PC by PC. Once the trap is handled,
74
+ * resume the previous execution flow where cause the trap.
75
+ */
76
+ #if RV32_HAS (SYSTEM )
77
+ static void trap_handler (riscv_t * rv );
78
+ #else
79
+ /* should not be called in non-SYSTEM mode since default trap handler is capable
80
+ * to handle traps
81
+ */
82
+ static void trap_handler (riscv_t * rv UNUSED ) {}
83
+ #endif
84
+
69
85
/* When a trap occurs in M-mode, mtval is either initialized to zero or
70
86
* populated with exception-specific details to assist software in managing
71
87
* the trap. Otherwise, the implementation never modifies mtval, although
@@ -82,43 +98,80 @@ static void rv_exception_default_handler(riscv_t *rv)
82
98
* it is worth noting that a future standard could redefine how mtval is
83
99
* handled for different types of traps.
84
100
*/
85
- #define EXCEPTION_HANDLER_IMPL (type , code ) \
86
- static void rv_except_##type(riscv_t *rv, uint32_t mtval) \
87
- { \
88
- /* mtvec (Machine Trap-Vector Base Address Register) \
89
- * mtvec[MXLEN-1:2]: vector base address \
90
- * mtvec[1:0] : vector mode \
91
- */ \
92
- const uint32_t base = rv -> csr_mtvec & ~0x3 ; \
93
- const uint32_t mode = rv -> csr_mtvec & 0x3 ; \
94
- /* mepc (Machine Exception Program Counter) \
95
- * mtval (Machine Trap Value Register) \
96
- * mcause (Machine Cause Register): store exception code \
97
- * mstatus (Machine Status Register): keep track of and controls the \
98
- * hart’s current operating state \
99
- */ \
100
- rv -> csr_mepc = rv -> PC ; \
101
- rv -> csr_mtval = mtval ; \
102
- rv -> csr_mcause = code ; \
103
- rv -> csr_mstatus = MSTATUS_MPP ; /* set privilege mode */ \
104
- if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
105
- rv_exception_default_handler (rv ); \
106
- return ; \
107
- } \
108
- switch (mode ) { \
109
- case 0 : /* DIRECT: All exceptions set PC to base */ \
110
- rv -> PC = base ; \
111
- break ; \
112
- /* VECTORED: Asynchronous interrupts set PC to base + 4 * code */ \
113
- case 1 : \
114
- rv -> PC = base + 4 * code ; \
115
- break ; \
116
- } \
101
+ static jmp_buf env ;
102
+ #define TRAP_HANDLER_IMPL (type , code ) \
103
+ static void rv_trap_##type(riscv_t *rv, uint32_t mtval) \
104
+ { \
105
+ /* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
106
+ * m/stvec[MXLEN-1:2]: vector base address \
107
+ * m/stvec[1:0] : vector mode \
108
+ */ \
109
+ uint32_t base ; \
110
+ uint32_t mode ; \
111
+ /* m/sepc (Machine/Supervisor Exception Program Counter) \
112
+ * m/stval (Machine/Supervisor Trap Value Register) \
113
+ * m/scause (Machine/Supervisor Cause Register): store exception code \
114
+ * m/sstatus (Machine/Supervisor Status Register): keep track of and \
115
+ * controls the hart’s current operating state \
116
+ */ \
117
+ /* supervisor */ \
118
+ if (rv -> csr_medeleg & (1U << code ) || \
119
+ rv -> csr_mideleg & (1U << code )) { \
120
+ const uint32_t sstatus_sie = \
121
+ (rv -> csr_sstatus & SSTATUS_SIE ) >> SSTATUS_SIE_SHIFT ; \
122
+ rv -> csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT ); \
123
+ rv -> csr_sstatus &= ~(SSTATUS_SIE ); \
124
+ rv -> csr_sstatus |= (rv -> priv_mode << SSTATUS_SPP_SHIFT ); \
125
+ rv -> priv_mode = RV_PRIV_S_MODE ; \
126
+ base = rv -> csr_stvec & ~0x3 ; \
127
+ mode = rv -> csr_stvec & 0x3 ; \
128
+ rv -> csr_sepc = rv -> PC ; \
129
+ rv -> csr_stval = mtval ; \
130
+ rv -> csr_scause = code ; \
131
+ rv -> csr_sstatus |= SSTATUS_SPP ; /* set privilege mode */ \
132
+ } else { /* machine */ \
133
+ const uint32_t mstatus_mie = \
134
+ (rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ; \
135
+ rv -> csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT ); \
136
+ rv -> csr_mstatus &= ~(MSTATUS_MIE ); \
137
+ rv -> csr_mstatus |= (rv -> priv_mode << MSTATUS_MPP_SHIFT ); \
138
+ rv -> priv_mode = RV_PRIV_M_MODE ; \
139
+ base = rv -> csr_mtvec & ~0x3 ; \
140
+ mode = rv -> csr_mtvec & 0x3 ; \
141
+ rv -> csr_mepc = rv -> PC ; \
142
+ rv -> csr_mtval = mtval ; \
143
+ rv -> csr_mcause = code ; \
144
+ rv -> csr_mstatus |= MSTATUS_MPP ; /* set privilege mode */ \
145
+ if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
146
+ rv_trap_default_handler (rv ); \
147
+ return ; \
148
+ } \
149
+ } \
150
+ switch (mode ) { \
151
+ /* DIRECT: All traps set PC to base */ \
152
+ case 0 : \
153
+ rv -> PC = base ; \
154
+ break ; \
155
+ /* VECTORED: Asynchronous traps set PC to base + 4 * code */ \
156
+ case 1 : \
157
+ /* MSB of code is used to indicate whether the trap is interrupt \
158
+ * or exception, so it is not considered as the 'real' code */ \
159
+ rv -> PC = base + 4 * (code & MASK (31 )); \
160
+ break ; \
161
+ } \
162
+ /* block escaping for trap handling */ \
163
+ if (rv -> is_trapped ) { \
164
+ if (setjmp (env ) == 0 ) { \
165
+ trap_handler (rv ); \
166
+ } else { \
167
+ fprintf (stderr , "setjmp failed" ); \
168
+ } \
169
+ } \
117
170
}
118
171
119
172
/* RISC-V exception handlers */
120
- #define _ (type , code ) EXCEPTION_HANDLER_IMPL (type, code)
121
- RV_EXCEPTION_LIST
173
+ #define _ (type , code ) TRAP_HANDLER_IMPL (type, code)
174
+ RV_TRAP_LIST
122
175
#undef _
123
176
124
177
/* wrap load/store and insn misaligned handler
@@ -135,7 +188,7 @@ RV_EXCEPTION_LIST
135
188
rv->compressed = compress; \
136
189
rv->csr_cycle = cycle; \
137
190
rv->PC = PC; \
138
- rv_except_ ##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
191
+ rv_trap_ ##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
139
192
return false; \
140
193
}
141
194
@@ -196,6 +249,26 @@ static uint32_t *csr_get_ptr(riscv_t *rv, uint32_t csr)
196
249
case CSR_FCSR :
197
250
return (uint32_t * ) (& rv -> csr_fcsr );
198
251
#endif
252
+ case CSR_SSTATUS :
253
+ return (uint32_t * ) (& rv -> csr_sstatus );
254
+ case CSR_SIE :
255
+ return (uint32_t * ) (& rv -> csr_sie );
256
+ case CSR_STVEC :
257
+ return (uint32_t * ) (& rv -> csr_stvec );
258
+ case CSR_SCOUNTEREN :
259
+ return (uint32_t * ) (& rv -> csr_scounteren );
260
+ case CSR_SSCRATCH :
261
+ return (uint32_t * ) (& rv -> csr_sscratch );
262
+ case CSR_SEPC :
263
+ return (uint32_t * ) (& rv -> csr_sepc );
264
+ case CSR_SCAUSE :
265
+ return (uint32_t * ) (& rv -> csr_scause );
266
+ case CSR_STVAL :
267
+ return (uint32_t * ) (& rv -> csr_stval );
268
+ case CSR_SIP :
269
+ return (uint32_t * ) (& rv -> csr_sip );
270
+ case CSR_SATP :
271
+ return (uint32_t * ) (& rv -> csr_satp );
199
272
default :
200
273
return NULL ;
201
274
}
@@ -377,9 +450,9 @@ enum {
377
450
};
378
451
379
452
#if RV32_HAS (GDBSTUB )
380
- #define RVOP_NO_NEXT (ir ) (!ir->next | rv->debug_mode)
453
+ #define RVOP_NO_NEXT (ir ) (!ir->next | rv->debug_mode | rv->is_trapped )
381
454
#else
382
- #define RVOP_NO_NEXT (ir ) (!ir->next)
455
+ #define RVOP_NO_NEXT (ir ) (!ir->next | rv->is_trapped )
383
456
#endif
384
457
385
458
/* record whether the branch is taken or not during emulation */
@@ -598,7 +671,7 @@ static void block_translate(riscv_t *rv, block_t *block)
598
671
/* decode the instruction */
599
672
if (!rv_decode (ir , insn )) {
600
673
rv -> compressed = is_compressed (insn );
601
- rv_except_illegal_insn (rv , insn );
674
+ rv_trap_illegal_insn (rv , insn );
602
675
break ;
603
676
}
604
677
ir -> impl = dispatch_table [ir -> opcode ];
@@ -1048,16 +1121,33 @@ void rv_step(void *arg)
1048
1121
#endif
1049
1122
}
1050
1123
1124
+ #if RV32_HAS (SYSTEM )
1125
+ static void trap_handler (riscv_t * rv )
1126
+ {
1127
+ rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1128
+ assert (ir );
1129
+
1130
+ uint32_t insn ;
1131
+ while (rv -> is_trapped ) { /* set to false by sret/mret implementation */
1132
+ insn = rv -> io .mem_ifetch (rv , rv -> PC );
1133
+ rv_decode (ir , insn );
1134
+ ir -> impl = dispatch_table [ir -> opcode ];
1135
+ rv -> compressed = is_compressed (insn );
1136
+ ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
1137
+ }
1138
+ }
1139
+ #endif
1140
+
1051
1141
void ebreak_handler (riscv_t * rv )
1052
1142
{
1053
1143
assert (rv );
1054
- rv_except_breakpoint (rv , rv -> PC );
1144
+ rv_trap_breakpoint (rv , rv -> PC );
1055
1145
}
1056
1146
1057
1147
void ecall_handler (riscv_t * rv )
1058
1148
{
1059
1149
assert (rv );
1060
- rv_except_ecall_M (rv , 0 );
1150
+ rv_trap_ecall_M (rv , 0 );
1061
1151
syscall_handler (rv );
1062
1152
}
1063
1153
0 commit comments