[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.