[PATCH 07/13] hw/riscv/trace-encoder: add interrupt support to N-Trace encoder
Konstantin Semichastnov <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Now IndirectBranchHist messages sent not only when branch executed, but also when exceptino or trap happen. Signed-off-by: Konstantin Semichastnov <[email protected]> --- disas/riscv.c | 2 +- disas/riscv.h | 2 ++ hw/riscv/trace-encoder.c | 36 +++++++++++++++++++++++++++++------- hw/riscv/trace-encoder.h | 7 +++---- target/riscv/cpu_helper.c | 21 ++++++++++++--------- 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 85cd2a9c2a..541fc93e0a 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5058,7 +5058,7 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c) /* instruction length */ -static size_t inst_length(rv_inst inst) +size_t inst_length(rv_inst inst) { /* NOTE: supports maximum instruction size of 64-bits */ diff --git a/disas/riscv.h b/disas/riscv.h index d211700cb2..c14c159103 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -306,4 +306,6 @@ enum { #define rv_fmt_rd2_imm "O\t0,2,(1),i" #define rv_fmt_fli "O\t3,h" +size_t inst_length(rv_inst inst); + #endif /* DISAS_RISCV_H */ diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c index fafafb7b9b..face6f83b7 100644 --- a/hw/riscv/trace-encoder.c +++ b/hw/riscv/trace-encoder.c @@ -22,6 +22,8 @@ #include "cpu.h" #include "hw/riscv/trace-ram-sink.h" #include "rv-trace-messages.h" +#include "system/dma.h" +#include "disas/riscv.h" /* * Size of header + payload since we're not sending @@ -229,6 +231,23 @@ static uint64_t trencoder_te_ctrl_prew(RegisterInfo *reg, uint64_t val) return val; } +static uint32_t get_inst_len_at(uint64_t pc) +{ + bfd_byte packet[2]; + uint16_t opcode; + MemTxResult status; + + status = dma_memory_read(&address_space_memory, pc, packet, 2, + MEMTXATTRS_UNSPECIFIED); + if (status != MEMTX_OK) { + error_setg(&error_fatal, "failed to read instruction during trace operation"); + } + + opcode = bfd_getl16(packet); + + return inst_length(opcode); +} + static void trencoder_te_ctrl_postw(RegisterInfo *reg, uint64_t val) { TraceEncoder *te = TRACE_ENCODER(reg->opaque); @@ -639,10 +658,9 @@ static uint32_t rv_ntrace_get_and_reset_icnt(TraceEncoder *trencoder, return icnt; } -void trencoder_trace_trap_insn(Object *trencoder_obj, - uint64_t pc, uint32_t ecause, - bool is_interrupt, - uint64_t tval) +void trencoder_trace_trap_insn(Object *trencoder_obj, uint64_t curr_pc, + uint64_t target_pc, uint32_t ecause, + bool is_interrupt, uint64_t tval) { TraceEncoder *trencoder = TRACE_ENCODER(trencoder_obj); TracePrivLevel priv = trencoder_get_curr_priv_level(trencoder); @@ -650,15 +668,19 @@ void trencoder_trace_trap_insn(Object *trencoder_obj, uint8_t msg_size; if (trencoder->ntrace) { - /* send IndirectBranchHist message */ + uint32_t curr_inst_len = get_inst_len_at(curr_pc); + uint32_t btype = is_interrupt ? BTYPE_INTERRUPT : BTYPE_EXCEPTION; + + trencoder_send_indirect_branch_hist(trencoder, curr_pc, curr_inst_len, + target_pc, btype); return; } if (trencoder->updiscon_pending) { - trencoder_send_updiscon(trencoder, pc); + trencoder_send_updiscon(trencoder, curr_pc); } - msg_size = rv_etrace_gen_encoded_trap_msg(msg, pc, priv, + msg_size = rv_etrace_gen_encoded_trap_msg(msg, curr_pc, priv, ecause, is_interrupt, tval); diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h index f8a6a254dc..d1ff813035 100644 --- a/hw/riscv/trace-encoder.h +++ b/hw/riscv/trace-encoder.h @@ -74,10 +74,9 @@ void trencoder_send_indirect_branch_hist(TraceEncoder *trencoder, uint32_t curr_inst_len, uint64_t target_pc, TraceBranchType btype); -void trencoder_trace_trap_insn(Object *trencoder_obj, - uint64_t pc, uint32_t ecause, - bool is_interrupt, - uint64_t tval); +void trencoder_trace_trap_insn(Object *trencoder_obj, uint64_t curr_pc, + uint64_t target_pc, uint32_t ecause, + bool is_interrupt, uint64_t tval); void trencoder_trace_ppccd(Object *trencoder_obj, uint64_t pc); void trencoder_report_updiscon(Object *trencoder_obj); void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 665aad6dea..9b7df4d4fd 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -2300,15 +2300,6 @@ void riscv_cpu_do_interrupt(CPUState *cs) __func__, env->mhartid, async, cause, env->pc, tval, riscv_cpu_get_trap_name(cause, async)); - if (cpu->trencoder) { - TraceEncoder *te = TRACE_ENCODER(cpu->trencoder); - - if (te->trace_running) { - trencoder_trace_trap_insn(cpu->trencoder, env->pc, - cause, async, tval); - } - } - mode = env->priv <= PRV_S && cause < 64 && (((deleg >> cause) & 1) || s_injected || vs_injected) ? PRV_S : PRV_M; @@ -2391,6 +2382,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->htinst = tinst; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); + + if (cpu->trencoder && TRACE_ENCODER(cpu->trencoder)->trace_running) { + trencoder_trace_trap_insn(cpu->trencoder, env->sepc, env->pc, + env->scause, async, env->stval); + } + riscv_cpu_set_mode(env, PRV_S, virt); src = env->sepc; @@ -2477,6 +2474,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); } + + if (cpu->trencoder && TRACE_ENCODER(cpu->trencoder)->trace_running) { + trencoder_trace_trap_insn(cpu->trencoder, env->mepc, env->pc, + env->mcause, async, env->mtval); + } + riscv_cpu_set_mode(env, PRV_M, virt); src = env->mepc; } -- 2.43.0