-
Notifications
You must be signed in to change notification settings - Fork 100
When the trigger action is set to 0, there is inconsistency between SPEC and SPIKE in handling the prevention of trap re-entry #1216
Description
RV DEBUG SPEC says:
For native triggers:
In these cases such a trigger may cause a breakpoint exception while already in a trap handler. This might leave the hart unable to resume normal execution because state such as mcause and mepc would be overwritten.
Harts that support triggers with action=0 should implement one of the following two solutions to solve the problem of reentrancy:
- The hardware prevents triggers with action=0 from matching or firing while in M-mode and while MIE in mstatus is 0. If medeleg [3]=1 then it prevents triggers with action=0 from matching or firing while in S-mode and while SIE in sstatus is 0. If medeleg [3]=1 and hedeleg [3]=1 then it prevents triggers with action=0 from matching or firing while in VS-mode and while SIE in vstatus is 0.
- mte and mpte in tcontrol is implemented. medeleg [3] is hard-wired to 0.
Both options prevent etrigger and itrigger from having any effect on exceptions and interrupts that are handled in M-mode. They also prevent triggering during some initial portion of each handler. Debuggers should use other mechanisms to debug these cases, such as patching the handler or setting a breakpoint on the instruction after MIE is cleared.
RV SPEC implement:
auto prv = use_prev_prv ? state->prev_prv : state->prv;
auto v = use_prev_prv ? state->prev_v : state->v;
if (!mode_match(prv, v))
return false;
if (!textra_match(proc))
return false;
if (get_action() == ACTION_DEBUG_EXCEPTION) {
if (proc->extension_enabled('S')) {
// The hardware prevents triggers with action=0 from matching or firing
// while in M-mode and while MIE in mstatus is 0. If medeleg [3]=1 then it
// prevents triggers with action=0 from matching or firing while in S-mode
// and while SIE in sstatus is 0. If medeleg [3]=1 and hedeleg [3]=1 then
// it prevents triggers with action=0 from matching or firing while in
// VS-mode and while SIE in vstatus is 0.
const bool mstatus_mie = state->mstatus->read() & MSTATUS_MIE;
if (prv == PRV_M && !mstatus_mie)
return false;
const bool sstatus_sie = state->sstatus->read() & MSTATUS_SIE;
const bool medeleg_breakpoint = (state->medeleg->read() >> CAUSE_BREAKPOINT) & 1;
if (prv == PRV_S && !v && medeleg_breakpoint && !sstatus_sie)
return false;
const bool vsstatus_sie = state->vsstatus->read() & MSTATUS_SIE;
const bool hedeleg_breakpoint = (state->hedeleg->read() >> CAUSE_BREAKPOINT) & 1;
if (prv == PRV_S && v && medeleg_breakpoint && hedeleg_breakpoint && !vsstatus_sie)
return false;
} else {
// mte and mpte in tcontrol is implemented. medeleg [3] is hard-wired to 0.
if (prv == PRV_M && !(tcontrol_value(state) & CSR_TCONTROL_MTE))
return false;
}
Namely, the SPEC description and spike implementation are inconsistent,
For example: S-mode page fault enters M-mode, Mstatus. MIE=0, Mstatus. SIE=1. Simultaneously configured with action=0 and able to capture page faults using an etrigger.
According to the spec description, the etrigger should not trigger, M-mode, And Mstatus. MIE=0
The implementation of Spike uses S-mode, with Mstatus. SIE=1, so the etrigger can trigger normally.