forked from Imagelibrary/rtems
cpu/riscv: Add Smdbltrp extension compatibility
If the Double Trap Extension is implemented, the MDT bit of the mstatus (or mstatush in RV32) register will be set when a trap is to be taken. The MIE (Machine Interrupt Enable) bit can only be set to 1 if the MDT bit is zero. Thus, we need to clear MDT first if we want to enable interrupts when dispatching a thread. MDT is also cleared in register a1 before restoring the interrupt frame as writing 1 to MDT will cause MIE to be set to 0. In RV64 this happens regardless of the value written to MIE in the same write. In RV32, MDT is in the mstatush so we do not need to clear during restore as this register is not restored. With this change all 60 SMP tests pass (compared to 20/60 before the fix). The tests have been run on hardware using two RV64 CPUs that implement the double trap extension. Update #5274
This commit is contained in:
committed by
Kinsey Moore
parent
20850e7e73
commit
19f12d2dca
@@ -45,6 +45,8 @@ extern "C" {
|
||||
#include <rtems/score/riscv.h>
|
||||
|
||||
#define RISCV_MSTATUS_MIE 0x8
|
||||
#define RISCV_MSTATUS_MDT 0x40000000000
|
||||
#define RISCV_MSTATUSH_MDT 0x400
|
||||
|
||||
#define CPU_ISR_PASSES_FRAME_POINTER FALSE
|
||||
|
||||
|
||||
@@ -106,6 +106,20 @@ SYM(_RISCV_Exception_handler):
|
||||
/* Check if this is a synchronous or interrupt exception */
|
||||
bgez a0, .Lsynchronous_exception
|
||||
|
||||
/*
|
||||
* Interrupt exception, clear MDT bit.
|
||||
* This is only necessary if the Smdbltrp extension is implemented.
|
||||
* In that case not clearing the MDT bit would prevent us from setting
|
||||
* the MIE bit later.
|
||||
*/
|
||||
#if __riscv_xlen == 64
|
||||
li t0, RISCV_MSTATUS_MDT
|
||||
csrrc zero, mstatus, t0
|
||||
#elif __riscv_xlen == 32
|
||||
li t0, RISCV_MSTATUSH_MDT
|
||||
csrrc zero, mstatush, t0
|
||||
#endif
|
||||
|
||||
/* Increment interrupt nest and thread dispatch disable level */
|
||||
lw t0, PER_CPU_ISR_NEST_LEVEL(s0)
|
||||
lw t1, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
|
||||
@@ -185,7 +199,6 @@ SYM(_RISCV_Exception_handler):
|
||||
/* Restore */
|
||||
LREG a0, RISCV_INTERRUPT_FRAME_MSTATUS(sp)
|
||||
LREG a1, RISCV_INTERRUPT_FRAME_MEPC(sp)
|
||||
LREG a2, RISCV_INTERRUPT_FRAME_A2(sp)
|
||||
LREG s0, RISCV_INTERRUPT_FRAME_S0(sp)
|
||||
LREG s1, RISCV_INTERRUPT_FRAME_S1(sp)
|
||||
LREG ra, RISCV_INTERRUPT_FRAME_RA(sp)
|
||||
@@ -201,6 +214,20 @@ SYM(_RISCV_Exception_handler):
|
||||
LREG t4, RISCV_INTERRUPT_FRAME_T4(sp)
|
||||
LREG t5, RISCV_INTERRUPT_FRAME_T5(sp)
|
||||
LREG t6, RISCV_INTERRUPT_FRAME_T6(sp)
|
||||
|
||||
/*
|
||||
* Clear MDT bit before restoring mstatus register.
|
||||
* This is only necessary if the Smdbltrp extension is implemented.
|
||||
* In that case, writing to mstatus with MDT set would clear the MIE
|
||||
* bit, regardless of the MIE value written.
|
||||
* On RV32, the MDT bit is in the mstatush CSR which is not restored.
|
||||
*/
|
||||
#if __riscv_xlen == 64
|
||||
li a2, RISCV_MSTATUS_MDT
|
||||
not a2, a2
|
||||
and a0, a0, a2
|
||||
#endif
|
||||
|
||||
csrw mstatus, a0
|
||||
csrw mepc, a1
|
||||
#if __riscv_flen > 0
|
||||
@@ -229,6 +256,7 @@ SYM(_RISCV_Exception_handler):
|
||||
#endif
|
||||
LREG a0, RISCV_INTERRUPT_FRAME_A0(sp)
|
||||
LREG a1, RISCV_INTERRUPT_FRAME_A1(sp)
|
||||
LREG a2, RISCV_INTERRUPT_FRAME_A2(sp)
|
||||
|
||||
addi sp, sp, CPU_INTERRUPT_FRAME_SIZE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user