Privilege filtering records cycle/instruction increments per mode. Reset overwrites privilege/V without adding the final interval to the old mode's total, so a counter filtering for that mode loses those counts.
Account for the old mode before entering M-mode with V=0 and rebuild the overflow timer after reset. On initial reset, only initialize baselines: no guest code has run, so pre-execution QEMU time must not count. Preserve architectural counter and selector state, as before. Test that a VS-only cycle counter retains its counts across reset. Signed-off-by: TANG Tiancheng <[email protected]> --- target/riscv/cpu.c | 16 ++++++ target/riscv/tcg/pmu.c | 11 ++++ target/riscv/tcg/pmu.h | 1 + tests/tcg/riscv64/pmu-reset-vs.S | 105 +++++++++++++++++++++++++++++++++++ tests/tcg/riscv64/system/meson.build | 7 +++ 5 files changed, 140 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f60d7cca1e2f0008b09b1055c5cdeed3ec4ad1d3..e27312ac505dbee072c5a3c52073b00d703fd81d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -42,6 +42,9 @@ #include "disas/capstone.h" #if !defined(CONFIG_USER_ONLY) #include "target/riscv/tcg/debug.h" +#ifdef CONFIG_TCG +#include "target/riscv/tcg/pmu.h" +#endif #endif /* RISC-V CPU definitions */ @@ -979,6 +982,16 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) } #ifndef CONFIG_USER_ONLY env->misa_mxl = mcc->def->misa_mxl_max; +#ifdef CONFIG_TCG + /* The initial reset has no guest execution to count. */ + if (tcg_enabled()) { + if (qdev_is_realized(DEVICE(cpu))) { + riscv_pmu_update_fixed_ctrs(env, PRV_M, false); + } else { + riscv_pmu_init_fixed_counter_baselines(env); + } + } +#endif env->priv = PRV_M; env->virt_enabled = false; env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); @@ -1092,6 +1105,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) #ifndef CONFIG_USER_ONLY #ifdef CONFIG_TCG + if (tcg_enabled()) { + riscv_pmu_rebuild_timer(env); + } if (cpu->cfg.debug || cpu->cfg.ext_sdtrig) { riscv_trigger_reset_hold(env); } diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index df99b572a4c16cb1ac65c2f7cde35c6f8349e681..1d692a0a8e3f7759e033214d579103627d070b5b 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -171,6 +171,17 @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, riscv_pmu_update_fixed_ctrs_snapshot(env, newpriv, new_virt, &snapshot); } +void riscv_pmu_init_fixed_counter_baselines(CPURISCVState *env) +{ + RISCVPMUFixedSnapshot snapshot; + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_CYCLE] + .counter_prev[PRV_M] = snapshot.cycle; + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_INSTRET] + .counter_prev[PRV_M] = snapshot.instret; +} + uint64_t riscv_pmu_ctr_get_fixed_value(CPURISCVState *env, uint32_t ctr_idx, const RISCVPMUFixedSnapshot *snapshot) diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index 1cfe6acf55b5468f5c00c4a136ece88981384341..fac84dbb1a8a6c637f7241ca27910e5e212223e9 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -53,6 +53,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx); void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name); void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, privilege_mode_t newpriv, bool new_virt); +void riscv_pmu_init_fixed_counter_baselines(CPURISCVState *env); void riscv_pmu_decr_instret(CPURISCVState *env); RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, bool upper_half, uint32_t ctr_idx, diff --git a/tests/tcg/riscv64/pmu-reset-vs.S b/tests/tcg/riscv64/pmu-reset-vs.S new file mode 100644 index 0000000000000000000000000000000000000000..d216faef17a2a395120cb3a71166a821a43dee88 --- /dev/null +++ b/tests/tcg/riscv64/pmu-reset-vs.S @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* CSR number for older assemblers. */ +#define CSR_MCYCLECFG 0x321 + + .option norvc + .option norelax + + .equ MSTATUS_MPP_S, (1 << 11) + .equ MSTATUS_MPP, (3 << 11) + .equ MSTATUS_SPP, (1 << 8) + .equ HSTATUS_SPV, (1 << 7) + .equ SIFIVE_TEST, 0x100000 + .equ MTIMECMP, 0x2004000 + .equ FINISHER_RESET, 0x7777 + + .text + .global _start +_start: + /* Preserve the reset marker and saved count in MTIMECMP. */ + li t0, MTIMECMP + ld t1, 0(t0) + srli t2, t1, 48 + li t3, 0xa5a5 + beq t2, t3, after_reset + + /* Count VS only, then remember the value before entering VS-mode. */ + li t0, 0x1d /* MINH | SINH | UINH | VUINH */ + slli t0, t0, 58 + csrw CSR_MCYCLECFG, t0 + csrr t1, mcycle + slli t1, t1, 16 + srli t1, t1, 16 + li t2, 0xa5a5 + slli t2, t2, 48 + or t1, t1, t2 + li t0, MTIMECMP + sd t1, 0(t0) + li t0, -1 + csrw pmpaddr0, t0 + li t0, 0x1f /* RWX, NAPOT */ + csrw pmpcfg0, t0 + + /* Enter HS-mode first. */ + csrr t0, mstatus + li t1, MSTATUS_MPP + not t1, t1 + and t0, t0, t1 + li t1, MSTATUS_MPP_S + or t0, t0, t1 + csrw mstatus, t0 + lla t0, hs_enter + csrw mepc, t0 + mret + +hs_enter: + li t0, HSTATUS_SPV + csrs hstatus, t0 + li t0, MSTATUS_SPP + csrs sstatus, t0 + lla t0, vs_reset + csrw sepc, t0 + sret + +vs_reset: + /* These VS-mode cycles must remain in mcycle after reset. */ + li t0, 128 +1: + addi t0, t0, -1 + bnez t0, 1b + + li t0, SIFIVE_TEST + li t1, FINISHER_RESET + sw t1, 0(t0) + j . + +after_reset: + csrr t0, mcycle + slli t1, t1, 16 /* Clear the MTIMECMP marker. */ + srli t1, t1, 16 + addi t1, t1, 128 + bgeu t1, t0, fail + li t3, 0 + j exit + +fail: + li t3, 1 + +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd t3, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 diff --git a/tests/tcg/riscv64/system/meson.build b/tests/tcg/riscv64/system/meson.build index d2355090121ba7a7d0046c1fc1824d6a89c1267f..3f2043d100ff88cc39a21002a1e90ccab319001b 100644 --- a/tests/tcg/riscv64/system/meson.build +++ b/tests/tcg/riscv64/system/meson.build @@ -142,6 +142,13 @@ tests += { }, } +tests += { + 'pmu-reset-vs.S': { + 'cflags': cflags, + 'qemu_args': ['-cpu', 'max,smcntrpmf=true', '-icount', 'shift=0', qemu_args], + }, +} + if 'qemu-system-riscv64' in emulators tcg_tests += { 'riscv64-softmmu': { -- 2.43.0
