In user-only builds the base Zicntr counters cycle/instret are retired unconditionally because the ext_zicntr gate sits inside the #if !defined(CONFIG_USER_ONLY) block. -cpu ... ,zicntr=false is therefore accepted but ignored, while the sibling zihpm=false correctly makes hpmcounter3 illegal. Move the ext_zicntr check ahead of the user-only block so an explicit zicntr=false makes the base counters behave as unsupported in linux-user mode, matching native hardware.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4148 Signed-off-by: wangyang <[email protected]> --- target/riscv/tcg/csr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 36f2004bc56..c0829aab043 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -111,6 +111,13 @@ static RISCVException vs(CPURISCVState *env, int csrno) static RISCVException ctr(CPURISCVState *env, int csrno) { + if ((csrno >= CSR_CYCLE && csrno <= CSR_INSTRET) || + (csrno >= CSR_CYCLEH && csrno <= CSR_INSTRETH)) { + if (!riscv_cpu_cfg(env)->ext_zicntr) { + return RISCV_EXCP_ILLEGAL_INST; + } + } + #if !defined(CONFIG_USER_ONLY) RISCVCPU *cpu = env_archcpu(env); int ctr_index; @@ -127,10 +134,6 @@ static RISCVException ctr(CPURISCVState *env, int csrno) if ((csrno >= CSR_CYCLE && csrno <= CSR_INSTRET) || (csrno >= CSR_CYCLEH && csrno <= CSR_INSTRETH)) { - if (!riscv_cpu_cfg(env)->ext_zicntr) { - return RISCV_EXCP_ILLEGAL_INST; - } - goto skip_ext_pmu_check; } -- 2.43.0
