Re: [RFC PATCH 2/2] target/riscv: Capture Sspesa sample PC and counter ID on overflow
Daniel Henrique Barboza <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On 8/17/2026 1:03 PM, Mayuresh Chitale wrote: > On a Zihpm counter overflow and with LCOFIP asserted, record the > overflowing counter ID in shpmsdata and arm a capture. When the LCOFI is > actually delivered, the shpmspc register is populated with the address of > the interrupted instruction. > Capturing shpmspc at LCOFI delivery (rather than at overflow time) > ensures the sample PC reflects the correct interrupted instruction. > > Signed-off-by: Mayuresh Chitale <[email protected]> > --- Reviewed-by: Daniel Henrique Barboza <[email protected]> > target/riscv/cpu.h | 2 ++ > target/riscv/tcg/cpu_helper.c | 6 ++++++ > target/riscv/tcg/csr.c | 25 +++++++++++++++++++++++++ > target/riscv/tcg/pmu.c | 27 +++++++++++++++++++++++++++ > 4 files changed, 60 insertions(+) > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index fe56a6afd1..36425c3605 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -473,6 +473,8 @@ struct CPUArchState { > /* Sspesa CSRs */ > target_ulong shpmspc; > target_ulong shpmsdata; > + /* Capture shpmspc/shpmsdata only on the first overflow */ > + bool sspesa_capture_pending; > > /* Sstc CSRs */ > uint64_t stimecmp; > diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c > index 07d9222652..15af3262ed 100644 > --- a/target/riscv/tcg/cpu_helper.c > +++ b/target/riscv/tcg/cpu_helper.c > @@ -2255,6 +2255,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) > sxlen = 16 << riscv_cpu_sxl(env); > env->scause = cause | ((target_ulong)async << (sxlen - 1)); > env->sepc = env->pc; > + /* On LCOFI delivery, latch the sample PC to the interrupted PC. */ > + if (riscv_cpu_cfg(env)->ext_sspesa && env->sspesa_capture_pending) { > + if (async && cause == IRQ_PMU_OVF) { > + env->shpmspc = env->pc; > + } > + } > env->stval = tval; > env->htval = htval; > env->htinst = tinst; > diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c > index ea49d28aae..e48c954359 100644 > --- a/target/riscv/tcg/csr.c > +++ b/target/riscv/tcg/csr.c > @@ -1228,6 +1228,15 @@ static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, > return RISCV_EXCP_NONE; > } > > +static bool sspesa_is_captured_ctr(CPURISCVState *env, uint32_t evt_index) > +{ > + if (!riscv_cpu_cfg(env)->ext_sspesa || !env->sspesa_capture_pending) { > + return false; > + } > + > + return (env->shpmsdata & SHPMSDATA_CNTRID) == evt_index; > +} > + > static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, > target_ulong *val) > { > @@ -1259,6 +1268,14 @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, > mhpmevt_val = val & inh_avail_mask; > } > > + /* Enable the sample capture when OF is cleared for the captured counter. */ > + if (sspesa_is_captured_ctr(env, evt_index)) { > + if ((env->mhpmevent_val[evt_index] & MHPMEVENT_BIT_OF) && > + !(mhpmevt_val & MHPMEVENT_BIT_OF)) { > + env->sspesa_capture_pending = false; > + } > + } > + > env->mhpmevent_val[evt_index] = mhpmevt_val; > riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); > > @@ -1289,6 +1306,14 @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, > inh_avail_mask |= (riscv_has_ext(env, RVH) && > riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; > > + /* Enable the sample capture when OF is cleared for the captured counter. */ > + if (sspesa_is_captured_ctr(env, evt_index)) { > + if ((env->mhpmevent_val[evt_index] & MHPMEVENT_BIT_OF) && > + !((val & inh_avail_mask) & MHPMEVENTH_BIT_OF)) { > + env->sspesa_capture_pending = false; > + } > + } > + > env->mhpmevent_val[evt_index] = deposit64(env->mhpmevent_val[evt_index], > 32, 32, val & inh_avail_mask); > > diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c > index 38ad2737e1..337e255da4 100644 > --- a/target/riscv/tcg/pmu.c > +++ b/target/riscv/tcg/pmu.c > @@ -147,6 +147,31 @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, > riscv_pmu_icount_update_priv(env, newpriv, new_virt); > } > > +static void riscv_pmu_sspesa_capture(CPURISCVState *env, uint32_t ctr_idx) > +{ > + RISCVCPU *cpu = env_archcpu(env); > + > + if (!cpu->cfg.ext_sspesa) { > + return; > + } > + > + /* > + * Only the first overflow updates the sample CSRs. While a capture is > + * pending, keep the lowest counter ID as required by the spec. > + */ > + if (env->sspesa_capture_pending) { > + if ((ctr_idx & SHPMSDATA_CNTRID) < > + (env->shpmsdata & SHPMSDATA_CNTRID)) { > + env->shpmsdata = ctr_idx & SHPMSDATA_CNTRID; > + } > + return; > + } > + > + /* shpmspc is latched later, on LCOFI delivery. */ > + env->shpmsdata = ctr_idx & SHPMSDATA_CNTRID; > + env->sspesa_capture_pending = true; > +} > + > int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) > { > uint32_t ctr_idx; > @@ -191,6 +216,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) > /* Generate interrupt only if OF bit is clear */ > if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { > env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; > + riscv_pmu_sspesa_capture(env, ctr_idx); > riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); > } > } else { > @@ -383,6 +409,7 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, > > if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) { > if (pmu_hpmevent_set_of_if_clear(env, ctr_idx)) { > + riscv_pmu_sspesa_capture(env, ctr_idx); > riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); > } > }