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

Reply via email to