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


Reply via email to