diff --git a/riscv/triggers.cc b/riscv/triggers.cc index 68baedda..7a691643 100644 --- a/riscv/triggers.cc +++ b/riscv/triggers.cc @@ -3,6 +3,11 @@ #include "processor.h" #include "triggers.h" +#define ASIDMAX(SXLEN) (SXLEN == 32 ? 9 : 16) +#define SATP_ASID(SXLEN) (SXLEN == 32 ? SATP32_ASID : SATP64_ASID) +#define VMIDMAX(HSXLEN) (HSXLEN == 32 ? 7 : 14) +#define HGATP_VMID(HSXLEN) (HSXLEN == 32 ? HGATP32_VMID : HGATP64_VMID) + #define CSR_TEXTRA_MHVALUE(XLEN) (XLEN == 32 ? CSR_TEXTRA32_MHVALUE : CSR_TEXTRA64_MHVALUE) #define CSR_TEXTRA_MHSELECT(XLEN) (XLEN == 32 ? CSR_TEXTRA32_MHSELECT : CSR_TEXTRA64_MHSELECT) #define CSR_TEXTRA_SBYTEMASK(XLEN) (XLEN == 32 ? CSR_TEXTRA32_SBYTEMASK : CSR_TEXTRA64_SBYTEMASK) @@ -39,6 +44,21 @@ unsigned trigger_t::legalize_mhselect(bool h_enabled) const noexcept { return convert[mhselect]; } +mhselect_mode_t trigger_t::mhselect_mode(bool h_enabled) const noexcept { + switch (legalize_mhselect(h_enabled)) { + case 0: // ignore mhvalue + return MHSELECT_MODE_IGNORE; + case 4: // match only if mcontext equal mhvalue + case 1: // match only if mcontext equal {mhvalue, 1b'0} + case 5: // match only if mcontext equal {mhvalue, 1b'1} + return MHSELECT_MODE_MCONTEXT; + case 2: // match only if hgapt.VMID equal {mhvalue, 1b'0} + case 6: // match only if hgapt.VMID equal {mhvalue, 1b'1} + return MHSELECT_MODE_VMID; + default: assert(false); + } +} + reg_t trigger_t::tdata3_read(const processor_t * const proc) const noexcept { auto xlen = proc->get_xlen(); reg_t tdata3 = 0; @@ -59,6 +79,30 @@ 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_ASID) ? SSELECT_ASID : SSELECT_IGNORE); } +bool trigger_t::textra_match(processor_t * const proc) const noexcept +{ + auto xlen = proc->get_xlen(); + auto hsxlen = proc->get_xlen(); // use xlen since no hsxlen + state_t * const state = proc->get_state(); + + assert(sselect <= SSELECT_MAXVAL); + if (sselect == SSELECT_ASID) { + const reg_t satp = state->satp->read(); + const reg_t asid = get_field(satp, SATP_ASID(xlen)); + if (asid != (svalue & ((1 << ASIDMAX(xlen)) - 1))) + return false; + } + + mhselect_mode_t mode = mhselect_mode(proc->extension_enabled('H')); + if (mode == MHSELECT_MODE_VMID) { // 2 and 6 are vmid + const reg_t vmid = get_field(state->hgatp->read(), HGATP_VMID(hsxlen)); + if (vmid != (mhselect_compare(proc->extension_enabled('H')) & ((1 << VMIDMAX(hsxlen)) - 1))) + return false; + } + + return true; +} + reg_t disabled_trigger_t::tdata1_read(const processor_t * const proc) const noexcept { auto xlen = proc->get_xlen(); @@ -410,7 +454,7 @@ std::optional module_t::detect_memory_access_match(operation_t o * entire chain did not match. This is allowed by the spec, because the final * trigger in the chain will never get `hit` set unless the entire chain * matches. */ - auto result = trigger->detect_memory_access_match(proc, operation, address, data); + auto result = trigger->textra_match(proc) ? trigger->detect_memory_access_match(proc, operation, address, data) : std::nullopt; if (result.has_value() && !trigger->get_chain()) return result; @@ -426,7 +470,7 @@ std::optional module_t::detect_trap_match(const trap_t& t) noexc return std::nullopt; for (auto trigger: triggers) { - auto result = trigger->detect_trap_match(proc, t); + auto result = trigger->textra_match(proc) ? trigger->detect_trap_match(proc, t) : std::nullopt; if (result.has_value()) return result; } diff --git a/riscv/triggers.h b/riscv/triggers.h index bf164d33..9ce465ac 100644 --- a/riscv/triggers.h +++ b/riscv/triggers.h @@ -36,6 +36,12 @@ typedef enum { SSELECT_MAXVAL = 2 } sselect_t; +typedef enum { + MHSELECT_MODE_IGNORE, + MHSELECT_MODE_MCONTEXT, + MHSELECT_MODE_VMID, +} mhselect_mode_t; + struct match_result_t { match_result_t(const timing_t t=TIMING_BEFORE, const action_t a=ACTION_DEBUG_EXCEPTION) { timing = t; @@ -77,6 +83,7 @@ public: virtual std::optional detect_memory_access_match(processor_t UNUSED * const proc, operation_t UNUSED operation, reg_t UNUSED address, std::optional UNUSED data) noexcept { return std::nullopt; } virtual std::optional detect_trap_match(processor_t UNUSED * const proc, const trap_t UNUSED & t) noexcept { return std::nullopt; } + bool textra_match(processor_t * const proc) const noexcept; protected: action_t legalize_action(reg_t val) const noexcept; @@ -84,6 +91,10 @@ protected: private: unsigned legalize_mhselect(bool h_enabled) const noexcept; + mhselect_mode_t mhselect_mode(bool h_enabled) const noexcept; + unsigned mhselect_compare(bool h_enabled) const noexcept { + return legalize_mhselect(h_enabled) == 4 ? mhvalue : (mhvalue << 1) + (mhselect >> 2); // mhvalue or {mhvalue, mhselect[2]} + } sselect_t sselect; unsigned svalue; unsigned sbytemask;