We'll have to instrument some RISC-V translations, as well as the start of a translation block, communicating with the associated trace encoder in case we're running a trace session. The trace encoder needs to report the first insn of the session so we'll start with that.
Add a new EXT_TB_FLAGS called CPU_TRACE_RUNNING, along with its ctx->cpu_trace_running boolean, to track when we should call the hwtrace helpers. For now we care about just the first insn of the trace session. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/riscv/trace-encoder.c | 17 ++++++++++++++++ hw/riscv/trace-encoder.h | 4 ++++ hw/riscv/trace-events | 1 + target/riscv/cpu.h | 3 +++ target/riscv/helper.h | 4 ++++ target/riscv/tcg/meson.build | 6 ++++++ target/riscv/tcg/tcg-cpu.c | 4 ++++ target/riscv/tcg/trace_helper.c | 36 +++++++++++++++++++++++++++++++++ target/riscv/tcg/translate.c | 9 +++++++++ 9 files changed, 84 insertions(+) create mode 100644 target/riscv/tcg/trace_helper.c diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c index 99399a55e1..1f89dc24fc 100644 --- a/hw/riscv/trace-encoder.c +++ b/hw/riscv/trace-encoder.c @@ -150,11 +150,15 @@ static void trencoder_te_ctrl_postw(RegisterInfo *reg, uint64_t val) uint32_t trTeEnable = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL, ENABLE); uint32_t trTeInstTracing = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL, INST_TRACING); + RISCVCPU *cpu = te->cpu; + CPURISCVState *env = &cpu->env; if (!trTeActive) { te->enabled = false; te->trace_running = false; te->trace_next_insn = false; + + env->trace_running = false; return; } @@ -170,6 +174,7 @@ static void trencoder_te_ctrl_postw(RegisterInfo *reg, uint64_t val) } te->trace_running = trTeInstTracing ? true : false; + env->trace_running = te->trace_running; } static RegisterAccessInfo trencoder_regs_info[] = { @@ -231,6 +236,8 @@ static const MemoryRegionOps trencoder_ops = { static void trencoder_reset(DeviceState *dev) { TraceEncoder *te = TRACE_ENCODER(dev); + RISCVCPU *cpu = te->cpu; + CPURISCVState *env = &cpu->env; for (int i = 0; i < ARRAY_SIZE(te->regs_info); i++) { register_reset(&te->regs_info[i]); @@ -239,6 +246,7 @@ static void trencoder_reset(DeviceState *dev) te->enabled = false; te->trace_running = false; te->trace_next_insn = false; + env->trace_running = false; } static void trencoder_realize(DeviceState *dev, Error **errp) @@ -266,6 +274,14 @@ static void trencoder_realize(DeviceState *dev, Error **errp) } } +void trencoder_set_first_trace_insn(Object *trencoder_obj, uint64_t pc) +{ + TraceEncoder *trencoder = TRACE_ENCODER(trencoder_obj); + + trencoder->first_pc = pc; + trace_trencoder_first_trace_insn(pc); +} + static const Property trencoder_props[] = { /* * We need a link to the associated CPU to @@ -294,6 +310,7 @@ static const VMStateDescription vmstate_trencoder = { VMSTATE_UINT64(ramsink_ramstart, TraceEncoder), VMSTATE_UINT64(ramsink_ramlimit, TraceEncoder), VMSTATE_INT32(cpu_id, TraceEncoder), + VMSTATE_UINT64(first_pc, TraceEncoder), VMSTATE_END_OF_LIST(), } }; diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h index 30d118be1e..1801193e15 100644 --- a/hw/riscv/trace-encoder.h +++ b/hw/riscv/trace-encoder.h @@ -27,6 +27,8 @@ struct TraceEncoder { MemoryRegion reg_mem; uint32_t reg_mem_size; + uint64_t first_pc; + hwaddr baseaddr; hwaddr dest_baseaddr; hwaddr ramsink_ramstart; @@ -43,4 +45,6 @@ struct TraceEncoder { OBJECT_DECLARE_SIMPLE_TYPE(TraceEncoder, TRACE_ENCODER) +void trencoder_set_first_trace_insn(Object *trencoder_obj, uint64_t pc); + #endif diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events index 14e333fd9e..dc25377acf 100644 --- a/hw/riscv/trace-events +++ b/hw/riscv/trace-events @@ -28,6 +28,7 @@ riscv_iommu_hpm_evt_write(uint32_t ctr_idx, uint32_t ovf, uint64_t val) "ctr_idx # trace-encoder.c trencoder_read_error(uint64_t addr) "addr 0x%" PRIx64 trencoder_write_error(uint64_t addr, uint64_t value) "addr 0x%" PRIx64 " value 0x%" PRIx64 +trencoder_first_trace_insn(uint64_t pc) "pc 0x%" PRIx64 # trace-ram-sink.c tr_ramsink_read_error(uint64_t addr) "addr 0x%" PRIx64 diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index e2ded4c257..e9a80365bf 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -551,6 +551,8 @@ struct CPUArchState { uint32_t kvm_mp_state; bool kvm_mp_state_loaded; #endif /* CONFIG_KVM */ + + bool trace_running; }; /* @@ -791,6 +793,7 @@ FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1) FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1) /* sdext single-step needs a TB flag to build 1-insn TBs */ FIELD(EXT_TB_FLAGS, SDEXT_STEP, 34, 1) +FIELD(EXT_TB_FLAGS, CPU_TRACE_RUNNING, 35, 1) #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 372f104972..0832159adc 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -129,6 +129,10 @@ DEF_HELPER_4(csrrw, tl, env, int, tl, tl) DEF_HELPER_2(csrr_i128, tl, env, int) DEF_HELPER_4(csrw_i128, void, env, int, tl, tl) DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl) + +/* Trace helpers (should be put inside ifdef) */ +DEF_HELPER_2(trace_insn, void, env, i64) + #ifndef CONFIG_USER_ONLY DEF_HELPER_1(sret, tl, env) DEF_HELPER_1(mret, tl, env) diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build index 86805b30cb..e5c72889eb 100644 --- a/target/riscv/tcg/meson.build +++ b/target/riscv/tcg/meson.build @@ -10,6 +10,12 @@ riscv_ss.add(files( 'fpu_helper.c', 'm128_helper.c', 'op_helper.c', + + # In theory the RISC-V HW e-trace support is system_ss only, + # but we're instrumeting TCG code that is visible to riscv_ss + # ae well, ergo the helper needs to be visible in user-mode too. + 'trace_helper.c', + 'translate.c', 'tcg-cpu.c', 'vcrypto_helper.c', diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 6e74d6a4de..8419eeca5f 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -201,6 +201,10 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs) if (cpu->cfg.ext_sdext && !env->debug_mode && (env->dcsr & DCSR_STEP)) { ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, SDEXT_STEP, 1); } + + if (env->trace_running) { + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, CPU_TRACE_RUNNING, 1); + } #endif return (TCGTBCPUState){ diff --git a/target/riscv/tcg/trace_helper.c b/target/riscv/tcg/trace_helper.c new file mode 100644 index 0000000000..5a6d725f56 --- /dev/null +++ b/target/riscv/tcg/trace_helper.c @@ -0,0 +1,36 @@ +/* + * RISC-V Trace Support TCG helpers + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "cpu.h" +#include "trace.h" +#include "exec/helper-proto.h" + +#ifndef CONFIG_USER_ONLY +#include "hw/riscv/trace-encoder.h" +#endif + +#ifndef CONFIG_USER_ONLY +void helper_trace_insn(CPURISCVState *env, uint64_t pc) +{ + RISCVCPU *cpu = env_archcpu(env); + TraceEncoder *te = TRACE_ENCODER(cpu->trencoder); + + if (te->trace_next_insn) { + trencoder_set_first_trace_insn(cpu->trencoder, pc); + te->trace_next_insn = false; + } +} +#else /* #ifndef CONFIG_USER_ONLY */ +void helper_trace_insn(CPURISCVState *env, uint64_t pc) +{ + return; +} +#endif /* #ifndef CONFIG_USER_ONLY*/ diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c index ede9c2563f..fb82a6b2fa 100644 --- a/target/riscv/tcg/translate.c +++ b/target/riscv/tcg/translate.c @@ -125,6 +125,8 @@ typedef struct DisasContext { bool bcfi_enabled; /* Data endianness from MSTATUS UBE/SBE/MBE */ MemOp mo_endianness; + /* Detect if we're in the middle of a CPU trace session. */ + bool cpu_trace_running; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -1368,10 +1370,17 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->decoders = cpu->decoders; ctx->mo_endianness = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, BIG_ENDIAN) ? MO_BE : MO_LE; + ctx->cpu_trace_running = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, + CPU_TRACE_RUNNING); } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) { + DisasContext *ctx = container_of(db, DisasContext, base); + + if (ctx->cpu_trace_running) { + gen_helper_trace_insn(tcg_env, tcg_constant_i64(db->pc_first)); + } } static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) -- 2.43.0
