diff --git a/riscv/processor.cc b/riscv/processor.cc index 74a0b8fe..23284b87 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -196,8 +196,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) // mstatus_csr_t::unlogged_write()): auto xlen = proc->get_isa().get_max_xlen(); - prv = PRV_M; - v = false; + prv = prev_prv = PRV_M; + v = prev_v = false; csrmap[CSR_MISA] = misa = std::make_shared(proc, CSR_MISA, max_isa); mstatus = std::make_shared(proc, CSR_MSTATUS); @@ -717,6 +717,7 @@ reg_t processor_t::legalize_privilege(reg_t prv) void processor_t::set_privilege(reg_t prv) { mmu->flush_tlb(); + state.prev_prv = state.prv; state.prv = legalize_privilege(prv); } @@ -747,17 +748,16 @@ void processor_t::set_virt(bool virt) if (state.prv == PRV_M) return; - if (state.v != virt) { - /* - * Ideally, we should flush TLB here but we don't need it because - * set_virt() is always used in conjucter with set_privilege() and - * set_privilege() will flush TLB unconditionally. - * - * The virtualized sstatus register also relies on this TLB flush, - * since changing V might change sstatus.MXR and sstatus.SUM. - */ - state.v = virt; - } + /* + * Ideally, we should flush TLB here but we don't need it because + * set_virt() is always used in conjucter with set_privilege() and + * set_privilege() will flush TLB unconditionally. + * + * The virtualized sstatus register also relies on this TLB flush, + * since changing V might change sstatus.MXR and sstatus.SUM. + */ + state.prev_v = state.v; + state.v = virt; } void processor_t::enter_debug_mode(uint8_t cause) diff --git a/riscv/processor.h b/riscv/processor.h index 1b74cc27..34354c22 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -83,7 +83,9 @@ struct state_t // control and status registers std::unordered_map csrmap; reg_t prv; // TODO: Can this be an enum instead? + reg_t prev_prv; bool v; + bool prev_v; misa_csr_t_p misa; mstatus_csr_t_p mstatus; csr_t_p mstatush; diff --git a/riscv/triggers.cc b/riscv/triggers.cc index 86dcc81a..65ba4c9b 100644 --- a/riscv/triggers.cc +++ b/riscv/triggers.cc @@ -55,16 +55,19 @@ void trigger_t::tdata3_write(processor_t * const proc, const reg_t val) noexcept sselect = (sselect_t)((proc->extension_enabled_const('S') && get_field(val, CSR_TEXTRA_SSELECT(xlen)) <= SSELECT_MAXVAL) ? get_field(val, CSR_TEXTRA_SSELECT(xlen)) : SSELECT_IGNORE); } -bool trigger_t::common_match(processor_t * const proc) const noexcept { - return mode_match(proc->get_state()) && textra_match(proc); +bool trigger_t::common_match(processor_t * const proc, bool use_prev_prv) const noexcept { + auto state = proc->get_state(); + auto prv = use_prev_prv ? state->prev_prv : state->prv; + auto v = use_prev_prv ? state->prev_v : state->v; + return mode_match(prv, v) && textra_match(proc); } -bool trigger_t::mode_match(state_t * const state) const noexcept +bool trigger_t::mode_match(reg_t prv, bool v) const noexcept { - switch (state->prv) { + switch (prv) { case PRV_M: return m; - case PRV_S: return state->v ? vs : s; - case PRV_U: return state->v ? vu : u; + case PRV_S: return v ? vs : s; + case PRV_U: return v ? vu : u; default: assert(false); } } @@ -397,7 +400,8 @@ void itrigger_t::tdata1_write(processor_t * const proc, const reg_t val, const b std::optional trap_common_t::detect_trap_match(processor_t * const proc, const trap_t& t) noexcept { - if (!common_match(proc)) + // Use the previous privilege for matching + if (!common_match(proc, true)) return std::nullopt; auto xlen = proc->get_xlen(); diff --git a/riscv/triggers.h b/riscv/triggers.h index aeda4d58..0bf6097a 100644 --- a/riscv/triggers.h +++ b/riscv/triggers.h @@ -90,7 +90,7 @@ public: protected: static action_t legalize_action(reg_t val, reg_t action_mask, reg_t dmode_mask) noexcept; - bool common_match(processor_t * const proc) const noexcept; + bool common_match(processor_t * const proc, bool use_prev_prv = false) const noexcept; bool allow_action(const state_t * const state) const; reg_t tdata2; @@ -102,7 +102,7 @@ protected: private: unsigned legalize_mhselect(bool h_enabled) const noexcept; - bool mode_match(state_t * const state) const noexcept; + bool mode_match(reg_t prv, bool v) const noexcept; bool textra_match(processor_t * const proc) const noexcept; struct mhselect_interpretation {