@@ -1938,6 +1938,24 @@ static target_ulong promote_load_fault(target_ulong orig_cause)
1938
1938
/* if no promotion, return original cause */
1939
1939
return orig_cause ;
1940
1940
}
1941
+
1942
+ static void riscv_do_nmi (CPURISCVState * env , target_ulong cause , bool virt )
1943
+ {
1944
+ env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_NMIE , false);
1945
+ env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPV , virt );
1946
+ env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPP , env -> priv );
1947
+ env -> mncause = cause ;
1948
+ env -> mnepc = env -> pc ;
1949
+ env -> pc = env -> rnmi_irqvec ;
1950
+
1951
+ if (cpu_get_fcfien (env )) {
1952
+ env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPELP , env -> elp );
1953
+ }
1954
+
1955
+ /* Trapping to M mode, virt is disabled */
1956
+ riscv_cpu_set_mode (env , PRV_M , false);
1957
+ }
1958
+
1941
1959
/*
1942
1960
* Handle Traps
1943
1961
*
@@ -1977,22 +1995,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
1977
1995
bool nnmi_excep = false;
1978
1996
1979
1997
if (cpu -> cfg .ext_smrnmi && env -> rnmip && async ) {
1980
- env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_NMIE , false);
1981
- env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPV ,
1982
- env -> virt_enabled );
1983
- env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPP ,
1984
- env -> priv );
1985
- env -> mncause = cause | ((target_ulong )1U << (mxlen - 1 ));
1986
- env -> mnepc = env -> pc ;
1987
- env -> pc = env -> rnmi_irqvec ;
1988
-
1989
- if (cpu_get_fcfien (env )) {
1990
- env -> mnstatus = set_field (env -> mnstatus , MNSTATUS_MNPELP , env -> elp );
1991
- }
1992
-
1993
- /* Trapping to M mode, virt is disabled */
1994
- riscv_cpu_set_mode (env , PRV_M , false);
1995
-
1998
+ riscv_do_nmi (env , cause | ((target_ulong )1U << (mxlen - 1 )),
1999
+ env -> virt_enabled );
1996
2000
return ;
1997
2001
}
1998
2002
@@ -2204,11 +2208,32 @@ void riscv_cpu_do_interrupt(CPUState *cs)
2204
2208
/* Trapping to M mode, virt is disabled */
2205
2209
virt = false;
2206
2210
}
2211
+ /*
2212
+ * If the hart encounters an exception while executing in M-mode,
2213
+ * with the mnstatus.NMIE bit clear, the program counter is set to
2214
+ * the RNMI exception trap handler address.
2215
+ */
2216
+ nnmi_excep = cpu -> cfg .ext_smrnmi &&
2217
+ !get_field (env -> mnstatus , MNSTATUS_NMIE ) &&
2218
+ !async ;
2207
2219
2208
2220
s = env -> mstatus ;
2209
2221
s = set_field (s , MSTATUS_MPIE , get_field (s , MSTATUS_MIE ));
2210
2222
s = set_field (s , MSTATUS_MPP , env -> priv );
2211
2223
s = set_field (s , MSTATUS_MIE , 0 );
2224
+ if (cpu -> cfg .ext_smdbltrp ) {
2225
+ if (env -> mstatus & MSTATUS_MDT ) {
2226
+ assert (env -> priv == PRV_M );
2227
+ if (!cpu -> cfg .ext_smrnmi || nnmi_excep ) {
2228
+ cpu_abort (CPU (cpu ), "M-mode double trap\n" );
2229
+ } else {
2230
+ riscv_do_nmi (env , cause , false);
2231
+ return ;
2232
+ }
2233
+ }
2234
+
2235
+ s = set_field (s , MSTATUS_MDT , 1 );
2236
+ }
2212
2237
env -> mstatus = s ;
2213
2238
env -> mcause = cause | ((target_ulong )async << (mxlen - 1 ));
2214
2239
if (smode_double_trap ) {
0 commit comments