From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712744; cv=none; d=zohomail.com; s=zohoarc; b=NBfgZgqR8ksSnxQFa/Immznv3bvZ5hWQKiYnop7bkgmlUrQVDdsjXuKXbAjTOVLYtkJMGXAuxBysWua4b2I3PDT3Jx4hWibyubpwXUTIJrMxXWmmY7kWp9EbyBCD88uZzpvpxvNq9lOu9xtEVrX2hAcBPJF/80FY2he6jncZffg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712744; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=dOfJ8+6QExV1DmAngK8MkFxO6aS7RxV3M/bn+xlTP4E=; b=DVsuBFiEoJk7s11d6kVPFBuSwEcakf4iSMGsv9BN3zucNnosR++jgbgZxT865W2fWlo0AozINxodquM9jQpsedX/EBka/sW+hZjfeMs4ItFpzN3CLnXtBLgsX6s53wzQiam+xBGgJGlEGboNVJZFAHyr+kTV1vGm0HvjXzlykg0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178871274376364.53637521666269; Sun, 6 Sep 2026 09:39:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsY-0002ut-Dx; Sun, 06 Sep 2026 12:38:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsW-0002sq-RT; Sun, 06 Sep 2026 12:38:00 -0400 Received: from [115.124.30.98] (helo=out30-98.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00033G-0Q; Sun, 06 Sep 2026 12:38:00 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIHs_1788712649 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:30 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712651; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=dOfJ8+6QExV1DmAngK8MkFxO6aS7RxV3M/bn+xlTP4E=; b=vwvc2SQWiTX8Oxi9L01zFVLv12q7e544yt8fIJGY7SfdUipkHBxh7Hcc1BlrKw6BrbEjfq/xiBZ2wkFCeuGE7oflfV/f+3zPA3La6IX7eLZVyYk7uyZGC0cyo+LEyKChKMD/m3ha3Ve8eAOK46Igcnh5PsCstOnDrasPOwaEEk0= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R201e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033045133197; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIHs_1788712649; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:17 +0800 Subject: [PATCH 01/14] target/riscv: Preserve PMU state across event selector writes MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-1-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=10131; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=ORUwe7GoYUVLaTJelBp5I7XplQsaZ+HnLS/9yIRVUZg=; b=JQZYk4K409Dio5aL8q7OFEcqWSCwKX2S/D5fAlrmAp5wwGJUIzLCHW5Rsd8ZixEWnqGyK6DiD dDcOSrgmE8tB8jKp5OQPxXwZK9oOqIEcqfKqIbNfd2A+PkkmBsbzbc0 X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.98 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.98; envelope-from=lyndra@linux.alibaba.com; helo=out30-98.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712746549158500 Changing mhpmevent can lose pending cycle/instruction counts or leave a new fixed source without a baseline and overflow timer. Account for the old source before replacing the selector, then establish the enabled counter's new baseline and timer. Apply this to direct and indirect writes. Test overflow after initializing a counter with event zero and then selecting instructions. Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support") Signed-off-by: TANG Tiancheng Reviewed-by: Daniel Henrique Barboza --- target/riscv/tcg/csr.c | 73 ++++++++++++++++++++++-----= ---- tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/sscofpmf-overflow.S | 60 +++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 21 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 65985efb220c80023cfd9d08e1878a19342aa879..52664a26f5a97a5dc8ff37abf99= b4d10927fb120 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1209,23 +1209,58 @@ static RISCVException write_minstretcfgh(CPURISCVSt= ate *env, int csrno, static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) { - int evt_index =3D csrno - CSR_MCOUNTINHIBIT; + int ctr_idx =3D csrno - CSR_MCOUNTINHIBIT; bool rv32 =3D riscv_cpu_mxl(env) =3D=3D MXL_RV32; =20 - *val =3D extract64(env->mhpmevent_val[evt_index], 0, rv32 ? 32 : 64); + *val =3D extract64(env->mhpmevent_val[ctr_idx], 0, rv32 ? 32 : 64); =20 return RISCV_EXCP_NONE; } =20 +static uint64_t riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, + int counter_idx); + +static void riscv_pmu_write_mhpmevent(CPURISCVState *env, + uint32_t ctr_idx, uint64_t value) +{ + PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; + bool enabled =3D !get_field(env->mcountinhibit, BIT(ctr_idx)); + + /* + * A programmable counter backed by a fixed source uses mhpmcounter_val + * as its base and mhpmcounter_prev as the source snapshot. Preserve = the + * visible value before changing the source or its privilege filters. + */ + if (enabled && + (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { + uint64_t source =3D riscv_pmu_ctr_get_fixed_counters_val(env, + ctr_idx); + + counter->mhpmcounter_val +=3D source - counter->mhpmcounter_prev; + } + + env->mhpmevent_val[ctr_idx] =3D value; + riscv_pmu_update_event_map(env, value, ctr_idx); + + if (enabled && + (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { + counter->mhpmcounter_prev =3D + riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); + } +} + static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - int evt_index =3D csrno - CSR_MCOUNTINHIBIT; + int ctr_idx =3D csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val; uint64_t inh_avail_mask; =20 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - mhpmevt_val =3D deposit64(env->mhpmevent_val[evt_index], 0, 32, va= l); + mhpmevt_val =3D deposit64(env->mhpmevent_val[ctr_idx], 0, 32, val); } else { inh_avail_mask =3D ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH; inh_avail_mask |=3D riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH := 0; @@ -1237,8 +1272,7 @@ static RISCVException write_mhpmevent(CPURISCVState *= env, int csrno, mhpmevt_val =3D val & inh_avail_mask; } =20 - env->mhpmevent_val[evt_index] =3D mhpmevt_val; - riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); =20 return RISCV_EXCP_NONE; } @@ -1246,9 +1280,9 @@ static RISCVException write_mhpmevent(CPURISCVState *= env, int csrno, static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, target_ulong *val) { - int evt_index =3D csrno - CSR_MHPMEVENT3H + 3; + int ctr_idx =3D csrno - CSR_MHPMEVENT3H + 3; =20 - *val =3D extract64(env->mhpmevent_val[evt_index], 32, 32); + *val =3D extract64(env->mhpmevent_val[ctr_idx], 32, 32); =20 return RISCV_EXCP_NONE; } @@ -1256,7 +1290,7 @@ static RISCVException read_mhpmeventh(CPURISCVState *= env, int csrno, static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - int evt_index =3D csrno - CSR_MHPMEVENT3H + 3; + int ctr_idx =3D csrno - CSR_MHPMEVENT3H + 3; target_ulong inh_avail_mask =3D (target_ulong)(~MHPMEVENTH_FILTER_MASK= | MHPMEVENTH_BIT_MINH); =20 @@ -1267,10 +1301,9 @@ static RISCVException write_mhpmeventh(CPURISCVState= *env, int csrno, inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; =20 - env->mhpmevent_val[evt_index] =3D deposit64(env->mhpmevent_val[evt_ind= ex], - 32, 32, val & inh_avail_mask= ); - - riscv_pmu_update_event_map(env, env->mhpmevent_val[evt_index], evt_ind= ex); + riscv_pmu_write_mhpmevent(env, ctr_idx, + deposit64(env->mhpmevent_val[ctr_idx], 32, 3= 2, + val & inh_avail_mask)); =20 return RISCV_EXCP_NONE; } @@ -1512,11 +1545,11 @@ static int rmw_cd_mhpmcounterh(CPURISCVState *env, = int ctr_idx, return 0; } =20 -static int rmw_cd_mhpmevent(CPURISCVState *env, int evt_index, +static int rmw_cd_mhpmevent(CPURISCVState *env, int ctr_idx, target_ulong *val, target_ulong new_val, uint64_t wr_mask) { - uint64_t mhpmevt_val =3D env->mhpmevent_val[evt_index]; + uint64_t mhpmevt_val =3D env->mhpmevent_val[ctr_idx]; =20 if (wr_mask !=3D 0 && wr_mask !=3D -1) { return -EINVAL; @@ -1531,8 +1564,7 @@ static int rmw_cd_mhpmevent(CPURISCVState *env, int e= vt_index, wr_mask &=3D ~MHPMEVENT_BIT_MINH; /* wr_mask is 64-bit so upper 32 bits of mhpmevt_val are retained = */ mhpmevt_val =3D (new_val & wr_mask) | (mhpmevt_val & ~wr_mask); - env->mhpmevent_val[evt_index] =3D mhpmevt_val; - riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); } else { return -EINVAL; } @@ -1540,11 +1572,11 @@ static int rmw_cd_mhpmevent(CPURISCVState *env, int= evt_index, return 0; } =20 -static int rmw_cd_mhpmeventh(CPURISCVState *env, int evt_index, +static int rmw_cd_mhpmeventh(CPURISCVState *env, int ctr_idx, target_ulong *val, target_ulong new_val, target_ulong wr_mask) { - uint64_t mhpmevt_val =3D env->mhpmevent_val[evt_index]; + uint64_t mhpmevt_val =3D env->mhpmevent_val[ctr_idx]; uint32_t mhpmevth_val =3D extract64(mhpmevt_val, 32, 32); =20 if (wr_mask !=3D 0 && wr_mask !=3D -1) { @@ -1560,8 +1592,7 @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int = evt_index, wr_mask &=3D ~MHPMEVENTH_BIT_MINH; mhpmevth_val =3D (new_val & wr_mask) | (mhpmevth_val & ~wr_mask); mhpmevt_val =3D deposit64(mhpmevt_val, 32, 32, mhpmevth_val); - env->mhpmevent_val[evt_index] =3D mhpmevt_val; - riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); } else { return -EINVAL; } diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index cd1ec0b8219bdb63dfe6a45bb9674fa22e62ee4e..97978c6707247bb786f41549ada= 69e12aab619ce 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -40,6 +40,10 @@ run-test-mcycle-rv32: test-mcycle-rv32 $(call run-test, $<, \ $(QEMU) -cpu rv32 -icount shift=3D1 $(QEMU_OPTS)$<) =20 +TESTS +=3D sscofpmf-overflow +run-sscofpmf-overflow: sscofpmf-overflow + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) + EXTRA_RUNS +=3D run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/sscofpmf-overflow.S b/tests/tcg/riscv64/ssco= fpmf-overflow.S new file mode 100644 index 0000000000000000000000000000000000000000..587c7d3ec430aac984621dfb818= f141088be7b23 --- /dev/null +++ b/tests/tcg/riscv64/sscofpmf-overflow.S @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* Program hpmcounter3 while no event is selected. */ + csrw 0x323, zero /* mhpmevent3 */ + li t0, -256 + csrw 0xb03, t0 /* mhpmcounter3 */ + + /* Start counting retired instructions with overflow enabled. */ + li t0, 2 + csrw 0x323, t0 + + /* Cross the 64-bit unsigned overflow boundary. */ + .rept 1024 + nop + .endr + + /* OF must be sticky and LCOFIP must pend even with LCOFIE clear. */ + li t4, 0 + csrr t0, 0x323 + srli t1, t0, 63 + xori t1, t1, 1 + or t4, t4, t1 + + csrr t0, mip + li t1, 1 << 13 + and t0, t0, t1 + sltu t0, zero, t0 + xori t0, t0, 1 + or t4, t4, t0 + + /* The counter wraps and continues counting after overflow. */ + csrr t0, 0xb03 + li t1, -256 + sltu t0, t0, t1 + xori t0, t0, 1 + or t4, t4, t0 + + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd t4, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712804; cv=none; d=zohomail.com; s=zohoarc; b=hRBbrzbkjTnQ2SnXp2LMUQx2q3+RbLr3nU/U8sPlOt8UCQwR9m5BKXNJP/Uk4DIS3ahTqYXzGQSewg08fjr4D/vCmR/+epP2uThI2e6UsYkWMntMvNDXk9P7ZFy6K80oVXniaK+KVGSo4vHhN5JRedZ2NqFWxosypEqgP4ELjac= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712804; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=l1HhZwtGaf6CKvlWb/N294WTBOhOXZUvbgD0XTLVO/8=; b=bEGyJwQeqv7pg9Np2BCSAoHY65Fw4rwFBL8Ta5pFExR6jeU+i4aPlF5YDleCcJiMl5kOPjecUi2+clBnkUzjhYhIdl+WXq0xs2Xr+x+0fwgkkUt/cWmPwu2DqBNKUL8bMd3zs5ZAzvkUy9p4CpYXerilUCW+zUjj0e24+TX11wQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712804111361.8264631647986; Sun, 6 Sep 2026 09:40:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsb-0002yf-VM; Sun, 06 Sep 2026 12:38:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsX-0002tD-Eb; Sun, 06 Sep 2026 12:38:01 -0400 Received: from [115.124.30.99] (helo=out30-99.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00033H-0a; Sun, 06 Sep 2026 12:38:01 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIHy_1788712650 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:31 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712651; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=l1HhZwtGaf6CKvlWb/N294WTBOhOXZUvbgD0XTLVO/8=; b=ypQja9aekLylbzB4DC72JNKWCvGmb3fnysbhCYi+7dWjn1TKZUBKosFG444qUIo67iFoAwj/sxVKnkGCfLCceJpj1xgznA6fgSHJ7F0W6b/IjrVrCOxzJLR+yJNcwTmuPg+U/gnb6zXO2iJEGTh2wXAdk3Er/p8UC4bMhIG5tVY= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R171e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037009110; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIHy_1788712650; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:18 +0800 Subject: [PATCH 02/14] target/riscv: Support multiple counters per PMU event MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-2-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=15770; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=ia4Y6fi2tkOaG+wUEBGAjReRt5gBQ1dxvJxUkRHuOEM=; b=G+H/5yFzBT1I5OKvprSegi4o59w7qE7RvFrep5qUbryfRl+mLaJ0pVM0K1ZNeBlzMYlSU4yIu OQigqC5BaHPCRO4EbplOAYKGDPqgaE4gPoaRWcda/q63kcj9vDRG/tB X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.99 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.99; envelope-from=lyndra@linux.alibaba.com; helo=out30-99.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712806338158500 The PMU FDT lists multiple eligible counters for each event, but the event map stores only one counter per event. A second selector for the same event is accepted by the CSR but ignored by the map, so its counter does not count or overflow. Changing a selector between nonzero events also leaves the old mapping. Store a counter mask per event and rebuild the map from mhpmevent CSRs after selector writes and migration. Update event delivery, fixed-source accounting and overflow handling to cover every mapped counter. Test selector replacement and multiple counters selecting instructions or DTLB misses. Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support") Signed-off-by: TANG Tiancheng Reviewed-by: Daniel Henrique Barboza --- target/riscv/machine.c | 6 ++ target/riscv/tcg/csr.c | 2 +- target/riscv/tcg/pmu.c | 182 +++++++++++++++++-------------= ---- target/riscv/tcg/pmu.h | 3 +- tests/tcg/riscv64/sscofpmf-overflow.S | 80 ++++++++++++++- 5 files changed, 176 insertions(+), 97 deletions(-) diff --git a/target/riscv/machine.c b/target/riscv/machine.c index bf203bffcefb32710ed0f2af4d4f4595e122d1d9..b0ff2fc7f2ac10fab1f2ff845a9= 53649091e1f43 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -24,6 +24,9 @@ #include "migration/cpu.h" #include "exec/icount.h" #include "target/riscv/tcg/debug.h" +#ifdef CONFIG_TCG +#include "target/riscv/tcg/pmu.h" +#endif #ifdef CONFIG_KVM #include "kvm/kvm_riscv.h" #endif @@ -311,6 +314,9 @@ static int riscv_cpu_post_load(void *opaque, int versio= n_id) CPURISCVState *env =3D &cpu->env; =20 env->xl =3D cpu_recompute_xl(env); +#ifdef CONFIG_TCG + riscv_pmu_rebuild_event_map(env); +#endif return 0; } =20 diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 52664a26f5a97a5dc8ff37abf99b4d10927fb120..d15a2d096cb6e13cd123ff9ae82= ee7c643c2a961 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1241,7 +1241,7 @@ static void riscv_pmu_write_mhpmevent(CPURISCVState *= env, } =20 env->mhpmevent_val[ctr_idx] =3D value; - riscv_pmu_update_event_map(env, value, ctr_idx); + riscv_pmu_rebuild_event_map(env); =20 if (enabled && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 1a4658319b11a9a8a0edef18fc8a5abd0027eb31..f19f417e90e33a94d00007ef132= ef4e154175b19 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -49,6 +49,17 @@ static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uin= t32_t ctr_idx) } } =20 +static uint32_t riscv_pmu_event_counter_mask(RISCVCPU *cpu, + uint32_t event_idx) +{ + if (!cpu->pmu_event_ctr_map) { + return 0; + } + + return GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx= ))); +} + static bool riscv_pmu_counter_filtered(CPURISCVState *env, uint64_t cfg) { bool virt_on =3D env->virt_enabled; @@ -180,41 +191,41 @@ void riscv_pmu_decr_instret(CPURISCVState *env) =20 int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) { - uint32_t ctr_idx; + uint32_t ctr_idx, ctr_mask; CPURISCVState *env =3D &cpu->env; uint64_t max_val =3D UINT64_MAX; PMUCTRState *counter; - gpointer value; =20 if (!cpu->cfg.pmu_mask) { return 0; } - value =3D g_hash_table_lookup(cpu->pmu_event_ctr_map, - GUINT_TO_POINTER(event_idx)); - if (!value) { - return -1; - } =20 - ctr_idx =3D GPOINTER_TO_UINT(value); - if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) { + ctr_mask =3D riscv_pmu_event_counter_mask(cpu, event_idx); + if (!ctr_mask) { return -1; } =20 - if (riscv_pmu_counter_filtered(env, env->mhpmevent_val[ctr_idx])) { - return 0; - } + while (ctr_mask) { + ctr_idx =3D ctz32(ctr_mask); + ctr_mask &=3D ~BIT(ctr_idx); =20 - /* Handle the overflow scenario */ - counter =3D &env->pmu_ctrs[ctr_idx]; - if (counter->mhpmcounter_val =3D=3D max_val) { - counter->mhpmcounter_val =3D 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |=3D MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); + if (!riscv_pmu_counter_enabled(cpu, ctr_idx) || + riscv_pmu_counter_filtered(env, env->mhpmevent_val[ctr_idx])) { + continue; + } + + /* Handle the overflow scenario */ + counter =3D &env->pmu_ctrs[ctr_idx]; + if (counter->mhpmcounter_val =3D=3D max_val) { + counter->mhpmcounter_val =3D 0; + /* Generate interrupt only if OF bit is clear */ + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |=3D MHPMEVENT_BIT_OF; + riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); + } + } else { + counter->mhpmcounter_val++; } - } else { - counter->mhpmcounter_val++; } =20 return 0; @@ -224,8 +235,7 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *= env, uint32_t target_ctr) { RISCVCPU *cpu; - uint32_t event_idx; - uint32_t ctr_idx; + uint32_t ctr_mask; =20 /* Fixed instret counter */ if (target_ctr =3D=3D 2) { @@ -237,21 +247,15 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState= *env, return false; } =20 - event_idx =3D RISCV_PMU_EVENT_HW_INSTRUCTIONS; - ctr_idx =3D GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_ma= p, - GUINT_TO_POINTER(event_idx))); - if (!ctr_idx) { - return false; - } - - return target_ctr =3D=3D ctr_idx ? true : false; + ctr_mask =3D riscv_pmu_event_counter_mask(cpu, + RISCV_PMU_EVENT_HW_INSTRUCTION= S); + return (ctr_mask & BIT(target_ctr)) !=3D 0; } =20 bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr) { RISCVCPU *cpu; - uint32_t event_idx; - uint32_t ctr_idx; + uint32_t ctr_mask; =20 /* Fixed mcycle counter */ if (target_ctr =3D=3D 0) { @@ -263,22 +267,23 @@ bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env,= uint32_t target_ctr) return false; } =20 - event_idx =3D RISCV_PMU_EVENT_HW_CPU_CYCLES; - ctr_idx =3D GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_ma= p, - GUINT_TO_POINTER(event_idx))); - - /* Counter zero is not used for event_ctr_map */ - if (!ctr_idx) { - return false; - } - - return (target_ctr =3D=3D ctr_idx) ? true : false; + ctr_mask =3D riscv_pmu_event_counter_mask(cpu, + RISCV_PMU_EVENT_HW_CPU_CYCLES); + return (ctr_mask & BIT(target_ctr)) !=3D 0; } =20 -static gboolean pmu_remove_event_map(gpointer key, gpointer value, - gpointer udata) +static bool riscv_pmu_event_supported(uint32_t event_idx) { - return (GPOINTER_TO_UINT(value) =3D=3D GPOINTER_TO_UINT(udata)) ? true= : false; + switch (event_idx) { + case RISCV_PMU_EVENT_HW_CPU_CYCLES: + case RISCV_PMU_EVENT_HW_INSTRUCTIONS: + case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS: + case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS: + case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS: + return true; + default: + return false; + } } =20 static int64_t pmu_icount_ticks_to_ns(int64_t value) @@ -294,48 +299,32 @@ static int64_t pmu_icount_ticks_to_ns(int64_t value) return ret; } =20 -int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, - uint32_t ctr_idx) +void riscv_pmu_rebuild_event_map(CPURISCVState *env) { - uint32_t event_idx; + uint32_t ctr_idx, ctr_mask, event_idx; RISCVCPU *cpu =3D env_archcpu(env); =20 - if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->pmu_event_ctr_map)= { - return -1; + if (!cpu->pmu_event_ctr_map) { + return; } =20 - /* - * Expected mhpmevent value is zero for reset case. Remove the current - * mapping. - */ - if (!(value & MHPMEVENT_IDX_MASK)) { - g_hash_table_foreach_remove(cpu->pmu_event_ctr_map, - pmu_remove_event_map, - GUINT_TO_POINTER(ctr_idx)); - return 0; - } + g_hash_table_remove_all(cpu->pmu_event_ctr_map); + for (ctr_idx =3D 3; ctr_idx < RV_MAX_MHPMCOUNTERS; ctr_idx++) { + if (!riscv_pmu_counter_valid(cpu, ctr_idx)) { + continue; + } =20 - event_idx =3D value & MHPMEVENT_IDX_MASK; - if (g_hash_table_lookup(cpu->pmu_event_ctr_map, - GUINT_TO_POINTER(event_idx))) { - return 0; - } + event_idx =3D env->mhpmevent_val[ctr_idx] & MHPMEVENT_IDX_MASK; + if (!event_idx || !riscv_pmu_event_supported(event_idx)) { + continue; + } =20 - switch (event_idx) { - case RISCV_PMU_EVENT_HW_CPU_CYCLES: - case RISCV_PMU_EVENT_HW_INSTRUCTIONS: - case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS: - case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS: - case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS: - break; - default: - /* We don't support any raw events right now */ - return -1; + ctr_mask =3D riscv_pmu_event_counter_mask(cpu, event_idx); + ctr_mask |=3D BIT(ctr_idx); + g_hash_table_insert(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx), + GUINT_TO_POINTER(ctr_mask)); } - g_hash_table_insert(cpu->pmu_event_ctr_map, GUINT_TO_POINTER(event_idx= ), - GUINT_TO_POINTER(ctr_idx)); - - return 0; } =20 static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_= idx) @@ -348,23 +337,14 @@ static bool pmu_hpmevent_set_of_if_clear(CPURISCVStat= e *env, uint32_t ctr_idx) } } =20 -static void pmu_timer_trigger_irq(RISCVCPU *cpu, - enum riscv_pmu_event_idx evt_idx) +static void pmu_timer_trigger_irq_counter(RISCVCPU *cpu, uint32_t ctr_idx) { - uint32_t ctr_idx; CPURISCVState *env =3D &cpu->env; PMUCTRState *counter; int64_t irq_trigger_at; uint64_t curr_ctr_val, curr_ctrh_val; uint64_t ctr_val; =20 - if (evt_idx !=3D RISCV_PMU_EVENT_HW_CPU_CYCLES && - evt_idx !=3D RISCV_PMU_EVENT_HW_INSTRUCTIONS) { - return; - } - - ctr_idx =3D GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_ma= p, - GUINT_TO_POINTER(evt_idx))); if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) { return; } @@ -408,6 +388,26 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, } } =20 +static void pmu_timer_trigger_irq(RISCVCPU *cpu, + enum riscv_pmu_event_idx evt_idx) +{ + uint32_t ctr_idx; + uint32_t ctr_mask; + + if (evt_idx !=3D RISCV_PMU_EVENT_HW_CPU_CYCLES && + evt_idx !=3D RISCV_PMU_EVENT_HW_INSTRUCTIONS) { + return; + } + + ctr_mask =3D riscv_pmu_event_counter_mask(cpu, evt_idx); + + while (ctr_mask) { + ctr_idx =3D ctz32(ctr_mask); + ctr_mask &=3D ~BIT(ctr_idx); + pmu_timer_trigger_irq_counter(cpu, ctr_idx); + } +} + /* Timer callback for instret and cycle counter overflow */ void riscv_pmu_timer_cb(void *priv) { diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index 2429c01b776693ebb324ed63fee1feb56c821c21..910091690290cac9f77855f479b= b9d90b2762efe 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -28,8 +28,7 @@ bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr); void riscv_pmu_timer_cb(void *priv); void riscv_pmu_init(RISCVCPU *cpu, Error **errp); -int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, - uint32_t ctr_idx); +void riscv_pmu_rebuild_event_map(CPURISCVState *env); 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= ); int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, diff --git a/tests/tcg/riscv64/sscofpmf-overflow.S b/tests/tcg/riscv64/ssco= fpmf-overflow.S index 587c7d3ec430aac984621dfb818f141088be7b23..b91d9dee825f9c9f54778522588= 2b3fc6a87e3da 100644 --- a/tests/tcg/riscv64/sscofpmf-overflow.S +++ b/tests/tcg/riscv64/sscofpmf-overflow.S @@ -6,14 +6,18 @@ .text .global _start _start: - /* Program hpmcounter3 while no event is selected. */ + /* Program counters 3 and 4 while no event is selected. */ csrw 0x323, zero /* mhpmevent3 */ li t0, -256 csrw 0xb03, t0 /* mhpmcounter3 */ + csrw 0x324, zero /* mhpmevent4 */ + li t0, -512 + csrw 0xb04, t0 /* mhpmcounter4 */ =20 - /* Start counting retired instructions with overflow enabled. */ + /* Count the same event in both counters with overflow enabled. */ li t0, 2 csrw 0x323, t0 + csrw 0x324, t0 =20 /* Cross the 64-bit unsigned overflow boundary. */ .rept 1024 @@ -26,6 +30,10 @@ _start: srli t1, t0, 63 xori t1, t1, 1 or t4, t4, t1 + csrr t0, 0x324 + srli t1, t0, 63 + xori t1, t1, 1 + or t4, t4, t1 =20 csrr t0, mip li t1, 1 << 13 @@ -34,12 +42,68 @@ _start: xori t0, t0, 1 or t4, t4, t0 =20 - /* The counter wraps and continues counting after overflow. */ + /* Both counters wrap and continue counting after overflow. */ csrr t0, 0xb03 li t1, -256 sltu t0, t0, t1 xori t0, t0, 1 or t4, t4, t0 + csrr t0, 0xb04 + li t1, -512 + sltu t0, t0, t1 + xori t0, t0, 1 + or t4, t4, t0 + + /* After selecting write misses, read misses must not increment HPM3. */ + csrw 0x323, zero /* mhpmevent3 */ + csrw 0xb03, zero /* mhpmcounter3 */ + li t0, 0x10019 /* DTLB read miss */ + csrw 0x323, t0 + li t0, 0x1001b /* DTLB write miss */ + csrw 0x323, t0 + sfence.vma + lla t2, stale_probe + lw t3, 0(t2) + csrr t0, 0xb03 + or t4, t4, t0 + + /* Both counters must count a DTLB read miss. */ + csrw 0x323, zero /* mhpmevent3 */ + csrw 0x324, zero /* mhpmevent4 */ + csrw 0xb03, zero /* mhpmcounter3 */ + csrw 0xb04, zero /* mhpmcounter4 */ + li t0, 0x10019 /* DTLB read miss */ + csrw 0x323, t0 + csrw 0x324, t0 + sfence.vma + lla t2, tlb_probe + lw t3, 0(t2) + csrr t0, 0xb03 + csrr t1, 0xb04 + sltu t2, zero, t0 + xori t2, t2, 1 + or t4, t4, t2 + sltu t2, zero, t1 + xori t2, t2, 1 + or t4, t4, t2 + xor t0, t0, t1 + sltu t0, zero, t0 + or t4, t4, t0 + + /* Disabling HPM3 must leave HPM4 counting the same event. */ + csrr t5, 0xb03 + csrr t6, 0xb04 + csrw 0x323, zero /* mhpmevent3 */ + sfence.vma + lla t2, tlb_probe2 + lw t3, 0(t2) + csrr t0, 0xb03 + xor t0, t0, t5 + or t4, t4, t0 + csrr t0, 0xb04 + sltu t0, t6, t0 + xori t0, t0, 1 + or t4, t4, t0 =20 lla a1, semiargs li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ @@ -55,6 +119,16 @@ _start: j . =20 .data + /* Give each DTLB probe a separate page. */ + .balign 4096 +stale_probe: + .word 0 + .balign 4096 +tlb_probe: + .word 0 + .balign 4096 +tlb_probe2: + .word 0 .balign 16 semiargs: .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712717; cv=none; d=zohomail.com; s=zohoarc; b=jDyl8jAf208i/Wu/Cgj0p/o2gqYPaGWmyBVvyTIUr3rCF3k5w6o7mNrfvlyb1gLvSdd6l97Dc0Fd2aBRkFpd2FNVJTP+VXt8XG1L+3b62RQYspST/HFZCtKXy2xMmooGInkfw3NwQdSd4XrQiHpWa/K4fdKztvXefZOOdrRC1go= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712717; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=B8tlVV5kyWP7b4zffdRFbJapfjKKslEj+tNfnE2hutg=; b=ejWVH0k6FOzMvIPebar24aiC5BZbIPI8vsyKFiGqMzO7Pi3ISAd3LBMXoYY6IGJShKQaPkKDq8V8ky9MUfY0/XDdu0tnnFE6oyBe6bhA62ylL+pWNlhIOQKp/4/k6h0eIZoJZ1Fo4kobr9SWEk9mUdYP1/rcNK0Le2rfagZtSGY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712717341943.5922979652607; Sun, 6 Sep 2026 09:38:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsU-0002qK-Ia; Sun, 06 Sep 2026 12:37:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsS-0002pR-FK; Sun, 06 Sep 2026 12:37:56 -0400 Received: from [115.124.30.110] (helo=out30-110.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsP-00033N-4f; Sun, 06 Sep 2026 12:37:56 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIID_1788712651 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:31 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712652; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=B8tlVV5kyWP7b4zffdRFbJapfjKKslEj+tNfnE2hutg=; b=Up14WDmAtuSBvQ+zvMtAjcQYIcETv7Kft8c0+y55R6IFvmTFho9ix4mjrWWGum56f3UXW1HBzL0LlASNCprPoi3kj2BmIFoCDZWiB5kM4//anOLAUmdxhbhVNkMSiOt2sXOrbNqjD8J8oDcf1Fut1dxvc2sWSvyXuuceYNRCxqI= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R431e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam011083073210; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIID_1788712651; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:19 +0800 Subject: [PATCH 03/14] target/riscv: Use VM-elapsed sources for fixed PMU events MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-3-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=9498; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=B3cVD38Jnpx5LXHlCGbC2pwe8lMbluVAHffi2wkGHRU=; b=TU5JB/8uEYhCe+iFzHONIvgEjQHweLpTm6/TWMIy1ZYtRy7v1UAb06lg+cTrFaLrzM2BDn2Ho /ynmVt2Xge5AGvH7Nsjxie+udx2gXJJb5VRLoH//bjT5ftcnXdZclCT X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.110 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.110; envelope-from=lyndra@linux.alibaba.com; helo=out30-110.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712721312158500 Raw host ticks keep advancing while the VM is stopped. Use cpus_get_elapsed_ticks() for cycles and non-icount instruction counting, and retain icount_get_raw() for instructions under icount. Document that cpu_get_ticks() returns its stored value while VM ticks are disabled. Under icount, cycles are already virtual nanoseconds. Convert only raw instruction counts when scheduling overflow, avoiding a second scaling of cycle distances. Add a cycle-overflow regression with icount shift=3D3. Link: https://lists.nongnu.org/archive/html/qemu-devel/2025-10/msg00668.html Signed-off-by: TANG Tiancheng Reviewed-by: Daniel Henrique Barboza --- system/cpu-timers.c | 4 +- system/cpus.c | 6 +-- target/riscv/tcg/csr.c | 8 +--- target/riscv/tcg/pmu.c | 52 +++++++++++++++----------- target/riscv/tcg/pmu.h | 1 + tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/sscofpmf-cycle-overflow.S | 58 +++++++++++++++++++++++++= ++++ 7 files changed, 100 insertions(+), 33 deletions(-) diff --git a/system/cpu-timers.c b/system/cpu-timers.c index 9919b46230f1caf8be1a1b6ef00acd94678437ce..0415636aff3f774f0de61fdac39= 69f5b45ae6993 100644 --- a/system/cpu-timers.c +++ b/system/cpu-timers.c @@ -118,8 +118,8 @@ void cpu_enable_ticks(void) } =20 /* - * disable cpu_get_ticks() : the clock is stopped. You must not call - * cpu_get_ticks() after that. + * Freeze VM ticks. While disabled, cpu_get_ticks() returns the stored tick + * value instead of sampling the advancing host counter. * Caller must hold BQL which serves as mutex for vm_clock_seqlock. */ void cpu_disable_ticks(void) diff --git a/system/cpus.c b/system/cpus.c index e11a5aab6a696962d94ad30ac38acd8867b1bf88..f61639ae78277fd90cbddb0b9f7= 5b134e3cc1a17 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -237,9 +237,9 @@ void cpus_set_virtual_clock(int64_t new_time) } =20 /* - * return the time elapsed in VM between vm_start and vm_stop. Unless - * icount is active, cpus_get_elapsed_ticks() uses units of the host CPU c= ycle - * counter. + * Return VM-elapsed ticks. While VM ticks are disabled, passage of host t= ime + * does not advance the returned value. Unless icount is active, the units= are + * those of the host CPU cycle counter. */ int64_t cpus_get_elapsed_ticks(void) { diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index d15a2d096cb6e13cd123ff9ae82ee7c643c2a961..60caee32dc0cf5b6a8492e0cf8f= f15f71acc2087 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1327,13 +1327,7 @@ static uint64_t riscv_pmu_ctr_get_fixed_counters_val= (CPURISCVState *env, } =20 if (!cfg_val) { - if (icount_enabled()) { - curr_val =3D inst ? icount_get_raw() : icount_get(); - } else { - curr_val =3D cpu_get_host_ticks(); - } - - return curr_val; + return riscv_pmu_read_fixed_source(env, inst); } =20 /* Update counter before reading. */ diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index f19f417e90e33a94d00007ef132ef4e154175b19..ea0ffe41258d4dbef9dc952655e= 6301c14ba1d23 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -24,8 +24,14 @@ #include "pmu.h" #include "exec/icount.h" #include "system/device_tree.h" +#include "system/cpu-timers.h" =20 -#define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */ +/* + * cpu_get_ticks() does not expose the host tick frequency. Use a 1 GHz + * approximation only when scheduling non-icount overflow checks; fixed + * counter values remain in host-tick units. + */ +#define RISCV_PMU_HOST_TICK_HZ_ASSUMED 1000000000 =20 static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx) { @@ -75,6 +81,19 @@ static bool riscv_pmu_counter_filtered(CPURISCVState *en= v, uint64_t cfg) (cfg & MHPMEVENT_BIT_UINH)); } =20 +/* + * VM-elapsed ticks stop advancing while VM ticks are disabled. Under + * icount, instruction events retain raw instruction-count units. + */ +uint64_t riscv_pmu_read_fixed_source(CPURISCVState *env, bool instret) +{ + if (instret && icount_enabled()) { + return icount_get_raw(); + } + + return cpus_get_elapsed_ticks(); +} + /* * Information needed to update counters: * new_priv, new_virt: To correctly save starting snapshot for the newly @@ -96,11 +115,7 @@ static void riscv_pmu_icount_update_priv(CPURISCVState = *env, uint64_t *counter_arr; uint64_t delta; =20 - if (icount_enabled()) { - current_icount =3D icount_get_raw(); - } else { - current_icount =3D cpu_get_host_ticks(); - } + current_icount =3D riscv_pmu_read_fixed_source(env, true); =20 if (env->virt_enabled) { g_assert(env->priv <=3D PRV_S); @@ -137,11 +152,7 @@ static void riscv_pmu_cycle_update_priv(CPURISCVState = *env, uint64_t *counter_arr; uint64_t delta; =20 - if (icount_enabled()) { - current_ticks =3D icount_get(); - } else { - current_ticks =3D cpu_get_host_ticks(); - } + current_ticks =3D riscv_pmu_read_fixed_source(env, false); =20 if (env->virt_enabled) { g_assert(env->priv <=3D PRV_S); @@ -286,17 +297,15 @@ static bool riscv_pmu_event_supported(uint32_t event_= idx) } } =20 -static int64_t pmu_icount_ticks_to_ns(int64_t value) +static int64_t pmu_ticks_to_ns(CPURISCVState *env, uint32_t ctr_idx, + int64_t value) { - int64_t ret =3D 0; - - if (icount_enabled()) { - ret =3D icount_to_ns(value); - } else { - ret =3D (NANOSECONDS_PER_SECOND / RISCV_TIMEBASE_FREQ) * value; + if (icount_enabled() && + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + return icount_to_ns(value); } =20 - return ret; + return (NANOSECONDS_PER_SECOND / RISCV_PMU_HOST_TICK_HZ_ASSUMED) * val= ue; } =20 void riscv_pmu_rebuild_event_map(CPURISCVState *env) @@ -448,8 +457,9 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t = value, uint32_t ctr_idx) =20 if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - overflow_ns =3D pmu_icount_ticks_to_ns((int64_t)overflow_delta); - overflow_left =3D pmu_icount_ticks_to_ns(overflow_left) ; + overflow_ns =3D pmu_ticks_to_ns(env, ctr_idx, + (int64_t)overflow_delta); + overflow_left =3D pmu_ticks_to_ns(env, ctr_idx, overflow_left); } else { return -1; } diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index 910091690290cac9f77855f479bb9d90b2762efe..339a4b3ac09c4a91cddd9250824= 284203b16b4fa 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -26,6 +26,7 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *en= v, uint32_t target_ctr); bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr); +uint64_t riscv_pmu_read_fixed_source(CPURISCVState *env, bool instret); void riscv_pmu_timer_cb(void *priv); void riscv_pmu_init(RISCVCPU *cpu, Error **errp); void riscv_pmu_rebuild_event_map(CPURISCVState *env); diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index 97978c6707247bb786f41549ada69e12aab619ce..677244e8b187435b09fc6b7616e= 269992543587c 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -44,6 +44,10 @@ TESTS +=3D sscofpmf-overflow run-sscofpmf-overflow: sscofpmf-overflow $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) =20 +TESTS +=3D sscofpmf-cycle-overflow +run-sscofpmf-cycle-overflow: sscofpmf-cycle-overflow + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D3 $(QEMU_OPTS)$<) + EXTRA_RUNS +=3D run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/sscofpmf-cycle-overflow.S b/tests/tcg/riscv6= 4/sscofpmf-cycle-overflow.S new file mode 100644 index 0000000000000000000000000000000000000000..1acf61ee54ab9b8dc6e5228a6bc= e3c013fe7201c --- /dev/null +++ b/tests/tcg/riscv64/sscofpmf-cycle-overflow.S @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* UINT64_MAX - 4095 leaves 4096 cycle increments until overflow. */ + csrw 0x323, zero /* mhpmevent3 */ + li t0, -4096 + csrw 0xb03, t0 /* mhpmcounter3 */ + li t0, 1 + csrw 0x323, t0 /* mhpmevent3: cycles */ + csrr t1, mcycle + +1: + csrr t0, 0x323 + beqz t0, fail + li t2, 1 + slli t2, t2, 63 + and t0, t0, t2 + bnez t0, pass + + /* + * Allow 16384 cycles for OF to become visible. With shift=3D3, scaling + * the 4096-cycle distance twice would delay it to about 32768 cycles. + */ + csrr t0, mcycle + sub t0, t0, t1 + li t2, 16384 + bltu t0, t2, 1b + +fail: + li a0, 1 + j exit + +pass: + li a0, 0 + +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712750; cv=none; d=zohomail.com; s=zohoarc; b=IUBPUaQFZ7r9isjqWSICJ74dp8pOgFhO4O0PW2GkuL9UWX4dkxnS0lX03D0Lnq9qW9RBOkfSTwsJfQ0igS8zkEUi5W+1immFoQRzguwq0/EfzN9gRWSBkKSxdSWzKQ/Srnkn3XwmuseYjYOmUSfcGmSXFgaY05+DOuZtIT1r6Mc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712750; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8kmJ+U2czJtSLYkhnnST/lEwFU0nr+9dKHTdViNoHZI=; b=TzIkxvFh7iOZkDQkRSzzVHRK9AfQO5iPWsp/YE1ytZc9CyI3m2hdrq9E/ilh4xFcZwV/qmxo4/k53tKzrZX3YGkpFbqWFGn7EXI7pnZm5uVkujReVY2qhLc/rsUIrIfp+MuTXUZ9cOvs2MxM6V0GK8rlDabwRj1r6mEqWRYUSYQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712750730501.2861033091997; Sun, 6 Sep 2026 09:39:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsX-0002sx-1L; Sun, 06 Sep 2026 12:38:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsV-0002r9-E9; Sun, 06 Sep 2026 12:37:59 -0400 Received: from [115.124.30.130] (helo=out30-130.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsO-00033U-DL; Sun, 06 Sep 2026 12:37:59 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIIZ_1788712652 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:32 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712653; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=8kmJ+U2czJtSLYkhnnST/lEwFU0nr+9dKHTdViNoHZI=; b=GakJzGGADDqv9ceDZgaS35BxHVeZcKFAkxWtshCsxH9bEGvpeeg+ms38ldVv2/xgewrmHQEwUOUXk+lMI+M5TKEuCThRBydSQq55XpphiC2nsAitUsVgcRFO+2Jtf5VhQCgYKSMmMJFgJ4C5WE7KD0evEXbIMCHHQ1GJkooqObs= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R491e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037026112; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIIZ_1788712652; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:20 +0800 Subject: [PATCH 04/14] target/riscv: Preserve MINH on delegated config reads MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-4-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=8019; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=9hnSioaihNxUR8jDthpZPvWFAvgJ4fXsLSawsn9mE8o=; b=FhPPdZndAzamOAHtsZH6gQyw0VSIS4xdgomJkwrz7FOQxxba6xIuRkOngM743YYLFjjG+uVdk DOYZH+da7HXBFbRePSVtlNFHHk0RNYRuXDPQNlq4Jotp+7ZHrVK0wdI X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.130 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.130; envelope-from=lyndra@linux.alibaba.com; helo=out30-130.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712752070158500 Smcdeleg requires MINH to read as zero through sireg*. The RV64 callback masks it by modifying the machine register; the RV32 high-half callback does not mask it. Return a masked copy without changing mcyclecfg or minstretcfg. Test both configuration registers on RV32 and RV64. Fixes: d9fa41e10156 ("target/riscv: Bugfix make bit 62 read-only 0 for sire= g* cfg CSR read") Signed-off-by: TANG Tiancheng --- target/riscv/tcg/csr.c | 8 ++-- tests/tcg/riscv32/Makefile.softmmu-target | 22 ++++++++++ tests/tcg/riscv32/smcdeleg-minh-rv32.S | 70 +++++++++++++++++++++++++++= ++++ tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/smcdeleg-minh.S | 70 +++++++++++++++++++++++++++= ++++ 5 files changed, 170 insertions(+), 4 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 60caee32dc0cf5b6a8492e0cf8ff15f71acc2087..57030724f85a897e21e5082b985= 7411b50f932ac 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1607,7 +1607,7 @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg= _index, target_ulong *val, wr_mask &=3D ~MCYCLECFG_BIT_MINH; env->mcyclecfg =3D (new_val & wr_mask) | (env->mcyclecfg & ~wr= _mask); } else { - *val =3D env->mcyclecfg &=3D ~MHPMEVENT_BIT_MINH; + *val =3D env->mcyclecfg & ~MCYCLECFG_BIT_MINH; } break; case 2: /* INSTRETCFG */ @@ -1616,7 +1616,7 @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg= _index, target_ulong *val, env->minstretcfg =3D (new_val & wr_mask) | (env->minstretcfg & ~wr_mask); } else { - *val =3D env->minstretcfg &=3D ~MHPMEVENT_BIT_MINH; + *val =3D env->minstretcfg & ~MINSTRETCFG_BIT_MINH; } break; default: @@ -1642,7 +1642,7 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cf= g_index, target_ulong *val, cfgh =3D (new_val & wr_mask) | (cfgh & ~wr_mask); env->mcyclecfg =3D deposit64(env->mcyclecfg, 32, 32, cfgh); } else { - *val =3D cfgh; + *val =3D cfgh & ~MCYCLECFGH_BIT_MINH; } break; case 2: /* INSTRETCFGH */ @@ -1652,7 +1652,7 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cf= g_index, target_ulong *val, cfgh =3D (new_val & wr_mask) | (cfgh & ~wr_mask); env->minstretcfg =3D deposit64(env->minstretcfg, 32, 32, cfgh); } else { - *val =3D cfgh; + *val =3D cfgh & ~MINSTRETCFGH_BIT_MINH; } break; default: diff --git a/tests/tcg/riscv32/Makefile.softmmu-target b/tests/tcg/riscv32/= Makefile.softmmu-target new file mode 100644 index 0000000000000000000000000000000000000000..67d334974577e14ff36e7c51067= ebcab4c1349bd --- /dev/null +++ b/tests/tcg/riscv32/Makefile.softmmu-target @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# RISC-V 32-bit system tests +# + +TEST_SRC =3D $(SRC_PATH)/tests/tcg/riscv32 +VPATH +=3D $(TEST_SRC) + +LINK_SCRIPT =3D $(SRC_PATH)/tests/tcg/riscv64/semihost.ld +LDFLAGS =3D -m elf32lriscv -T $(LINK_SCRIPT) +CFLAGS +=3D -g -Og $(EXTRA_CFLAGS) -march=3Drv32im_zicsr -mabi=3Dilp32 + +%.o: %.S + $(CC) $(CFLAGS) $< -Wa,--noexecstack -c -o $@ +%: %.o $(LINK_SCRIPT) + $(LD) $(LDFLAGS) $< -o $@ + +QEMU_OPTS +=3D -M virt -display none -semihosting -device loader,file=3D + +TESTS +=3D smcdeleg-minh-rv32 +run-smcdeleg-minh-rv32: smcdeleg-minh-rv32 + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv32/smcdeleg-minh-rv32.S b/tests/tcg/riscv32/smc= deleg-minh-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..2e8ee394f5f8a4e01b1c9efc815= d21af18de4b3c --- /dev/null +++ b/tests/tcg/riscv32/smcdeleg-minh-rv32.S @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* + * Failure bits: + * 0: delegated cyclecfgh exposes MINH + * 1: reading delegated cyclecfgh clears mcyclecfgh.MINH + * 2: delegated instretcfgh exposes MINH + * 3: reading delegated instretcfgh clears minstretcfgh.MINH + */ + li t4, 0 + li t0, 1 + slli t0, t0, 30 /* MINH in the high half */ + csrw 0x721, t0 /* mcyclecfgh */ + csrw 0x722, t0 /* minstretcfgh */ + li t1, 1 + slli t1, t1, 28 /* menvcfgh.CDE */ + csrw 0x31a, t1 + li t1, 5 /* delegate cycle and instret */ + csrw mcounteren, t1 + + li t1, 0x40 + csrw 0x150, t1 /* siselect: cycle */ + csrr t1, 0x156 /* sireg5: cyclecfgh */ + and t1, t1, t0 + sltu t1, zero, t1 + or t4, t4, t1 + csrr t1, 0x721 + and t1, t1, t0 + sltu t1, zero, t1 + xori t1, t1, 1 + slli t1, t1, 1 + or t4, t4, t1 + + li t1, 0x42 + csrw 0x150, t1 /* siselect: instret */ + csrr t1, 0x156 /* sireg5: instretcfgh */ + and t1, t1, t0 + sltu t1, zero, t1 + slli t1, t1, 2 + or t4, t4, t1 + csrr t1, 0x722 + and t1, t1, t0 + sltu t1, zero, t1 + xori t1, t1, 1 + slli t1, t1, 3 + or t4, t4, t1 + + la a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sw t0, 0(a1) + sw t4, 4(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 8 diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index 677244e8b187435b09fc6b7616e269992543587c..af6bc1aad8893726a3b26392da8= 9f34319dd78a8 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -48,6 +48,10 @@ TESTS +=3D sscofpmf-cycle-overflow run-sscofpmf-cycle-overflow: sscofpmf-cycle-overflow $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D3 $(QEMU_OPTS)$<) =20 +TESTS +=3D smcdeleg-minh +run-smcdeleg-minh: smcdeleg-minh + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + EXTRA_RUNS +=3D run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/smcdeleg-minh.S b/tests/tcg/riscv64/smcdeleg= -minh.S new file mode 100644 index 0000000000000000000000000000000000000000..41cbb580475b5dcd079d4542631= dfe2474536d60 --- /dev/null +++ b/tests/tcg/riscv64/smcdeleg-minh.S @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* + * Failure bits: + * 0: delegated cyclecfg exposes MINH + * 1: reading delegated cyclecfg clears mcyclecfg.MINH + * 2: delegated instretcfg exposes MINH + * 3: reading delegated instretcfg clears minstretcfg.MINH + */ + li t4, 0 + li t0, 1 + slli t0, t0, 62 /* MINH */ + csrw 0x321, t0 /* mcyclecfg */ + csrw 0x322, t0 /* minstretcfg */ + li t1, 1 + slli t1, t1, 60 /* menvcfg.CDE */ + csrw 0x30a, t1 + li t1, 5 /* delegate cycle and instret */ + csrw mcounteren, t1 + + li t1, 0x40 + csrw 0x150, t1 /* siselect: cycle */ + csrr t1, 0x152 /* sireg2: cyclecfg */ + and t1, t1, t0 + sltu t1, zero, t1 + or t4, t4, t1 + csrr t1, 0x321 /* mcyclecfg: MINH remains set */ + and t1, t1, t0 + sltu t1, zero, t1 + xori t1, t1, 1 + slli t1, t1, 1 + or t4, t4, t1 + + li t1, 0x42 + csrw 0x150, t1 /* siselect: instret */ + csrr t1, 0x152 /* sireg2: instretcfg */ + and t1, t1, t0 + sltu t1, zero, t1 + slli t1, t1, 2 + or t4, t4, t1 + csrr t1, 0x322 /* minstretcfg: MINH remains set */ + and t1, t1, t0 + sltu t1, zero, t1 + xori t1, t1, 1 + slli t1, t1, 3 + or t4, t4, t1 + + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd t4, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712798; cv=none; d=zohomail.com; s=zohoarc; b=lFlv8Q1qX0MddZhYKusV7Jx8GCa9sJiBVVOwjXcRH/zprimJE0s5ak5w7KlJTja/uGNkYOwuE4+oUANJLdp/RnXHSrvyK5e+EIE1dvxr8Lsg1a0rbhhNQgUuHQEA+YKT62S+hG6wm2XMqIrd2elnntW7lppZY3K3AjKOGbAiTMg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712798; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=uRt0gBb8L8FGHi21aFS83kzFqYi/Wj94R+OnC6gSM+4=; b=AYApT0b1gMbmk7PVZIyoKgceqviWOdMG5Io1oRxd1hbHfuXbvbF44dIR95vHQesj+yBcXsVTlSZWtB4JwEVAZ+NavSWsExxkomJ2HMqzhGG6moaV72VgNIYNJZQQUkVgx0I+cw/FRMxltWMyzc/11tpoRjFHsRyCiFFwtNHy5Oc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712798471996.2467785124632; Sun, 6 Sep 2026 09:39:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsV-0002rK-K7; Sun, 06 Sep 2026 12:37:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsT-0002pe-5U; Sun, 06 Sep 2026 12:37:57 -0400 Received: from [115.124.30.98] (helo=out30-98.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsO-00033c-Rw; Sun, 06 Sep 2026 12:37:56 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIIv_1788712653 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:33 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712654; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=uRt0gBb8L8FGHi21aFS83kzFqYi/Wj94R+OnC6gSM+4=; b=U+8dkjAB0ey0OM6z/RIoebvGkSyUfQtFaoqu/nK4K9K8GXPJn1FeCUdqYByIFfqZ+lAYlvGwICXoV/qqy+ugygvDjWPFMyi9kfW4R3u656wjI88xdyIxDn0LUM8feGIDtcpcbZtySYwv5T7BmYqxxdIlF8k0Ntx/P7RsKWFYoRo= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R171e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033032089153; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIIv_1788712653; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:21 +0800 Subject: [PATCH 05/14] target/riscv: Preserve minstretcfgh on RV32 minstretcfg writes MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-5-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=3379; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=IdUFjos+O+zWBPe2lmEXuq6/NeB+c260XZxX21qLlJ4=; b=UazR3ic5L6ZlPb9Cp1TC29Btv/HvlK7CvnOqkiHWFSKbcHIIyBr+/LBjqc/MVBfR/M+jTjHj3 r70IyBg+3efCE8s0IyqiYWTQWixraeXI8xO4EtWomkfPQ1hsDVDC50S X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.98 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.98; envelope-from=lyndra@linux.alibaba.com; helo=out30-98.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712800032154100 RV32 write_minstretcfg() replaces the full 64-bit register, clearing minstretcfgh and its privilege-inhibit bits. Replace only bits 31:0, as write_mcyclecfg() does. Test that a low-half write preserves both set and clear xINH bits in minstretcfgh. Fixes: b54a84c15e38 ("target/riscv: Add cycle & instret privilege mode filt= ering support") Signed-off-by: TANG Tiancheng --- target/riscv/tcg/csr.c | 2 +- tests/tcg/riscv32/Makefile.softmmu-target | 4 +++ tests/tcg/riscv32/pmu-minstretcfg-rv32.S | 48 +++++++++++++++++++++++++++= ++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 57030724f85a897e21e5082b9857411b50f932ac..f9f43a9c12e1afdbdf6c7202c16= 7988389963c10 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1167,7 +1167,7 @@ static RISCVException write_minstretcfg(CPURISCVState= *env, int csrno, uint64_t inh_avail_mask; =20 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - env->minstretcfg =3D val; + env->minstretcfg =3D deposit64(env->minstretcfg, 0, 32, val); } else { inh_avail_mask =3D ~MHPMEVENT_FILTER_MASK | MINSTRETCFG_BIT_MINH; inh_avail_mask |=3D riscv_has_ext(env, RVU) ? MINSTRETCFG_BIT_UINH= : 0; diff --git a/tests/tcg/riscv32/Makefile.softmmu-target b/tests/tcg/riscv32/= Makefile.softmmu-target index 67d334974577e14ff36e7c51067ebcab4c1349bd..43c162fd337f7b0d5d3e4dedb3f= 5b06b2821fd88 100644 --- a/tests/tcg/riscv32/Makefile.softmmu-target +++ b/tests/tcg/riscv32/Makefile.softmmu-target @@ -20,3 +20,7 @@ QEMU_OPTS +=3D -M virt -display none -semihosting -device= loader,file=3D TESTS +=3D smcdeleg-minh-rv32 run-smcdeleg-minh-rv32: smcdeleg-minh-rv32 $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + +TESTS +=3D pmu-minstretcfg-rv32 +run-pmu-minstretcfg-rv32: pmu-minstretcfg-rv32 + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv32/pmu-minstretcfg-rv32.S b/tests/tcg/riscv32/p= mu-minstretcfg-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..44f6127da1babe04d6d1094dce5= f37528282bee3 --- /dev/null +++ b/tests/tcg/riscv32/pmu-minstretcfg-rv32.S @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* RV32 writes to minstretcfg must preserve minstretcfgh. */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* + * Use complementary patterns to check both set and clear xINH bits. + * All fields in the low half are WPRI, so write zero there. + * Exit status 1 or 2 identifies the pattern that was not preserved. + */ + li t4, 1 + li t0, 0x54000000 /* MINH, UINH, VUINH */ + csrw 0x722, t0 /* minstretcfgh */ + csrw 0x322, zero /* minstretcfg */ + csrr t1, 0x722 + bne t0, t1, exit + + li t4, 2 + li t0, 0x28000000 /* SINH, VSINH */ + csrw 0x722, t0 /* minstretcfgh */ + csrw 0x322, zero /* minstretcfg */ + csrr t1, 0x722 + bne t0, t1, exit + li t4, 0 + +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sw t0, 0(a1) + sw t4, 4(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 8 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712779; cv=none; d=zohomail.com; s=zohoarc; b=jRK5w/kq20NrWV9yGJnPGoKcqkpL0SNb7ioDLf3Zsy1qxUuybMo8iotga9Zk0F24NRyh0fGQyaYXC+q73s4OfO1kAKyZK9NYvVJJWPdWeVw2xsYmWdazwaAQlbO6f8MFr3LptXXItVcu96TOZC3/xxLSaWuPLJkLGHjL5zqUITo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712779; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=waY5yx8GQpkd/QlH6r0keWNmP1y1xKVsntWQ9/jG6as=; b=YF/95MSv1B73Et8ib5Rz/7wwpa20Yyq39Bd9O/8RaR63p5ECWoXAJlo/1HnwbE1tkatdk383nUfM3Rc8i49uetTLUeKBUHbCSutlCWi+1u4MOvKT+Ow3rMNh1ZfoKxPXJdcB2eWQNY5SosubwQel3PqrrLzvJHzEFHelGFDZT8o= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712779267790.2083100301505; Sun, 6 Sep 2026 09:39:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsd-0002yw-1c; Sun, 06 Sep 2026 12:38:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsZ-0002wg-PY; Sun, 06 Sep 2026 12:38:03 -0400 Received: from [115.124.30.111] (helo=out30-111.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsP-00033j-2o; Sun, 06 Sep 2026 12:38:03 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIJ7_1788712653 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:34 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712655; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=waY5yx8GQpkd/QlH6r0keWNmP1y1xKVsntWQ9/jG6as=; b=CgPkvcHX6pdst/M0w3knMcTukODSoV6Gv/+IV2WQW4B9uEo9e1FRml0kq2gWNW6lk0CyhhMmSwze6lRaB68TqTv28oXdYsPjernw2tveGqu0Q44QFfa6W+eJoY5MhmLD1YdfBIgXrXn4UuRGIlIdB7k+JLN7TaE4n2e0N6K6XIk= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R961e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037033178; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIJ7_1788712653; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:22 +0800 Subject: [PATCH 06/14] target/riscv: Fix RV32 accesses to delegated PMU registers MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-6-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=20779; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=OdgJvva4rE/W6mRjxi/71pHc3YXppF1NxJk3kd8P5Mw=; b=YXTIZhHrIvKll3MB0C8MkB7I+UB9J6FvcTXOMRazhvjQ/L3jd5FsC+jVWwDYxe2RaDVbas7sM aiV3ItZRLgBBobMu2tDys/6N4AT/mmC4MhdY/3K/LNWPJVMI92iu/94 X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.111 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.111; envelope-from=lyndra@linux.alibaba.com; helo=out30-111.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712781794154100 Delegated PMU writes compare the full-write mask with -1 in its C type, rejecting valid RV32 writes. Counter widths and high-half access checks also use MXLEN, so RV32 S-mode on an RV64 CPU cannot access the high half and low-half counter writes overwrite all 64 bits. Use the current XLEN for delegated masks, counter widths and high-half checks, as required by Smcsrind. Keep MXLEN for direct counter accesses and retain the 64-bit selector merge mask to preserve the unwritten half. Test RV32 CPUs in both system emulators and RV32 S-mode on an RV64 CPU, including half preservation, machine MINH and RV64 M-mode alias accesses. Fixes: 6247dc2ef70b ("target/riscv: Add counter delegation/configuration su= pport") Fixes: c9efdb7b63a4 ("target/riscv: Combine mhpmevent and mhpmeventh") Link: https://docs.riscv.org/reference/isa/v20260120/priv/indirect-csr.html Signed-off-by: TANG Tiancheng --- target/riscv/tcg/csr.c | 43 +++--- target/riscv/tcg/pmu.c | 6 +- target/riscv/tcg/pmu.h | 3 +- tests/tcg/riscv32/Makefile.softmmu-target | 8 ++ tests/tcg/riscv32/smcdeleg-counter-rv32.S | 84 ++++++++++++ tests/tcg/riscv32/smcdeleg-event-rv32.S | 69 ++++++++++ tests/tcg/riscv64/Makefile.softmmu-target | 25 ++++ tests/tcg/riscv64/smcdeleg-sxl32.S | 219 ++++++++++++++++++++++++++= ++++ 8 files changed, 434 insertions(+), 23 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index f9f43a9c12e1afdbdf6c7202c167988389963c10..d72368ccb5a1bd5f26a20b8e4a3= c214b842afba6 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1357,10 +1357,10 @@ static uint64_t riscv_pmu_ctr_get_fixed_counters_va= l(CPURISCVState *env, } =20 static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong= val, - uint32_t ctr_idx) + uint32_t ctr_idx, RISCVMXL xl) { PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; - bool rv32 =3D riscv_cpu_mxl(env) =3D=3D MXL_RV32; + bool rv32 =3D xl =3D=3D MXL_RV32; int deposit_size =3D rv32 ? 32 : 64; uint64_t ctr; =20 @@ -1418,7 +1418,7 @@ static RISCVException write_mhpmcounter(CPURISCVState= *env, int csrno, { int ctr_idx =3D csrno - CSR_MCYCLE; =20 - return riscv_pmu_write_ctr(env, val, ctr_idx); + return riscv_pmu_write_ctr(env, val, ctr_idx, riscv_cpu_mxl(env)); } =20 static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, @@ -1430,10 +1430,11 @@ static RISCVException write_mhpmcounterh(CPURISCVSt= ate *env, int csrno, } =20 RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, - bool upper_half, uint32_t ctr_idx) + bool upper_half, uint32_t ctr_idx, + RISCVMXL xl) { PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; - bool rv32 =3D riscv_cpu_mxl(env) =3D=3D MXL_RV32; + bool rv32 =3D xl =3D=3D MXL_RV32; int start =3D upper_half ? 32 : 0; int length =3D rv32 ? 32 : 64; uint64_t ctr_val; @@ -1482,7 +1483,7 @@ static RISCVException read_hpmcounter(CPURISCVState *= env, int csrno, return RISCV_EXCP_ILLEGAL_INST; } =20 - return riscv_pmu_read_ctr(env, val, false, ctr_index); + return riscv_pmu_read_ctr(env, val, false, ctr_index, riscv_cpu_mxl(en= v)); } =20 static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, @@ -1498,21 +1499,23 @@ static RISCVException read_hpmcounterh(CPURISCVStat= e *env, int csrno, return RISCV_EXCP_ILLEGAL_INST; } =20 - return riscv_pmu_read_ctr(env, val, true, ctr_index); + return riscv_pmu_read_ctr(env, val, true, ctr_index, riscv_cpu_mxl(env= )); } =20 static int rmw_cd_mhpmcounter(CPURISCVState *env, int ctr_idx, target_ulong *val, target_ulong new_val, target_ulong wr_mask) { - if (wr_mask !=3D 0 && wr_mask !=3D -1) { + uint64_t xlen_mask =3D env->xl =3D=3D MXL_RV32 ? UINT32_MAX : UINT64_M= AX; + + if (wr_mask !=3D 0 && wr_mask !=3D xlen_mask) { return -EINVAL; } =20 if (!wr_mask && val) { - riscv_pmu_read_ctr(env, val, false, ctr_idx); + riscv_pmu_read_ctr(env, val, false, ctr_idx, env->xl); } else if (wr_mask) { - riscv_pmu_write_ctr(env, new_val, ctr_idx); + riscv_pmu_write_ctr(env, new_val, ctr_idx, env->xl); } else { return -EINVAL; } @@ -1524,12 +1527,14 @@ static int rmw_cd_mhpmcounterh(CPURISCVState *env, = int ctr_idx, target_ulong *val, target_ulong new_val, target_ulong wr_mask) { - if (wr_mask !=3D 0 && wr_mask !=3D -1) { + uint64_t xlen_mask =3D env->xl =3D=3D MXL_RV32 ? UINT32_MAX : UINT64_M= AX; + + if (wr_mask !=3D 0 && wr_mask !=3D xlen_mask) { return -EINVAL; } =20 if (!wr_mask && val) { - riscv_pmu_read_ctr(env, val, true, ctr_idx); + riscv_pmu_read_ctr(env, val, true, ctr_idx, env->xl); } else if (wr_mask) { riscv_pmu_write_ctrh(env, new_val, ctr_idx); } else { @@ -1544,8 +1549,9 @@ static int rmw_cd_mhpmevent(CPURISCVState *env, int c= tr_idx, uint64_t wr_mask) { uint64_t mhpmevt_val =3D env->mhpmevent_val[ctr_idx]; + uint64_t xlen_mask =3D env->xl =3D=3D MXL_RV32 ? UINT32_MAX : UINT64_M= AX; =20 - if (wr_mask !=3D 0 && wr_mask !=3D -1) { + if (wr_mask !=3D 0 && wr_mask !=3D xlen_mask) { return -EINVAL; } =20 @@ -1572,8 +1578,9 @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int = ctr_idx, { uint64_t mhpmevt_val =3D env->mhpmevent_val[ctr_idx]; uint32_t mhpmevth_val =3D extract64(mhpmevt_val, 32, 32); + uint64_t xlen_mask =3D env->xl =3D=3D MXL_RV32 ? UINT32_MAX : UINT64_M= AX; =20 - if (wr_mask !=3D 0 && wr_mask !=3D -1) { + if (wr_mask !=3D 0 && wr_mask !=3D xlen_mask) { return -EINVAL; } =20 @@ -1630,10 +1637,6 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int c= fg_index, target_ulong *val, { uint64_t cfgh; =20 - if (riscv_cpu_mxl(env) !=3D MXL_RV32) { - return RISCV_EXCP_ILLEGAL_INST; - } - switch (cfg_index) { case 0: /* CYCLECFGH */ cfgh =3D extract64(env->mcyclecfg, 32, 32); @@ -2809,9 +2812,9 @@ static int rmw_xireg_cd(CPURISCVState *env, int csrno, goto done; } =20 - /* sireg4 and sireg5 provides access RV32 only CSRs */ + /* Delegated high halves are accessible only when the current XLEN is = 32. */ if (((csrno =3D=3D CSR_SIREG5) || (csrno =3D=3D CSR_SIREG4)) && - (riscv_cpu_mxl(env) !=3D MXL_RV32)) { + env->xl !=3D MXL_RV32) { ret =3D RISCV_EXCP_ILLEGAL_INST; goto done; } diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index ea0ffe41258d4dbef9dc952655e6301c14ba1d23..54fff2ba49c1034d5fa6db1c7b1= 9ff59003cd1e1 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -372,10 +372,12 @@ static void pmu_timer_trigger_irq_counter(RISCVCPU *c= pu, uint32_t ctr_idx) return; } =20 - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx); + riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx, + riscv_cpu_mxl(env)); ctr_val =3D counter->mhpmcounter_val; if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_= idx); + riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_= idx, + riscv_cpu_mxl(env)); curr_ctr_val =3D curr_ctr_val | (curr_ctrh_val << 32); } =20 diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index 339a4b3ac09c4a91cddd9250824284203b16b4fa..bf2e8373474d471d914f8801c55= d2f6ffbb5cdd3 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -38,6 +38,7 @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, priv= ilege_mode_t newpriv, bool new_virt); void riscv_pmu_decr_instret(CPURISCVState *env); RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, - bool upper_half, uint32_t ctr_idx); + bool upper_half, uint32_t ctr_idx, + RISCVMXL xl); =20 #endif /* RISCV_PMU_H */ diff --git a/tests/tcg/riscv32/Makefile.softmmu-target b/tests/tcg/riscv32/= Makefile.softmmu-target index 43c162fd337f7b0d5d3e4dedb3f5b06b2821fd88..1316eadc033f15af819eae4416c= 0d37494fb3184 100644 --- a/tests/tcg/riscv32/Makefile.softmmu-target +++ b/tests/tcg/riscv32/Makefile.softmmu-target @@ -24,3 +24,11 @@ run-smcdeleg-minh-rv32: smcdeleg-minh-rv32 TESTS +=3D pmu-minstretcfg-rv32 run-pmu-minstretcfg-rv32: pmu-minstretcfg-rv32 $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + +TESTS +=3D smcdeleg-event-rv32 +run-smcdeleg-event-rv32: smcdeleg-event-rv32 + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + +TESTS +=3D smcdeleg-counter-rv32 +run-smcdeleg-counter-rv32: smcdeleg-counter-rv32 + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv32/smcdeleg-counter-rv32.S b/tests/tcg/riscv32/= smcdeleg-counter-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..1f130f316e95dcbbb9aeee06001= 553a7fe8ae46d --- /dev/null +++ b/tests/tcg/riscv32/smcdeleg-counter-rv32.S @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* RV32 delegated counter accesses must also work in the RV64 emulator. */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* Unexpected exceptions report the current check number. */ + li t4, 1 + lla t0, fail + csrw mtvec, t0 + li t0, 8 /* Stop HPM3 so reads are exact. */ + csrw mcountinhibit, t0 + csrw mcounteren, t0 + li t0, 1 << 28 /* menvcfgh.CDE */ + csrw 0x31a, t0 + li t0, 0x43 /* siselect: counter 3 */ + csrw 0x150, t0 + li t0, 0x12345678 + csrw 0xb83, t0 /* mhpmcounter3h */ + li t0, 1 /* HW_CPU_CYCLES */ + csrw 0x323, t0 + li t0, 0xc0000000 /* OF | MINH */ + csrw 0x723, t0 + + /* sireg writes the low half without changing the high half. */ + li t0, 0x2468ace0 + csrw 0x151, t0 + csrr t1, 0x151 + bne t0, t1, fail + csrr t1, 0xb03 + bne t0, t1, fail + li t0, 0x12345678 + csrr t1, 0xb83 + bne t0, t1, fail + + /* sireg4 writes the high half without changing the low half. */ + li t4, 2 + li t0, 0xfedcba98 + csrw 0x155, t0 + csrr t1, 0x155 + bne t0, t1, fail + csrr t1, 0xb83 + bne t0, t1, fail + li t0, 0x2468ace0 + csrr t1, 0xb03 + bne t0, t1, fail + + /* sireg5 clears OF and sets SINH, but cannot change machine MINH. */ + li t4, 3 + li t0, 0x20000000 /* SINH */ + csrw 0x156, t0 + csrr t1, 0x156 + bne t0, t1, fail + li t0, 0x60000000 /* MINH | SINH */ + csrr t1, 0x723 + bne t0, t1, fail + li t0, 1 + csrr t1, 0x323 + bne t0, t1, fail + + /* sireg2 changes the event without changing those high-half bits. */ + li t4, 4 + li t0, 2 /* HW_INSTRUCTIONS */ + csrw 0x152, t0 + csrr t1, 0x323 + bne t0, t1, fail + li t0, 0x60000000 + csrr t1, 0x723 + bne t0, t1, fail + + li t0, 0x5555 /* FINISHER_PASS */ + j finish +fail: + slli t0, t4, 16 + li t1, 0x3333 /* FINISHER_FAIL with check number */ + or t0, t0, t1 +finish: + li t1, 0x100000 /* virt test device */ + sw t0, 0(t1) + j . diff --git a/tests/tcg/riscv32/smcdeleg-event-rv32.S b/tests/tcg/riscv32/sm= cdeleg-event-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..ee3063a7f5486e7fac53e6035f6= 3fe2d9826611c --- /dev/null +++ b/tests/tcg/riscv32/smcdeleg-event-rv32.S @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* RV32 sireg2 writes replace only the low half of a delegated selector. */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* Any unexpected exception fails with the current check number. */ + li t4, 1 + lla t0, exit + csrw mtvec, t0 + li t0, 8 /* mcountinhibit.HPM3 */ + csrs mcountinhibit, t0 + li t0, 0xe0000000 /* OF | MINH | SINH */ + csrw 0x723, t0 /* mhpmevent3h */ + li t0, 1 /* HW_CPU_CYCLES */ + csrw 0x323, t0 /* mhpmevent3 */ + + li t0, 1 << 28 /* menvcfgh.CDE */ + csrw 0x31a, t0 + li t0, 8 /* Delegate counter 3. */ + csrw mcounteren, t0 + li t0, 0x43 + csrw 0x150, t0 /* siselect: counter 3 */ + + /* Replace the event without changing OF or the privilege filters. */ + li t0, 2 /* HW_INSTRUCTIONS */ + csrw 0x152, t0 /* sireg2: hpmevent3 */ + li t4, 2 + csrr t1, 0x323 + bne t0, t1, exit + li t4, 3 + li t0, 0xe0000000 + csrr t1, 0x723 + bne t0, t1, exit + + /* Selecting event zero must also leave the high half unchanged. */ + li t4, 4 + csrw 0x152, zero + li t4, 5 + csrr t1, 0x323 + bnez t1, exit + li t4, 6 + csrr t1, 0x723 + bne t0, t1, exit + li t4, 0 + + .balign 4 +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sw t0, 0(a1) + sw t4, 4(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 8 diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index af6bc1aad8893726a3b26392da89f34319dd78a8..9f61da861a44881875457506c44= bfc383560d1a9 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -40,6 +40,31 @@ run-test-mcycle-rv32: test-mcycle-rv32 $(call run-test, $<, \ $(QEMU) -cpu rv32 -icount shift=3D1 $(QEMU_OPTS)$<) =20 +smcdeleg-counter-rv32: $(SRC_PATH)/tests/tcg/riscv32/smcdeleg-counter-rv32= .S $(LINK_SCRIPT) + $(CC) $(CFLAGS) $(RV32_CFLAGS) $< -Wa,--noexecstack -c -o $@.o + $(LD) -m elf32lriscv $(LDFLAGS) $@.o -o $@ + +TESTS +=3D smcdeleg-counter-rv32 +run-smcdeleg-counter-rv32: smcdeleg-counter-rv32 + $(call run-test, $<, \ + $(QEMU) -cpu rv32$(COMMA)smcdeleg=3Dtrue$(COMMA)ssccfg=3Dtrue$(COMMA)ss= cofpmf=3Dtrue $(QEMU_OPTS)$<) + +TESTS +=3D smcdeleg-sxl32 smcdeleg-sxl32-high smcdeleg-sxl32-cfg +smcdeleg-sxl32-high: smcdeleg-sxl32.S $(LINK_SCRIPT) + $(CC) $(CFLAGS) -DTEST_HIGH_HALF $< -Wa,--noexecstack -c -o $@.o + $(LD) $(LDFLAGS) $@.o -o $@ + +smcdeleg-sxl32-cfg: smcdeleg-sxl32.S $(LINK_SCRIPT) + $(CC) $(CFLAGS) -DTEST_CONFIG $< -Wa,--noexecstack -c -o $@.o + $(LD) $(LDFLAGS) $@.o -o $@ + +run-smcdeleg-sxl32: smcdeleg-sxl32 + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) +run-smcdeleg-sxl32-high: smcdeleg-sxl32-high + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) +run-smcdeleg-sxl32-cfg: smcdeleg-sxl32-cfg + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + TESTS +=3D sscofpmf-overflow run-sscofpmf-overflow: sscofpmf-overflow $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv64/smcdeleg-sxl32.S b/tests/tcg/riscv64/smcdele= g-sxl32.S new file mode 100644 index 0000000000000000000000000000000000000000..45762ad662099a48a51591bc8a6= eade7b08928ef --- /dev/null +++ b/tests/tcg/riscv64/smcdeleg-sxl32.S @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Exercise delegated PMU registers with MXLEN=3D64 and SXLEN=3D32. + * Build separately for counter low halves, counter high halves and configs + * so a failure in one access path does not hide failures in the others. + */ + + .option norvc + .option norelax + + /* RV64 'li' can emit ADDIW, which is illegal in the RV32 blocks. */ + .macro load32 reg, value + lui \reg, %hi(\value) + addi \reg, \reg, %lo(\value) + .endm + + /* Enter RV32 S-mode; the ECALL trap below returns to M-mode. */ + .macro enter_s32 label + li a0, 0 + li a5, 9 /* Expected exception: S-mode ECALL. */ + li t0, 3 << 11 + csrc mstatus, t0 + li t0, 1 << 11 + csrs mstatus, t0 /* MPP=3DS */ + lla t0, \label + csrw mepc, t0 + mret + .endm + + /* Each alias must be 64-bit in M-mode, even while SXLEN is 32. */ + .macro check_m64_alias csr + li t0, 0x1234567811223344 + csrw 0x151, t0 /* sireg */ + csrr t1, \csr + bne t0, t1, fail + csrr t1, 0x151 + bne t0, t1, fail + + /* High-half aliases must still trap when the current XLEN is 64. */ + li a0, 0 + li a5, 2 /* Expect illegal instruction. */ + li s9, 0 + csrr t0, 0x155 /* sireg4 */ + csrr t0, 0x156 /* sireg5 */ + li t0, 2 + bne s9, t0, fail /* Both accesses must have trapped. */ + .endm + + .macro check_counter index, csr + li s10, \index + 1 /* Counter-specific failure code. */ + li t0, 0x40 + \index + csrw 0x150, t0 /* siselect */ + check_m64_alias \csr + enter_s32 .Ls_counter\@ +.Ls_counter\@: +#ifdef TEST_HIGH_HALF + csrr t0, 0x155 /* sireg4: original high half */ + load32 t1, 0x12345678 + bne t0, t1, .Ls_fail\@ + load32 t0, 0x07654321 + csrw 0x155, t0 + csrr t1, 0x155 + bne t0, t1, .Ls_fail\@ + /* A high-half write must preserve the low half. */ + csrr t0, 0x151 + load32 t1, 0x11223344 +#else + csrr t0, 0x151 /* sireg: original low half */ + load32 t1, 0x11223344 + bne t0, t1, .Ls_fail\@ + load32 t0, 0x55667788 + csrw 0x151, t0 + csrr t1, 0x151 +#endif + bne t0, t1, .Ls_fail\@ + li a0, 0 + j .Ls_done\@ +.Ls_fail\@: + mv a0, s10 +.Ls_done\@: + ecall + + /* Read the complete machine counter to check the unwritten half. */ + csrr t0, \csr +#ifdef TEST_HIGH_HALF + li t1, 0x0765432111223344 +#else + li t1, 0x1234567855667788 +#endif + bne t0, t1, fail + .endm + + .macro check_config index, csr, old_low, new_low + li s10, \index + 1 + li t0, 0x40 + \index + csrw 0x150, t0 + li t0, 0x6000000000000000 | \old_low /* MINH | SINH */ + csrw \csr, t0 + enter_s32 .Ls_config\@ +.Ls_config\@: + csrr t0, 0x152 /* sireg2: config/selector low half */ + li t1, \old_low + bne t0, t1, .Lcfg_fail\@ + li t0, \new_low + csrw 0x152, t0 + csrr t1, 0x152 + bne t0, t1, .Lcfg_fail\@ + + /* Low-half writes preserve the high half; MINH reads as zero. */ + csrr t0, 0x156 /* sireg5 */ + li t1, 0x20000000 /* SINH, without MINH */ + bne t0, t1, .Lcfg_fail\@ + li t0, 0x10000000 /* Replace SINH with UINH. */ + csrw 0x156, t0 + csrr t1, 0x156 + bne t0, t1, .Lcfg_fail\@ + csrr t0, 0x152 + li t1, \new_low + bne t0, t1, .Lcfg_fail\@ + li a0, 0 + j .Lcfg_done\@ +.Lcfg_fail\@: + mv a0, s10 +.Lcfg_done\@: + ecall + + /* Both the low half and the machine-only MINH bit must be retained. */ + csrr t0, \csr + li t1, 0x5000000000000000 | \new_low /* MINH | UINH */ + bne t0, t1, fail + .endm + + .text + .global _start +_start: + li s10, 31 /* Setup failure. */ + lla t0, trap + csrw mtvec, t0 + csrw medeleg, zero + csrw mie, zero + li t0, -1 + /* Freeze counters for exact comparisons. */ + csrw mcountinhibit, t0 + csrw mcounteren, t0 + csrw pmpaddr0, t0 + li t0, 0x1f /* Allow S-mode access to RAM. */ + csrw pmpcfg0, t0 + li t0, 1 << 60 + csrw menvcfg, t0 /* CDE */ + csrw 0x30c, t0 /* mstateen0: allow indirect CSRs. */ + + /* Select RV32 for lower privilege modes; M-mode remains RV64. */ + csrr t0, mstatus + li t1, (3 << 34) | (3 << 32) + not t1, t1 + and t0, t0, t1 + li t1, (1 << 34) | (1 << 32) + or t0, t0, t1 + csrw mstatus, t0 + csrr t0, mstatus + srli t0, t0, 34 + andi t0, t0, 3 + li t1, 1 + bne t0, t1, fail + +#ifdef TEST_CONFIG + check_config 0, 0x321, 0, 0 /* mcyclecfg */ + check_config 2, 0x322, 0, 0 /* minstretcfg */ + check_config 3, 0x323, 1, 2 /* mhpmevent3: cycles -> instructions */ +#else + li t0, 1 + csrw 0x323, t0 /* HPM3 counts cycles. */ + li t0, 2 + csrw 0x324, t0 /* HPM4 counts instructions. */ + csrw 0x325, zero /* HPM5 has no selected event. */ + check_counter 0, mcycle + check_counter 2, minstret + check_counter 3, 0xb03 + check_counter 4, 0xb04 + check_counter 5, 0xb05 +#endif + li a0, 0 + j exit + + .balign 4 +trap: + csrr t0, mcause + bne t0, a5, fail + bnez a0, exit + addi s9, s9, 1 + csrr t0, mepc + /* Zero-extend the RV32 trap PC for physical addressing in M-mode. */ + slli t0, t0, 32 + srli t0, t0, 32 + addi t0, t0, 4 + csrw mepc, t0 + li t0, 3 << 11 + csrs mstatus, t0 /* Resume in M-mode. */ + mret + +fail: + mv a0, s10 +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 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 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712804; cv=none; d=zohomail.com; s=zohoarc; b=SFIhHbTTdSqG4pUWYe+/hWMl+Lzz8UN4SNYTRL/azrS/8HU5pyi/bDNii5D5RGKXqQ6f2hZ9Vyz61uR7/nkXoOUzxiadJKIgI0lYAvNaKnhj7dxEAu+YXe7BUtY+JmW3I88Nj/NzCf2jftmr4KywqvTb9N566IHL9wt1r81HgMw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712804; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=i1hi6u+Hbgi5jrbTE9Nu94CEpQxoJkZsBTm2dNCYUR4=; b=fxKYw3db1gWct5wVg/c1RLUJ/Rg1xQHG5hEEpIxQWgai/XI3K1J15KbuULhYazpl0PmKsTSxRDHokIoDcA7X/doVgOHOgYHIHdq53t2ZsWTPVgDISWgGbH1D3P1/C+yr66B9c6MOjMc2FzuVCmqB4JW+mW8V7K+GBvc6m1/VYeM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712803922349.4230880714083; Sun, 6 Sep 2026 09:40:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsa-0002xa-Va; Sun, 06 Sep 2026 12:38:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsY-0002uE-1X; Sun, 06 Sep 2026 12:38:02 -0400 Received: from [115.124.30.99] (helo=out30-99.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsO-00034A-NV; Sun, 06 Sep 2026 12:38:01 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIJG_1788712654 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:34 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712656; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=i1hi6u+Hbgi5jrbTE9Nu94CEpQxoJkZsBTm2dNCYUR4=; b=LisS9Do+qZkbvqPhmtQEpCus+DcbH1PWKMu5G+BsOc2zkWal+Ojxkb+WY+tbA2PdN6xl912mu89hexE8C72KvNSgG6TpV9VaNYf/asovyOwT+IEiZbah7nwSeSrcw1fOz+VaOxiBoTOl6c4vg5WOeSYO+LR5C+pmbtNHjqYUO5A= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R131e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033045133197; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIJG_1788712654; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:23 +0800 Subject: [PATCH 07/14] target/riscv: Preserve fixed counters across PMU state changes MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-7-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=44070; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=t3aDD2Krbx/hV8NYV9xGKyzpCcDSatHQVvGTsPuzsiE=; b=1TBC0Puz1ham7jnwgwTH3wxOOSEHJ44TOK8g5LsQYT2j/azLnD2xfw5pkskOKU4QSeEZu7Sdg RC7+U/1SKScBHtjFyMLCW3kzoiXQCxK3L/FzA23cm0deikP3Nh+UIMn X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.99 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.99; envelope-from=lyndra@linux.alibaba.com; helo=out30-99.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712806447158500 mcycle/minstret and HPM cycle/instruction counters use a stored value plus the increment since a source baseline. Changing selectors, filters or inhibit bits before accounting for the old settings can lose counts or add inhibited time. Take one snapshot, add the increments allowed by the old settings, apply the write and establish the new baseline from that snapshot. Share this sequence between direct and indirect CSR accesses. Merge selector bits after accounting so low-half writes preserve OF set by a pending wrap; explicit high-half or RV64 writes can still clear it. Preserve full-width arithmetic for RV32 accesses and keep source baselines independent of written counter bits. Delegated writes must preserve machine MINH. Test filter changes, RV32 counter halves and OF across partial selector writes. Signed-off-by: TANG Tiancheng --- target/riscv/cpu.h | 8 +- target/riscv/tcg/csr.c | 243 +++++------------------ target/riscv/tcg/pmu.c | 309 +++++++++++++++++++++++++-= ---- target/riscv/tcg/pmu.h | 18 +- tests/tcg/riscv32/Makefile.softmmu-target | 8 + tests/tcg/riscv32/pmu-fixed-rv32.S | 90 +++++++++ tests/tcg/riscv32/sscofpmf-event-rv32.S | 91 +++++++++ tests/tcg/riscv64/Makefile.softmmu-target | 4 + tests/tcg/riscv64/pmu-cycle-controls.S | 77 ++++++++ 9 files changed, 602 insertions(+), 246 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c2138dbd4ba312a5cb17f0916bce64d6faad38a9..f7b1bfc9cf5069125bc22dc2674= d8e67431c5970 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -240,6 +240,12 @@ typedef struct PMUCTRState { uint64_t irq_overflow_left; } PMUCTRState; =20 +typedef enum { + RISCV_PMU_FIXED_DOMAIN_CYCLE, + RISCV_PMU_FIXED_DOMAIN_INSTRET, + RISCV_PMU_FIXED_DOMAIN_COUNT, +} RISCVPMUFixedDomain; + typedef struct PMUFixedCtrState { /* Track cycle and icount for each privilege mode */ uint64_t counter[4]; @@ -465,7 +471,7 @@ struct CPUArchState { */ uint64_t mhpmevent_val[RV_MAX_MHPMEVENTS]; =20 - PMUFixedCtrState pmu_fixed_ctrs[2]; + PMUFixedCtrState pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_COUNT]; =20 uint64_t sscratch; uint64_t mscratch; diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index d72368ccb5a1bd5f26a20b8e4a3c214b842afba6..65edd9d2eed06956c65aef266a7= 6f74b1545487f 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -1110,9 +1110,10 @@ static RISCVException write_mcyclecfg(CPURISCVState = *env, int csrno, target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; + uint64_t value; =20 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - env->mcyclecfg =3D deposit64(env->mcyclecfg, 0, 32, val); + value =3D deposit64(env->mcyclecfg, 0, 32, val); } else { /* Set xINH fields if priv mode supported */ inh_avail_mask =3D ~MHPMEVENT_FILTER_MASK | MCYCLECFG_BIT_MINH; @@ -1122,8 +1123,9 @@ static RISCVException write_mcyclecfg(CPURISCVState *= env, int csrno, riscv_has_ext(env, RVU)) ? MCYCLECFG_BIT_VUINH = : 0; inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MCYCLECFG_BIT_VSINH = : 0; - env->mcyclecfg =3D val & inh_avail_mask; + value =3D val & inh_avail_mask; } + riscv_pmu_write_ctr_cfg(env, 0, value); =20 return RISCV_EXCP_NONE; } @@ -1149,7 +1151,9 @@ static RISCVException write_mcyclecfgh(CPURISCVState = *env, int csrno, inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MCYCLECFGH_BIT_VSINH : 0; =20 - env->mcyclecfg =3D deposit64(env->mcyclecfg, 32, 32, val & inh_avail_m= ask); + riscv_pmu_write_ctr_cfg(env, 0, + deposit64(env->mcyclecfg, 32, 32, + val & inh_avail_mask)); return RISCV_EXCP_NONE; } =20 @@ -1165,9 +1169,10 @@ static RISCVException write_minstretcfg(CPURISCVStat= e *env, int csrno, target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; + uint64_t value; =20 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - env->minstretcfg =3D deposit64(env->minstretcfg, 0, 32, val); + value =3D deposit64(env->minstretcfg, 0, 32, val); } else { inh_avail_mask =3D ~MHPMEVENT_FILTER_MASK | MINSTRETCFG_BIT_MINH; inh_avail_mask |=3D riscv_has_ext(env, RVU) ? MINSTRETCFG_BIT_UINH= : 0; @@ -1176,8 +1181,9 @@ static RISCVException write_minstretcfg(CPURISCVState= *env, int csrno, riscv_has_ext(env, RVU)) ? MINSTRETCFG_BIT_VUIN= H : 0; inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MINSTRETCFG_BIT_VSIN= H : 0; - env->minstretcfg =3D val & inh_avail_mask; + value =3D val & inh_avail_mask; } + riscv_pmu_write_ctr_cfg(env, 2, value); return RISCV_EXCP_NONE; } =20 @@ -1201,8 +1207,9 @@ static RISCVException write_minstretcfgh(CPURISCVStat= e *env, int csrno, inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MINSTRETCFGH_BIT_VSINH := 0; =20 - env->minstretcfg =3D deposit64(env->minstretcfg, 32, 32, - val & inh_avail_mask); + riscv_pmu_write_ctr_cfg(env, 2, + deposit64(env->minstretcfg, 32, 32, + val & inh_avail_mask)); return RISCV_EXCP_NONE; } =20 @@ -1217,50 +1224,17 @@ static RISCVException read_mhpmevent(CPURISCVState = *env, int csrno, return RISCV_EXCP_NONE; } =20 -static uint64_t riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, - int counter_idx); - -static void riscv_pmu_write_mhpmevent(CPURISCVState *env, - uint32_t ctr_idx, uint64_t value) -{ - PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; - bool enabled =3D !get_field(env->mcountinhibit, BIT(ctr_idx)); - - /* - * A programmable counter backed by a fixed source uses mhpmcounter_val - * as its base and mhpmcounter_prev as the source snapshot. Preserve = the - * visible value before changing the source or its privilege filters. - */ - if (enabled && - (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - uint64_t source =3D riscv_pmu_ctr_get_fixed_counters_val(env, - ctr_idx); - - counter->mhpmcounter_val +=3D source - counter->mhpmcounter_prev; - } - - env->mhpmevent_val[ctr_idx] =3D value; - riscv_pmu_rebuild_event_map(env); - - if (enabled && - (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - counter->mhpmcounter_prev =3D - riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); - } -} - static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { int ctr_idx =3D csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val; uint64_t inh_avail_mask; + uint64_t wr_mask =3D UINT64_MAX; =20 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - mhpmevt_val =3D deposit64(env->mhpmevent_val[ctr_idx], 0, 32, val); + mhpmevt_val =3D val; + wr_mask =3D UINT32_MAX; } else { inh_avail_mask =3D ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH; inh_avail_mask |=3D riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH := 0; @@ -1272,7 +1246,7 @@ static RISCVException write_mhpmevent(CPURISCVState *= env, int csrno, mhpmevt_val =3D val & inh_avail_mask; } =20 - riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); + riscv_pmu_write_event(env, ctr_idx, mhpmevt_val, wr_mask); =20 return RISCV_EXCP_NONE; } @@ -1301,9 +1275,9 @@ static RISCVException write_mhpmeventh(CPURISCVState = *env, int csrno, inh_avail_mask |=3D (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; =20 - riscv_pmu_write_mhpmevent(env, ctr_idx, - deposit64(env->mhpmevent_val[ctr_idx], 32, 3= 2, - val & inh_avail_mask)); + riscv_pmu_write_event(env, ctr_idx, + (uint64_t)(val & inh_avail_mask) << 32, + MAKE_64BIT_MASK(32, 32)); =20 return RISCV_EXCP_NONE; } @@ -1311,106 +1285,10 @@ static RISCVException write_mhpmeventh(CPURISCVSta= te *env, int csrno, static uint64_t riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, int counter_idx) { - int inst =3D riscv_pmu_ctr_monitor_instructions(env, counter_idx); - uint64_t *counter_arr_virt =3D env->pmu_fixed_ctrs[inst].counter_virt; - uint64_t *counter_arr =3D env->pmu_fixed_ctrs[inst].counter; - uint64_t curr_val =3D 0; - uint64_t cfg_val =3D 0; - - if (counter_idx =3D=3D 0) { - cfg_val =3D env->mcyclecfg; - } else if (counter_idx =3D=3D 2) { - cfg_val =3D env->minstretcfg; - } else { - cfg_val =3D env->mhpmevent_val[counter_idx]; - cfg_val &=3D MHPMEVENT_FILTER_MASK; - } - - if (!cfg_val) { - return riscv_pmu_read_fixed_source(env, inst); - } - - /* Update counter before reading. */ - riscv_pmu_update_fixed_ctrs(env, env->priv, env->virt_enabled); - - if (!(cfg_val & MCYCLECFG_BIT_MINH)) { - curr_val +=3D counter_arr[PRV_M]; - } - - if (!(cfg_val & MCYCLECFG_BIT_SINH)) { - curr_val +=3D counter_arr[PRV_S]; - } + RISCVPMUFixedSnapshot snapshot; =20 - if (!(cfg_val & MCYCLECFG_BIT_UINH)) { - curr_val +=3D counter_arr[PRV_U]; - } - - if (!(cfg_val & MCYCLECFG_BIT_VSINH)) { - curr_val +=3D counter_arr_virt[PRV_S]; - } - - if (!(cfg_val & MCYCLECFG_BIT_VUINH)) { - curr_val +=3D counter_arr_virt[PRV_U]; - } - - return curr_val; -} - -static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong= val, - uint32_t ctr_idx, RISCVMXL xl) -{ - PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; - bool rv32 =3D xl =3D=3D MXL_RV32; - int deposit_size =3D rv32 ? 32 : 64; - uint64_t ctr; - - if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && - (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctr =3D riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); - counter->mhpmcounter_val +=3D ctr - counter->mhpmcounter_prev; - counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, - 0, deposit_size, val); - counter->mhpmcounter_prev =3D ctr; - if (ctr_idx > 2) { - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); - } - } else { - counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, - 0, deposit_size, val); - /* Other counters can keep incrementing from the given value */ - counter->mhpmcounter_prev =3D deposit64(counter->mhpmcounter_prev, - 0, deposit_size, val); - } - - return RISCV_EXCP_NONE; -} - -static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulon= g val, - uint32_t ctr_idx) -{ - PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; - uint64_t ctr; - - if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && - (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctr =3D riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); - counter->mhpmcounter_val +=3D ctr - counter->mhpmcounter_prev; - counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, - 32, 32, val); - counter->mhpmcounter_prev =3D ctr; - if (ctr_idx > 2) { - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); - } - } else { - counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, - 32, 32, val); - counter->mhpmcounter_prev =3D deposit64(counter->mhpmcounter_prev, - 32, 32, val); - } - - return RISCV_EXCP_NONE; + riscv_pmu_take_fixed_snapshot(env, &snapshot); + return riscv_pmu_ctr_get_fixed_value(env, counter_idx, &snapshot); } =20 static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, @@ -1418,7 +1296,8 @@ static RISCVException write_mhpmcounter(CPURISCVState= *env, int csrno, { int ctr_idx =3D csrno - CSR_MCYCLE; =20 - return riscv_pmu_write_ctr(env, val, ctr_idx, riscv_cpu_mxl(env)); + riscv_pmu_write_counter(env, ctr_idx, val, false, riscv_cpu_mxl(env)); + return RISCV_EXCP_NONE; } =20 static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, @@ -1426,7 +1305,8 @@ static RISCVException write_mhpmcounterh(CPURISCVStat= e *env, int csrno, { int ctr_idx =3D csrno - CSR_MCYCLEH; =20 - return riscv_pmu_write_ctrh(env, val, ctr_idx); + riscv_pmu_write_counter(env, ctr_idx, val, true, riscv_cpu_mxl(env)); + return RISCV_EXCP_NONE; } =20 RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, @@ -1515,7 +1395,7 @@ static int rmw_cd_mhpmcounter(CPURISCVState *env, int= ctr_idx, if (!wr_mask && val) { riscv_pmu_read_ctr(env, val, false, ctr_idx, env->xl); } else if (wr_mask) { - riscv_pmu_write_ctr(env, new_val, ctr_idx, env->xl); + riscv_pmu_write_counter(env, ctr_idx, new_val, false, env->xl); } else { return -EINVAL; } @@ -1536,7 +1416,7 @@ static int rmw_cd_mhpmcounterh(CPURISCVState *env, in= t ctr_idx, if (!wr_mask && val) { riscv_pmu_read_ctr(env, val, true, ctr_idx, env->xl); } else if (wr_mask) { - riscv_pmu_write_ctrh(env, new_val, ctr_idx); + riscv_pmu_write_counter(env, ctr_idx, new_val, true, env->xl); } else { return -EINVAL; } @@ -1562,9 +1442,7 @@ static int rmw_cd_mhpmevent(CPURISCVState *env, int c= tr_idx, } } else if (wr_mask) { wr_mask &=3D ~MHPMEVENT_BIT_MINH; - /* wr_mask is 64-bit so upper 32 bits of mhpmevt_val are retained = */ - mhpmevt_val =3D (new_val & wr_mask) | (mhpmevt_val & ~wr_mask); - riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); + riscv_pmu_write_event(env, ctr_idx, new_val, wr_mask); } else { return -EINVAL; } @@ -1591,9 +1469,8 @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int = ctr_idx, } } else if (wr_mask) { wr_mask &=3D ~MHPMEVENTH_BIT_MINH; - mhpmevth_val =3D (new_val & wr_mask) | (mhpmevth_val & ~wr_mask); - mhpmevt_val =3D deposit64(mhpmevt_val, 32, 32, mhpmevth_val); - riscv_pmu_write_mhpmevent(env, ctr_idx, mhpmevt_val); + riscv_pmu_write_event(env, ctr_idx, (uint64_t)new_val << 32, + (uint64_t)wr_mask << 32); } else { return -EINVAL; } @@ -1612,7 +1489,9 @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg= _index, target_ulong *val, case 0: /* CYCLECFG */ if (wr_mask) { wr_mask &=3D ~MCYCLECFG_BIT_MINH; - env->mcyclecfg =3D (new_val & wr_mask) | (env->mcyclecfg & ~wr= _mask); + riscv_pmu_write_ctr_cfg(env, 0, + (new_val & wr_mask) | + (env->mcyclecfg & ~wr_mask)); } else { *val =3D env->mcyclecfg & ~MCYCLECFG_BIT_MINH; } @@ -1620,8 +1499,9 @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg= _index, target_ulong *val, case 2: /* INSTRETCFG */ if (wr_mask) { wr_mask &=3D ~MINSTRETCFG_BIT_MINH; - env->minstretcfg =3D (new_val & wr_mask) | - (env->minstretcfg & ~wr_mask); + riscv_pmu_write_ctr_cfg(env, 2, + (new_val & wr_mask) | + (env->minstretcfg & ~wr_mask)); } else { *val =3D env->minstretcfg & ~MINSTRETCFG_BIT_MINH; } @@ -1643,7 +1523,8 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cf= g_index, target_ulong *val, if (wr_mask) { wr_mask &=3D ~MCYCLECFGH_BIT_MINH; cfgh =3D (new_val & wr_mask) | (cfgh & ~wr_mask); - env->mcyclecfg =3D deposit64(env->mcyclecfg, 32, 32, cfgh); + riscv_pmu_write_ctr_cfg(env, 0, + deposit64(env->mcyclecfg, 32, 32, cfgh= )); } else { *val =3D cfgh & ~MCYCLECFGH_BIT_MINH; } @@ -1653,7 +1534,8 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cf= g_index, target_ulong *val, if (wr_mask) { wr_mask &=3D ~MINSTRETCFGH_BIT_MINH; cfgh =3D (new_val & wr_mask) | (cfgh & ~wr_mask); - env->minstretcfg =3D deposit64(env->minstretcfg, 32, 32, cfgh); + riscv_pmu_write_ctr_cfg(env, 2, + deposit64(env->minstretcfg, 32, 32, cf= gh)); } else { *val =3D cfgh & ~MINSTRETCFGH_BIT_MINH; } @@ -3092,44 +2974,7 @@ static RISCVException read_mcountinhibit(CPURISCVSta= te *env, int csrno, static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - int cidx; - PMUCTRState *counter; - RISCVCPU *cpu =3D env_archcpu(env); - uint32_t present_ctrs =3D cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTER= EN_IR; - target_ulong updated_ctrs =3D (env->mcountinhibit ^ val) & present_ctr= s; - uint64_t mhpmctr_val, prev_count, curr_count; - - /* WARL register - disable unavailable counters; TM bit is always 0 */ - env->mcountinhibit =3D val & present_ctrs; - - /* Check if any other counter is also monitoring cycles/instructions */ - for (cidx =3D 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) { - if (!(updated_ctrs & BIT(cidx)) || - (!riscv_pmu_ctr_monitor_cycles(env, cidx) && - !riscv_pmu_ctr_monitor_instructions(env, cidx))) { - continue; - } - - counter =3D &env->pmu_ctrs[cidx]; - - if (!get_field(env->mcountinhibit, BIT(cidx))) { - counter->mhpmcounter_prev =3D riscv_pmu_ctr_get_fixed_counters= _val(env, cidx); - - if (cidx > 2) { - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, cidx); - } - } else { - curr_count =3D riscv_pmu_ctr_get_fixed_counters_val(env, cidx); - - mhpmctr_val =3D counter->mhpmcounter_val; - prev_count =3D counter->mhpmcounter_prev; - - /* Adjust the counter for later reads. */ - mhpmctr_val =3D curr_count - prev_count + mhpmctr_val; - counter->mhpmcounter_val =3D mhpmctr_val; - } - } - + riscv_pmu_write_inhibit(env, val); return RISCV_EXCP_NONE; } =20 diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 54fff2ba49c1034d5fa6db1c7b19ff59003cd1e1..16942e53489cd5a2d2dd055fdff= ef07d04d59465 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -85,15 +85,27 @@ static bool riscv_pmu_counter_filtered(CPURISCVState *e= nv, uint64_t cfg) * VM-elapsed ticks stop advancing while VM ticks are disabled. Under * icount, instruction events retain raw instruction-count units. */ -uint64_t riscv_pmu_read_fixed_source(CPURISCVState *env, bool instret) +static uint64_t riscv_pmu_read_fixed_source(CPURISCVState *env, + RISCVPMUFixedDomain domain) { - if (instret && icount_enabled()) { + if (domain =3D=3D RISCV_PMU_FIXED_DOMAIN_INSTRET && icount_enabled()) { return icount_get_raw(); } =20 + g_assert(domain =3D=3D RISCV_PMU_FIXED_DOMAIN_CYCLE || + domain =3D=3D RISCV_PMU_FIXED_DOMAIN_INSTRET); return cpus_get_elapsed_ticks(); } =20 +void riscv_pmu_take_fixed_snapshot(CPURISCVState *env, + RISCVPMUFixedSnapshot *snapshot) +{ + snapshot->cycle =3D + riscv_pmu_read_fixed_source(env, RISCV_PMU_FIXED_DOMAIN_CYCLE); + snapshot->instret =3D + riscv_pmu_read_fixed_source(env, RISCV_PMU_FIXED_DOMAIN_INSTRET); +} + /* * Information needed to update counters: * new_priv, new_virt: To correctly save starting snapshot for the newly @@ -106,82 +118,289 @@ uint64_t riscv_pmu_read_fixed_source(CPURISCVState *= env, bool instret) * env->priv and env->virt_enabled contain old priv and old virt and * new priv and new virt values are passed in as arguments. */ -static void riscv_pmu_icount_update_priv(CPURISCVState *env, - privilege_mode_t newpriv, - bool new_virt) +static void riscv_pmu_fixed_update_priv(CPURISCVState *env, + privilege_mode_t newpriv, + bool new_virt, + RISCVPMUFixedDomain domain, + uint64_t source) { + PMUFixedCtrState *fixed =3D &env->pmu_fixed_ctrs[domain]; uint64_t *snapshot_prev, *snapshot_new; - uint64_t current_icount; uint64_t *counter_arr; uint64_t delta; =20 - current_icount =3D riscv_pmu_read_fixed_source(env, true); - if (env->virt_enabled) { g_assert(env->priv <=3D PRV_S); - counter_arr =3D env->pmu_fixed_ctrs[1].counter_virt; - snapshot_prev =3D env->pmu_fixed_ctrs[1].counter_virt_prev; + counter_arr =3D fixed->counter_virt; + snapshot_prev =3D fixed->counter_virt_prev; } else { - counter_arr =3D env->pmu_fixed_ctrs[1].counter; - snapshot_prev =3D env->pmu_fixed_ctrs[1].counter_prev; + counter_arr =3D fixed->counter; + snapshot_prev =3D fixed->counter_prev; } =20 if (new_virt) { g_assert(newpriv <=3D PRV_S); - snapshot_new =3D env->pmu_fixed_ctrs[1].counter_virt_prev; + snapshot_new =3D fixed->counter_virt_prev; } else { - snapshot_new =3D env->pmu_fixed_ctrs[1].counter_prev; + snapshot_new =3D fixed->counter_prev; } =20 - /* - * new_priv can be same as env->priv. So we need to calculate - * delta first before updating snapshot_new[new_priv]. - */ - delta =3D current_icount - snapshot_prev[env->priv]; - snapshot_new[newpriv] =3D current_icount; + /* + * new_priv can be same as env->priv. So we need to calculate + * delta first before updating snapshot_new[new_priv]. + */ + delta =3D source - snapshot_prev[env->priv]; + snapshot_new[newpriv] =3D source; =20 counter_arr[env->priv] +=3D delta; } =20 -static void riscv_pmu_cycle_update_priv(CPURISCVState *env, - privilege_mode_t newpriv, - bool new_virt) +static void +riscv_pmu_update_fixed_ctrs_snapshot(CPURISCVState *env, + privilege_mode_t newpriv, bool new_vi= rt, + const RISCVPMUFixedSnapshot *snapshot) { - uint64_t *snapshot_prev, *snapshot_new; - uint64_t current_ticks; + riscv_pmu_fixed_update_priv(env, newpriv, new_virt, + RISCV_PMU_FIXED_DOMAIN_CYCLE, + snapshot->cycle); + riscv_pmu_fixed_update_priv(env, newpriv, new_virt, + RISCV_PMU_FIXED_DOMAIN_INSTRET, + snapshot->instret); +} + +void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, + privilege_mode_t newpriv, + bool new_virt) +{ + RISCVPMUFixedSnapshot snapshot; + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + riscv_pmu_update_fixed_ctrs_snapshot(env, newpriv, new_virt, &snapshot= ); +} + +uint64_t +riscv_pmu_ctr_get_fixed_value(CPURISCVState *env, uint32_t ctr_idx, + const RISCVPMUFixedSnapshot *snapshot) +{ + RISCVPMUFixedDomain domain; + PMUFixedCtrState *fixed; + uint64_t *counter_arr_virt; uint64_t *counter_arr; - uint64_t delta; + uint64_t cfg; + uint64_t value =3D 0; =20 - current_ticks =3D riscv_pmu_read_fixed_source(env, false); + if (riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + domain =3D RISCV_PMU_FIXED_DOMAIN_INSTRET; + } else { + domain =3D RISCV_PMU_FIXED_DOMAIN_CYCLE; + } =20 - if (env->virt_enabled) { - g_assert(env->priv <=3D PRV_S); - counter_arr =3D env->pmu_fixed_ctrs[0].counter_virt; - snapshot_prev =3D env->pmu_fixed_ctrs[0].counter_virt_prev; + fixed =3D &env->pmu_fixed_ctrs[domain]; + counter_arr_virt =3D fixed->counter_virt; + counter_arr =3D fixed->counter; + + if (ctr_idx =3D=3D 0) { + cfg =3D env->mcyclecfg; + } else if (ctr_idx =3D=3D 2) { + cfg =3D env->minstretcfg; } else { - counter_arr =3D env->pmu_fixed_ctrs[0].counter; - snapshot_prev =3D env->pmu_fixed_ctrs[0].counter_prev; + cfg =3D env->mhpmevent_val[ctr_idx] & MHPMEVENT_FILTER_MASK; } =20 - if (new_virt) { - g_assert(newpriv <=3D PRV_S); - snapshot_new =3D env->pmu_fixed_ctrs[0].counter_virt_prev; + if (!cfg) { + return domain =3D=3D RISCV_PMU_FIXED_DOMAIN_INSTRET ? + snapshot->instret : snapshot->cycle; + } + + riscv_pmu_update_fixed_ctrs_snapshot(env, env->priv, env->virt_enabled, + snapshot); + + if (!(cfg & MCYCLECFG_BIT_MINH)) { + value +=3D counter_arr[PRV_M]; + } + if (!(cfg & MCYCLECFG_BIT_SINH)) { + value +=3D counter_arr[PRV_S]; + } + if (!(cfg & MCYCLECFG_BIT_UINH)) { + value +=3D counter_arr[PRV_U]; + } + if (!(cfg & MCYCLECFG_BIT_VSINH)) { + value +=3D counter_arr_virt[PRV_S]; + } + if (!(cfg & MCYCLECFG_BIT_VUINH)) { + value +=3D counter_arr_virt[PRV_U]; + } + + return value; +} + +static bool riscv_pmu_fixed_ctr_selected(CPURISCVState *env, + uint32_t ctr_idx) +{ + return riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx); +} + +static bool riscv_pmu_fixed_ctr_enabled(CPURISCVState *env, + uint32_t ctr_idx) +{ + return !(env->mcountinhibit & BIT(ctr_idx)) && + riscv_pmu_fixed_ctr_selected(env, ctr_idx); +} + +static bool riscv_pmu_fixed_ctr_running(CPURISCVState *env, + uint32_t ctr_idx) +{ + return riscv_pmu_fixed_ctr_enabled(env, ctr_idx); +} + +static void riscv_pmu_set_overflow(CPURISCVState *env, uint32_t ctr_idx) +{ + if (ctr_idx < 3 || !riscv_cpu_cfg(env)->ext_sscofpmf || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + return; + } + + env->mhpmevent_val[ctr_idx] |=3D MHPMEVENT_BIT_OF; + riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); +} + +/* + * Accumulate the delta from mhpmcounter_prev to the fixed source snapshot, + * then align mhpmcounter_prev with that snapshot. + */ +static void +riscv_pmu_accumulate_fixed_delta(CPURISCVState *env, uint32_t ctr_idx, + const RISCVPMUFixedSnapshot *snapshot) +{ + PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; + uint64_t source, delta, value; + + g_assert(riscv_pmu_fixed_ctr_selected(env, ctr_idx)); + + source =3D riscv_pmu_ctr_get_fixed_value(env, ctr_idx, snapshot); + delta =3D source - counter->mhpmcounter_prev; + value =3D counter->mhpmcounter_val; + + if (delta > UINT64_MAX - value) { + riscv_pmu_set_overflow(env, ctr_idx); + } + + counter->mhpmcounter_val =3D value + delta; + counter->mhpmcounter_prev =3D source; +} + +static void +riscv_pmu_set_fixed_baseline(CPURISCVState *env, uint32_t ctr_idx, + const RISCVPMUFixedSnapshot *snapshot) +{ + g_assert(riscv_pmu_fixed_ctr_selected(env, ctr_idx)); + env->pmu_ctrs[ctr_idx].mhpmcounter_prev =3D + riscv_pmu_ctr_get_fixed_value(env, ctr_idx, snapshot); +} + +void riscv_pmu_write_ctr_cfg(CPURISCVState *env, uint32_t ctr_idx, + uint64_t value) +{ + RISCVPMUFixedSnapshot snapshot; + + g_assert(ctr_idx =3D=3D 0 || ctr_idx =3D=3D 2); + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); + } + if (ctr_idx =3D=3D 0) { + env->mcyclecfg =3D value; } else { - snapshot_new =3D env->pmu_fixed_ctrs[0].counter_prev; + env->minstretcfg =3D value; + } + if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { + riscv_pmu_set_fixed_baseline(env, ctr_idx, &snapshot); } +} =20 - delta =3D current_ticks - snapshot_prev[env->priv]; - snapshot_new[newpriv] =3D current_ticks; +void riscv_pmu_write_event(CPURISCVState *env, uint32_t ctr_idx, + uint64_t value, uint64_t wr_mask) +{ + RISCVPMUFixedSnapshot snapshot; + PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; =20 - counter_arr[env->priv] +=3D delta; + riscv_pmu_take_fixed_snapshot(env, &snapshot); + if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); + } + /* Accumulating the old source can set OF outside the written bits. */ + env->mhpmevent_val[ctr_idx] =3D (value & wr_mask) | + (env->mhpmevent_val[ctr_idx] & ~wr_mask); + riscv_pmu_rebuild_event_map(env); + if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { + riscv_pmu_set_fixed_baseline(env, ctr_idx, &snapshot); + } + + if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); + } } =20 -void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, - privilege_mode_t newpriv, - bool new_virt) +void riscv_pmu_write_counter(CPURISCVState *env, uint32_t ctr_idx, + target_ulong value, bool upper_half, RISCVMXL= xl) +{ + RISCVPMUFixedSnapshot snapshot; + PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; + bool rv32 =3D xl =3D=3D MXL_RV32; + bool running; + int start =3D upper_half ? 32 : 0; + int length =3D rv32 ? 32 : 64; + + g_assert(rv32 || !upper_half); + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + running =3D riscv_pmu_fixed_ctr_running(env, ctr_idx); + if (running) { + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); + } + counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, + start, length, value); + /* mhpmcounter_prev tracks the source, not the written counter value. = */ + if (running && ctr_idx > 2) { + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); + } +} + +void riscv_pmu_write_inhibit(CPURISCVState *env, uint32_t value) { - riscv_pmu_cycle_update_priv(env, newpriv, new_virt); - riscv_pmu_icount_update_priv(env, newpriv, new_virt); + RISCVCPU *cpu =3D env_archcpu(env); + RISCVPMUFixedSnapshot snapshot; + uint32_t present =3D cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; + uint32_t old =3D env->mcountinhibit; + uint32_t changed =3D (old ^ value) & present; + uint32_t ctr_idx; + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + for (ctr_idx =3D 0; ctr_idx < RV_MAX_MHPMCOUNTERS; ctr_idx++) { + if ((changed & BIT(ctr_idx)) && !(old & BIT(ctr_idx)) && + riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); + } + } + + env->mcountinhibit =3D value & present; + + for (ctr_idx =3D 0; ctr_idx < RV_MAX_MHPMCOUNTERS; ctr_idx++) { + if (!(changed & BIT(ctr_idx)) || + (env->mcountinhibit & BIT(ctr_idx))) { + continue; + } + + if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { + riscv_pmu_set_fixed_baseline(env, ctr_idx, &snapshot); + } + if (ctr_idx > 2 && riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_setup_timer(env, env->pmu_ctrs[ctr_idx].mhpmcounter_= val, + ctr_idx); + } + } } =20 void riscv_pmu_decr_instret(CPURISCVState *env) diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index bf2e8373474d471d914f8801c55d2f6ffbb5cdd3..1494fbc21f53137a90c1338f6ca= 8e3c3e750276a 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -22,11 +22,27 @@ #include "cpu.h" #include "qapi/error.h" =20 +typedef struct RISCVPMUFixedSnapshot { + uint64_t cycle; + uint64_t instret; +} RISCVPMUFixedSnapshot; + bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env, uint32_t target_ctr); bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr); -uint64_t riscv_pmu_read_fixed_source(CPURISCVState *env, bool instret); +void riscv_pmu_take_fixed_snapshot(CPURISCVState *env, + RISCVPMUFixedSnapshot *snapshot); +uint64_t riscv_pmu_ctr_get_fixed_value(CPURISCVState *env, + uint32_t ctr_idx, + const RISCVPMUFixedSnapshot *snapsh= ot); +void riscv_pmu_write_ctr_cfg(CPURISCVState *env, uint32_t ctr_idx, + uint64_t value); +void riscv_pmu_write_event(CPURISCVState *env, uint32_t ctr_idx, + uint64_t value, uint64_t wr_mask); +void riscv_pmu_write_counter(CPURISCVState *env, uint32_t ctr_idx, + target_ulong value, bool upper_half, RISCVMXL= xl); +void riscv_pmu_write_inhibit(CPURISCVState *env, uint32_t value); void riscv_pmu_timer_cb(void *priv); void riscv_pmu_init(RISCVCPU *cpu, Error **errp); void riscv_pmu_rebuild_event_map(CPURISCVState *env); diff --git a/tests/tcg/riscv32/Makefile.softmmu-target b/tests/tcg/riscv32/= Makefile.softmmu-target index 1316eadc033f15af819eae4416c0d37494fb3184..f886dc00920c22deea641a0e5b8= 431397412dac5 100644 --- a/tests/tcg/riscv32/Makefile.softmmu-target +++ b/tests/tcg/riscv32/Makefile.softmmu-target @@ -17,6 +17,10 @@ CFLAGS +=3D -g -Og $(EXTRA_CFLAGS) -march=3Drv32im_zicsr= -mabi=3Dilp32 =20 QEMU_OPTS +=3D -M virt -display none -semihosting -device loader,file=3D =20 +TESTS +=3D pmu-fixed-rv32 +run-pmu-fixed-rv32: pmu-fixed-rv32 + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) + TESTS +=3D smcdeleg-minh-rv32 run-smcdeleg-minh-rv32: smcdeleg-minh-rv32 $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) @@ -32,3 +36,7 @@ run-smcdeleg-event-rv32: smcdeleg-event-rv32 TESTS +=3D smcdeleg-counter-rv32 run-smcdeleg-counter-rv32: smcdeleg-counter-rv32 $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) + +TESTS +=3D sscofpmf-event-rv32 +run-sscofpmf-event-rv32: sscofpmf-event-rv32 + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv32/pmu-fixed-rv32.S b/tests/tcg/riscv32/pmu-fix= ed-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..3910ca97cadd133bd1cbc9a546f= dd29b6f23d1b6 --- /dev/null +++ b/tests/tcg/riscv32/pmu-fixed-rv32.S @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* + * Failure bits: + * 0: selecting cycles changes the initialized high half + * 1: a low-half write discards a carry into the visible high half + * 2: the high-half read does not match the value just written + */ + li t4, 0 + csrw 0x323, zero /* mhpmevent3 */ + csrw 0xb03, zero /* mhpmcounter3 */ + li t0, 1 + csrw 0xb83, t0 /* mhpmcounter3h */ + li t0, 1 + csrw 0x323, t0 /* mhpmevent3: cycles */ + + /* Starting the counter must preserve its initialized high half. */ + csrr t0, 0xc83 /* hpmcounter3h */ + li t1, 1 + xor t0, t0, t1 + sltu t0, zero, t0 + or t4, t4, t0 + + /* + * Start 256 cycles below 2 << 32. With -icount shift=3D0, the + * following instructions carry into the visible high half. A + * low-half write must replace only bits 31:0 and preserve that carry. + */ + csrw 0x323, zero /* mhpmevent3 */ + li t0, -256 + csrw 0xb03, t0 /* mhpmcounter3 */ + li t0, 1 + csrw 0xb83, t0 /* mhpmcounter3h */ + li t0, 1 + csrw 0x323, t0 /* mhpmevent3: cycles */ + .rept 512 + nop + .endr + li t0, 0x1234 + csrw 0xb03, t0 + csrr t0, 0xc83 + li t1, 2 + xor t0, t0, t1 + sltu t0, zero, t0 + slli t0, t0, 1 + or t4, t4, t0 + + /* + * Restart with a small low half so no carry can affect this check. + * Writing 2 to the running counter's high half must read back as 2. + */ + csrw 0x323, zero /* mhpmevent3 */ + li t0, 0x1234 + csrw 0xb03, t0 /* mhpmcounter3 */ + li t0, 1 + csrw 0xb83, t0 /* mhpmcounter3h */ + li t0, 1 + csrw 0x323, t0 /* mhpmevent3: cycles */ + li t0, 2 + csrw 0xb83, t0 + csrr t0, 0xc83 + li t1, 2 + xor t0, t0, t1 + sltu t0, zero, t0 + slli t0, t0, 2 + or t4, t4, t0 + + la a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sw t0, 0(a1) + sw t4, 4(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 8 diff --git a/tests/tcg/riscv32/sscofpmf-event-rv32.S b/tests/tcg/riscv32/ss= cofpmf-event-rv32.S new file mode 100644 index 0000000000000000000000000000000000000000..9a8c82cb42360ae2bd6f7d427ad= e6b2bad3b20ab --- /dev/null +++ b/tests/tcg/riscv32/sscofpmf-event-rv32.S @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Low-half selector writes preserve OF; high-half writes can clear it. */ + + .option norvc + .option norelax + + .macro check_selector_write low_csr, high_csr, first_failure + li t4, \first_failure + li t0, 8 /* mcountinhibit.HPM3 */ + csrs mcountinhibit, t0 + li t1, 1 << 29 /* SINH: still count in M-mode. */ + csrw 0x723, t1 /* mhpmevent3h: OF is clear. */ + li t1, 2 /* HW_INSTRUCTIONS */ + csrw 0x323, t1 /* mhpmevent3 */ + /* Set the counter to UINT64_MAX while inhibited. */ + li t2, -1 + csrw 0xb03, t2 /* mhpmcounter3 */ + csrw 0xb83, t2 /* mhpmcounter3h */ + li t3, 1 << 13 /* mip.LCOFIP */ + csrc mip, t3 + + /* + * With icount, this write accounts for the first increment after + * enabling HPM3. The counter wraps, setting OF. Updating bits 31:0 + * must preserve both that OF and the existing SINH in bits 63:32. + */ + csrc mcountinhibit, t0 + csrw \low_csr, t1 + csrr t2, 0x723 + li t1, 0xa0000000 /* OF | SINH */ + bne t1, t2, exit + csrs mcountinhibit, t0 + + li t4, \first_failure + 1 + csrr t2, mip + and t2, t2, t3 + beqz t2, exit + + /* Explicitly writing the high half must still be able to clear OF. */ + li t4, \first_failure + 2 + li t1, 1 << 29 /* Keep SINH, clear OF. */ + csrw \high_csr, t1 + csrr t2, 0x723 + bne t1, t2, exit + + /* The high-half write must not change the selected event. */ + li t4, \first_failure + 3 + csrr t2, 0x323 + li t1, 2 + bne t1, t2, exit + .endm + + .text + .global _start +_start: + /* Unexpected exceptions report the check in progress. */ + li t4, 9 + lla t0, exit + csrw mtvec, t0 + li t0, 1 << 28 /* menvcfgh.CDE */ + csrw 0x31a, t0 + li t0, 8 + csrw mcounteren, t0 /* Delegate counter 3. */ + li t0, 0x43 + csrw 0x150, t0 /* siselect: counter 3 */ + + /* Checks 1-4 use machine CSRs; checks 5-8 use delegated aliases. */ + check_selector_write 0x323, 0x723, 1 /* mhpmevent3, mhpmevent3h */ + check_selector_write 0x152, 0x156, 5 /* sireg2, sireg5 */ + li t4, 0 + + .balign 4 +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sw t0, 0(a1) + sw t4, 4(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 8 diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index 9f61da861a44881875457506c44bfc383560d1a9..5a94a90c40f838e4e78268f8ced= c480d5e2ff3bf 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -77,6 +77,10 @@ TESTS +=3D smcdeleg-minh run-smcdeleg-minh: smcdeleg-minh $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) =20 +TESTS +=3D pmu-cycle-controls +run-pmu-cycle-controls: pmu-cycle-controls + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) + EXTRA_RUNS +=3D run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/pmu-cycle-controls.S b/tests/tcg/riscv64/pmu= -cycle-controls.S new file mode 100644 index 0000000000000000000000000000000000000000..cda477f6699899e4fd625a301aa= 146fa9fdac344 --- /dev/null +++ b/tests/tcg/riscv64/pmu-cycle-controls.S @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Check cycle-counter behavior across filter and inhibit control writes. = */ + + .option norvc + .option norelax + + .text + .global _start +_start: + /* + * Failure bits: + * 0: enabling MINH discards the previously accumulated value + * 1: mcycle changes while M-mode is filtered + * 2: disabling MINH adds the filtered interval + * 3: mcycle does not resume after disabling MINH + */ + li t4, 0 + csrw mcountinhibit, zero + csrw 0x321, zero /* mcyclecfg */ + + /* Filtering M-mode must not discard the value accumulated so far. */ + csrr s0, mcycle + .rept 64 + nop + .endr + li t0, 1 + slli t0, t0, 62 /* MINH */ + csrw 0x321, t0 + csrr s1, mcycle + sltu t1, s0, s1 + xori t1, t1, 1 + or t4, t4, t1 + .rept 128 + nop + .endr + csrr s2, mcycle + xor t1, s1, s2 + sltu t1, zero, t1 + slli t1, t1, 1 + or t4, t4, t1 + + /* Removing the filter must not add the inhibited interval. */ + csrw 0x321, zero + csrr s3, mcycle + sub t1, s3, s2 + li t2, 64 + sltu t1, t1, t2 + xori t1, t1, 1 + slli t1, t1, 2 + or t4, t4, t1 + .rept 128 + nop + .endr + csrr t1, mcycle + sltu t1, s3, t1 + xori t1, t1, 1 + slli t1, t1, 3 + or t4, t4, t1 + + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd t4, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712758; cv=none; d=zohomail.com; s=zohoarc; b=m28k2Pv6X6WDdIrKzi6LME/CnmnO01MrDOj91tgYrlIYC4XjE3ZRJIXRdydXMpLF7c+74L9eI+AqvPxCm9eh1D51BdVcib5ZYjsiuY9BcZS4/nr+A7Kn2nHGXJB6e8LZxxSafWX+KsgWE5tNTjYiPZVu265ROwNGKkOpzmC2mEU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712758; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=m3wUYFgSVvglMEd51r/8qFafUu1CfPU9Xj4xomSW6JM=; b=DwOsyYFolftT7cVOPP3HsC6c6JPFFYQdngLRnS8yKEIqfUM+dYlWbB5aTrle7Cbqkb9AdLFXXPM7YhL5RqffLAf7SUwYqfdavP/K5ZbyT92qb4me2+MH7+2grTfhA+tOuihZHppU8ZsiECqNBDroz4VRWvO3j6SBivfNi8GL1SU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712758283717.4746196508964; Sun, 6 Sep 2026 09:39:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsW-0002ra-Fy; Sun, 06 Sep 2026 12:38:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsU-0002qM-Hp; Sun, 06 Sep 2026 12:37:58 -0400 Received: from [115.124.30.130] (helo=out30-130.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsP-00033q-3p; Sun, 06 Sep 2026 12:37:58 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIJQ_1788712655 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:35 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712656; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=m3wUYFgSVvglMEd51r/8qFafUu1CfPU9Xj4xomSW6JM=; b=THeo2qF/w2N+8i/KqeSiYjIM6FhlNPBR5RPC+tr+P2FXlEURxcGLPK6tPcnDcoC4HeOYf3H5+OkvCeR4gQI9jK5SQlnm4wNEJTRXl6oVTCX/JH55sPdeGc/ZBSuEDmhTrh36BVJ18KuSjsnfDuA0tr9XgpeyZWTVlJz0stHvxTw= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R111e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037026112; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIJQ_1788712655; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:24 +0800 Subject: [PATCH 08/14] target/riscv: Require Sscofpmf for non-fixed event overflow MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-8-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=5025; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=SWLDZaobL2cuTdxkuNJsKTxxt0qUm6tEdzPQvavnhhQ=; b=rO4zGoUZJA7WCO8O0biP8tGvwHXuMqBm2xYWjc1idI9fCcyQTC6xmPeglGP5WO/RT4a5Uh0bG aA6h5/X7yTjDIHBmKK68EfE8QU04UuSkVySXdtjClnqU+YLOhMLorFJ X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.130 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.130; envelope-from=lyndra@linux.alibaba.com; helo=out30-130.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712760213158500 riscv_pmu_incr_ctr() sets OF and LCOFIP on wrap even when Sscofpmf is disabled. Use the shared overflow helper to require Sscofpmf and suppress notifications while OF is set without stopping the counter. Test DTLB overflow with Sscofpmf enabled and disabled, including notification suppression and continued counting. Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support") Signed-off-by: TANG Tiancheng --- target/riscv/tcg/pmu.c | 6 +- tests/tcg/riscv64/Makefile.softmmu-target | 10 +++ tests/tcg/riscv64/sscofpmf-event-overflow.S | 103 ++++++++++++++++++++++++= ++++ 3 files changed, 114 insertions(+), 5 deletions(-) diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 16942e53489cd5a2d2dd055fdffef07d04d59465..2f600c5a0fc2d7ba380ef34f89a= f6366e3e27884 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -448,11 +448,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_e= vent_idx event_idx) counter =3D &env->pmu_ctrs[ctr_idx]; if (counter->mhpmcounter_val =3D=3D max_val) { counter->mhpmcounter_val =3D 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |=3D MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } + riscv_pmu_set_overflow(env, ctr_idx); } else { counter->mhpmcounter_val++; } diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index 5a94a90c40f838e4e78268f8cedc480d5e2ff3bf..b100f7a9ddf8e31fb104aa834b2= 8aa64fc31f50e 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -69,6 +69,16 @@ TESTS +=3D sscofpmf-overflow run-sscofpmf-overflow: sscofpmf-overflow $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) =20 +sscofpmf-event-overflow-off: sscofpmf-event-overflow.S $(LINK_SCRIPT) + $(CC) $(CFLAGS) -DEXPECT_SSCOFPMF=3D0 $< -Wa,--noexecstack -c -o $@.o + $(LD) $(LDFLAGS) $@.o -o $@ + +TESTS +=3D sscofpmf-event-overflow sscofpmf-event-overflow-off +run-sscofpmf-event-overflow: sscofpmf-event-overflow + $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<) +run-sscofpmf-event-overflow-off: sscofpmf-event-overflow-off + $(call run-test, $<, $(QEMU) -cpu max$(COMMA)sscofpmf=3Dfalse $(QEMU_OPTS= )$<) + TESTS +=3D sscofpmf-cycle-overflow run-sscofpmf-cycle-overflow: sscofpmf-cycle-overflow $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D3 $(QEMU_OPTS)$<) diff --git a/tests/tcg/riscv64/sscofpmf-event-overflow.S b/tests/tcg/riscv6= 4/sscofpmf-event-overflow.S new file mode 100644 index 0000000000000000000000000000000000000000..5bbcb060ae87124349151a14c6d= b815755c6e58d --- /dev/null +++ b/tests/tcg/riscv64/sscofpmf-event-overflow.S @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Non-fixed event overflow with and without Sscofpmf. */ + +#ifndef EXPECT_SSCOFPMF +#define EXPECT_SSCOFPMF 1 +#endif + + .option norvc + .option norelax + + .text + .global _start +_start: + /* Unexpected exceptions report the current check number. */ + li t4, 1 + lla t0, exit + csrw mtvec, t0 + csrw mie, zero + csrw mip, zero + csrw mcountinhibit, zero + csrw 0x323, zero /* mhpmevent3 */ + li t0, -1 + csrw 0xb03, t0 /* mhpmcounter3 */ + li t0, 0x10019 /* DTLB read miss */ + csrw 0x323, t0 + + /* One load after flushing the TLB must wrap the counter to zero. */ + sfence.vma + lla t0, first_page + lw t1, 0(t0) + csrr t0, 0xb03 + bnez t0, exit + + /* Only Sscofpmf turns that wrap into OF and LCOFIP. */ + li t4, 2 + csrr t0, 0x323 + srli t0, t0, 63 + li t1, EXPECT_SSCOFPMF + bne t0, t1, exit + li t4, 3 + csrr t0, mip + srli t0, t0, 13 + andi t0, t0, 1 + bne t0, t1, exit + + /* Clearing LCOFIP alone must not re-enable overflow notification. */ + li t0, 1 << 13 + csrc mip, t0 + li t0, -1 + csrw 0xb03, t0 + sfence.vma + lla t0, second_page + lw t1, 0(t0) + li t4, 4 + csrr t0, 0xb03 + bnez t0, exit + li t4, 5 + csrr t0, 0x323 + srli t0, t0, 63 + li t1, EXPECT_SSCOFPMF + bne t0, t1, exit + li t4, 6 + csrr t0, mip + li t1, 1 << 13 + and t0, t0, t1 + bnez t0, exit + + /* Overflow notification must not stop event counting. */ + sfence.vma + lla t0, third_page + lw t1, 0(t0) + li t4, 7 + csrr t0, 0xb03 + li t1, 1 + bne t0, t1, exit + li t4, 0 + +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd t4, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 4096 +first_page: + .word 0 + .balign 4096 +second_page: + .word 0 + .balign 4096 +third_page: + .word 0 + .balign 16 +semiargs: + .space 16 --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712849; cv=none; d=zohomail.com; s=zohoarc; b=ePE1BFAJCik1loKfV3Sgi/X/UE/WYBl0rPzp5yFrKaXa5rIhzisSH3tTfiagDZ+0fU4aDmkMDkMcHcnewa7cjl43+sfgKzSVcTAj9IiD9S9abl/WmgV2sZ1/xkVKbqfks7Bcdx4tvkzy8B8YgjZfvnjXpQ+/2IiCgnWtf15KAgE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712849; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=q/GwFzMFGFkF35V6csq21/leImRbvW7pVYqM4X6u5Uk=; b=BtypQlXSBlhUwP1kQicLOOrJuybZBfPac0nfZpTkPFu9xqErl5KtFYnEYPabZJdOioaWWODPeKzhMkeSwmVUNquGS8jvDc4lXn/4dYExasTrPd2hXikFpyLKx0W7LNMzgAO4eo4hILtJq9wisKhI81/zb4uKfCem1oUWt4TcjOY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712849434154.54242101521947; Sun, 6 Sep 2026 09:40:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsX-0002t6-7K; Sun, 06 Sep 2026 12:38:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsV-0002qs-5E; Sun, 06 Sep 2026 12:37:59 -0400 Received: from [115.124.30.131] (helo=out30-131.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsO-00034C-7f; Sun, 06 Sep 2026 12:37:58 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIJk_1788712655 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:36 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712657; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=q/GwFzMFGFkF35V6csq21/leImRbvW7pVYqM4X6u5Uk=; b=FYCDbWU5Sfg7e935JrtKdjLecwjy4XtqxIixKQWV+9rxI4N392FZZykNucC1SGLtHhM5JHW4E+J/nCNxp7YekKjWdUX5lsQxycsn7R5kP/hlgGpFJXLQTvgQcPQmoGLOpixFct5LJLzfD38qkqg4g8FZrf6yxfC2yYRSoEu3fVk= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R151e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033032089153; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIJk_1788712655; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:25 +0800 Subject: [PATCH 09/14] target/riscv: Rebuild fixed-event PMU overflow deadlines MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-9-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=18550; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=HLjpg0UUYTyWedU3pFOTKs920Z10qHrMp5Yns3RRc/0=; b=D9ueqn0zI7oIGXfxj8BAqfOZNEuEYercmaeN6Xj6BEeYr6IXVNZHRNJQAvrzh7u5gSW3lEKHy rn9n0F7P/dVC3YYwAMqxpkfVaOA1VvC5iLK+ZSceshqCH2Jq6RuwL/6 X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.131 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.131; envelope-from=lyndra@linux.alibaba.com; helo=out30-131.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.01, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712850389158500 timer_mod_anticipate_ns() cannot postpone the shared overflow timer when a counter is stopped or reconfigured. Recompute the earliest deadline from all eligible counters after PMU changes and timer expiry. Check for an actual counter wrap before setting OF or LCOFIP. Keep counter arithmetic in source units. For timer scheduling, convert only raw icount instruction counts to nanoseconds. Check how many fit within INT64_MAX - now nanoseconds before conversion, using INT64_MAX as the deadline if the count is larger. Recompute the remaining count at expiry instead of keeping irq_overflow_left. Icount time warp can expire the timer without executing instructions. If the instruction source has not advanced, defer its next deadline until execution resumes to avoid an endless warp/rearm loop. Extend the cycle-control test to cover selector writes while CY is set and resuming mcycle after CY is cleared. Signed-off-by: TANG Tiancheng --- target/riscv/cpu.h | 4 +- target/riscv/tcg/cpu_helper.c | 2 + target/riscv/tcg/pmu.c | 239 +++++++++++++----------------= ---- target/riscv/tcg/pmu.h | 3 +- target/riscv/tcg/tcg-cpu.c | 10 ++ tests/tcg/riscv64/pmu-cycle-controls.S | 27 ++++ 6 files changed, 139 insertions(+), 146 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f7b1bfc9cf5069125bc22dc2674d8e67431c5970..17b9929785f668487d2ec851b73= 6d588e025fd91 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -236,8 +236,6 @@ typedef struct PMUCTRState { uint64_t mhpmcounter_val; /* Snapshot value of a counter */ uint64_t mhpmcounter_prev; - /* Value beyond INT64_MAX before overflow interrupt trigger */ - uint64_t irq_overflow_left; } PMUCTRState; =20 typedef enum { @@ -583,6 +581,8 @@ struct ArchCPU { RISCVSATPModes satp_modes; =20 QEMUTimer *pmu_timer; + uint64_t pmu_timer_instret_snapshot; + bool pmu_timer_stalled; /* A bitmask of Available programmable counters */ uint32_t pmu_avail_ctrs; /* Mapping of events to counters */ diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c index 07d92226527d85da93b8810e526d044e64fa4e3d..89751cdbf29f5bbd46d0d6b8c9d= 23eac5e3accac 100644 --- a/target/riscv/tcg/cpu_helper.c +++ b/target/riscv/tcg/cpu_helper.c @@ -889,6 +889,8 @@ void riscv_cpu_set_mode(CPURISCVState *env, privilege_m= ode_t newpriv, riscv_cpu_update_mip(env, 0, 0); } } + + riscv_pmu_rebuild_timer(env); } =20 /* diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 2f600c5a0fc2d7ba380ef34f89af6366e3e27884..f88f6ae671d877ed874d22c9d4b= 840edb6f433a5 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -26,13 +26,6 @@ #include "system/device_tree.h" #include "system/cpu-timers.h" =20 -/* - * cpu_get_ticks() does not expose the host tick frequency. Use a 1 GHz - * approximation only when scheduling non-icount overflow checks; fixed - * counter values remain in host-tick units. - */ -#define RISCV_PMU_HOST_TICK_HZ_ASSUMED 1000000000 - static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx) { if (ctr_idx < 3 || ctr_idx >=3D RV_MAX_MHPMCOUNTERS || @@ -324,7 +317,6 @@ void riscv_pmu_write_event(CPURISCVState *env, uint32_t= ctr_idx, uint64_t value, uint64_t wr_mask) { RISCVPMUFixedSnapshot snapshot; - PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; =20 riscv_pmu_take_fixed_snapshot(env, &snapshot); if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { @@ -337,10 +329,7 @@ void riscv_pmu_write_event(CPURISCVState *env, uint32_= t ctr_idx, if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { riscv_pmu_set_fixed_baseline(env, ctr_idx, &snapshot); } - - if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); - } + riscv_pmu_rebuild_timer(env); } =20 void riscv_pmu_write_counter(CPURISCVState *env, uint32_t ctr_idx, @@ -349,23 +338,19 @@ void riscv_pmu_write_counter(CPURISCVState *env, uint= 32_t ctr_idx, RISCVPMUFixedSnapshot snapshot; PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; bool rv32 =3D xl =3D=3D MXL_RV32; - bool running; int start =3D upper_half ? 32 : 0; int length =3D rv32 ? 32 : 64; =20 g_assert(rv32 || !upper_half); =20 riscv_pmu_take_fixed_snapshot(env, &snapshot); - running =3D riscv_pmu_fixed_ctr_running(env, ctr_idx); - if (running) { + if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); } counter->mhpmcounter_val =3D deposit64(counter->mhpmcounter_val, start, length, value); /* mhpmcounter_prev tracks the source, not the written counter value. = */ - if (running && ctr_idx > 2) { - riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); - } + riscv_pmu_rebuild_timer(env); } =20 void riscv_pmu_write_inhibit(CPURISCVState *env, uint32_t value) @@ -396,11 +381,8 @@ void riscv_pmu_write_inhibit(CPURISCVState *env, uint3= 2_t value) if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { riscv_pmu_set_fixed_baseline(env, ctr_idx, &snapshot); } - if (ctr_idx > 2 && riscv_pmu_fixed_ctr_running(env, ctr_idx)) { - riscv_pmu_setup_timer(env, env->pmu_ctrs[ctr_idx].mhpmcounter_= val, - ctr_idx); - } } + riscv_pmu_rebuild_timer(env); } =20 void riscv_pmu_decr_instret(CPURISCVState *env) @@ -512,17 +494,6 @@ static bool riscv_pmu_event_supported(uint32_t event_i= dx) } } =20 -static int64_t pmu_ticks_to_ns(CPURISCVState *env, uint32_t ctr_idx, - int64_t value) -{ - if (icount_enabled() && - riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - return icount_to_ns(value); - } - - return (NANOSECONDS_PER_SECOND / RISCV_PMU_HOST_TICK_HZ_ASSUMED) * val= ue; -} - void riscv_pmu_rebuild_event_map(CPURISCVState *env) { uint32_t ctr_idx, ctr_mask, event_idx; @@ -551,148 +522,132 @@ void riscv_pmu_rebuild_event_map(CPURISCVState *env) } } =20 -static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_= idx) -{ - if (!get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |=3D MHPMEVENT_BIT_OF; - return true; - } else { - return false; - } -} - -static void pmu_timer_trigger_irq_counter(RISCVCPU *cpu, uint32_t ctr_idx) +static int64_t riscv_pmu_overflow_delay_ns(CPURISCVState *env, + uint32_t ctr_idx, + uint64_t value, int64_t now) { - CPURISCVState *env =3D &cpu->env; - PMUCTRState *counter; - int64_t irq_trigger_at; - uint64_t curr_ctr_val, curr_ctrh_val; - uint64_t ctr_val; + uint64_t remaining; + uint64_t max_delay =3D INT64_MAX - now; =20 - if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) { - return; + if (!value) { + /* A complete 64-bit wrap is beyond the signed timer horizon. */ + return max_delay; } + remaining =3D -value; =20 - /* Generate interrupt only if OF bit is clear */ - if (get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { - return; - } - - counter =3D &env->pmu_ctrs[ctr_idx]; - if (counter->irq_overflow_left > 0) { - irq_trigger_at =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - counter->irq_overflow_left; - timer_mod_anticipate_ns(cpu->pmu_timer, irq_trigger_at); - counter->irq_overflow_left =3D 0; - return; - } + if (icount_enabled() && + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + /* Use one adaptive-shift sample for both bounds and conversion. */ + uint64_t ns_per_tick =3D icount_to_ns(1); + uint64_t max_ticks =3D max_delay / ns_per_tick; =20 - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx, - riscv_cpu_mxl(env)); - ctr_val =3D counter->mhpmcounter_val; - if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_= idx, - riscv_cpu_mxl(env)); - curr_ctr_val =3D curr_ctr_val | (curr_ctrh_val << 32); + if (remaining > max_ticks) { + return max_delay; + } + return remaining * ns_per_tick; } =20 /* - * We can not accommodate for inhibited modes when setting up timer. C= heck - * if the counter has actually overflowed or not by comparing current - * counter value (accommodated for inhibited modes) with software writ= ten - * counter value. + * Cycle under icount is already virtual ns. Non-icount fixed events + * retain QEMU's existing one-host-tick-per-ns deadline approximation. */ - if (curr_ctr_val >=3D ctr_val) { - riscv_pmu_setup_timer(env, curr_ctr_val, ctr_idx); - return; - } - - if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) { - if (pmu_hpmevent_set_of_if_clear(env, ctr_idx)) { - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } - } + return MIN(remaining, max_delay); } =20 -static void pmu_timer_trigger_irq(RISCVCPU *cpu, - enum riscv_pmu_event_idx evt_idx) +static void riscv_pmu_rebuild_timer_internal(CPURISCVState *env, + bool timer_expired) { + RISCVCPU *cpu =3D env_archcpu(env); + RISCVPMUFixedSnapshot snapshot; uint32_t ctr_idx; uint32_t ctr_mask; + int64_t deadline =3D INT64_MAX; + int64_t now; + bool have_deadline =3D false; + bool timer_horizon_exhausted; + bool stalled =3D false; =20 - if (evt_idx !=3D RISCV_PMU_EVENT_HW_CPU_CYCLES && - evt_idx !=3D RISCV_PMU_EVENT_HW_INSTRUCTIONS) { + if (!cpu->pmu_timer) { return; } =20 - ctr_mask =3D riscv_pmu_event_counter_mask(cpu, evt_idx); + riscv_pmu_take_fixed_snapshot(env, &snapshot); + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + /* No future absolute timer deadline is representable at this point. */ + timer_horizon_exhausted =3D now =3D=3D INT64_MAX; + + ctr_mask =3D riscv_pmu_event_counter_mask( + cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES); + ctr_mask |=3D riscv_pmu_event_counter_mask( + cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS); =20 while (ctr_mask) { + PMUCTRState *counter; + int64_t candidate; + ctr_idx =3D ctz32(ctr_mask); ctr_mask &=3D ~BIT(ctr_idx); - pmu_timer_trigger_irq_counter(cpu, ctr_idx); - } -} + counter =3D &env->pmu_ctrs[ctr_idx]; =20 -/* Timer callback for instret and cycle counter overflow */ -void riscv_pmu_timer_cb(void *priv) -{ - RISCVCPU *cpu =3D priv; + if (!riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + continue; + } + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, &snapshot); + if ((env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF) || + riscv_pmu_counter_filtered(env, + env->mhpmevent_val[ctr_idx])) { + continue; + } =20 - /* Timer event was triggered only for these events */ - pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES); - pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS); -} + /* + * Settle current deltas and overflows even when no future deadlin= e is + * representable. + */ + if (timer_horizon_exhausted) { + continue; + } =20 -int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr= _idx) -{ - uint64_t overflow_delta, overflow_at, curr_ns; - int64_t overflow_ns, overflow_left =3D 0; - RISCVCPU *cpu =3D env_archcpu(env); - PMUCTRState *counter =3D &env->pmu_ctrs[ctr_idx]; + if (timer_expired && icount_enabled() && + riscv_pmu_ctr_monitor_instructions(env, ctr_idx) && + snapshot.instret =3D=3D cpu->pmu_timer_instret_snapshot) { + /* + * Icount can warp QEMU_CLOCK_VIRTUAL to this deadline without + * executing an instruction. Re-arming the unchanged instructi= on + * distance would create a warp/rearm loop; defer it until this + * CPU enters execution again. + */ + stalled =3D true; + continue; + } =20 - /* No need to setup a timer if LCOFI is disabled when OF is set */ - if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf || - get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { - return -1; + candidate =3D now + riscv_pmu_overflow_delay_ns( + env, ctr_idx, counter->mhpmcounter_val, now); + if (!have_deadline || candidate < deadline) { + deadline =3D candidate; + have_deadline =3D true; + } } =20 - if (value) { - overflow_delta =3D UINT64_MAX - value + 1; + cpu->pmu_timer_instret_snapshot =3D snapshot.instret; + cpu->pmu_timer_stalled =3D stalled; + if (have_deadline) { + timer_mod_ns(cpu->pmu_timer, deadline); } else { - overflow_delta =3D UINT64_MAX; - } - - /* - * QEMU supports only int64_t timers while RISC-V counters are uint64_= t. - * Compute the leftover and save it so that it can be reprogrammed aga= in - * when timer expires. - */ - if (overflow_delta > INT64_MAX) { - overflow_left =3D overflow_delta - INT64_MAX; + timer_del(cpu->pmu_timer); } +} =20 - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - overflow_ns =3D pmu_ticks_to_ns(env, ctr_idx, - (int64_t)overflow_delta); - overflow_left =3D pmu_ticks_to_ns(env, ctr_idx, overflow_left); - } else { - return -1; - } - curr_ns =3D (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - overflow_at =3D curr_ns + overflow_ns; - if (overflow_at <=3D curr_ns) - overflow_at =3D UINT64_MAX; +void riscv_pmu_rebuild_timer(CPURISCVState *env) +{ + riscv_pmu_rebuild_timer_internal(env, false); +} =20 - if (overflow_at > INT64_MAX) { - overflow_left +=3D overflow_at - INT64_MAX; - counter->irq_overflow_left =3D overflow_left; - overflow_at =3D INT64_MAX; - } - timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); +/* Timer callback for instret and cycle counter overflow */ +void riscv_pmu_timer_cb(void *priv) +{ + RISCVCPU *cpu =3D priv; =20 - return 0; + riscv_pmu_rebuild_timer_internal(&cpu->env, true); } =20 =20 diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index 1494fbc21f53137a90c1338f6ca8e3c3e750276a..d9238ae680f5e67031511db4f9a= fc2884212c5c2 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -44,12 +44,11 @@ void riscv_pmu_write_counter(CPURISCVState *env, uint32= _t ctr_idx, target_ulong value, bool upper_half, RISCVMXL= xl); void riscv_pmu_write_inhibit(CPURISCVState *env, uint32_t value); void riscv_pmu_timer_cb(void *priv); +void riscv_pmu_rebuild_timer(CPURISCVState *env); void riscv_pmu_init(RISCVCPU *cpu, Error **errp); void riscv_pmu_rebuild_event_map(CPURISCVState *env); 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= ); -int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, - uint32_t ctr_idx); void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, privilege_mode_t newp= riv, bool new_virt); void riscv_pmu_decr_instret(CPURISCVState *env); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index b68160af8307c1e46d3f200c5313823d240eb7b3..cdcb94f3bcaf0526512f1994e9f= 7127209e1adcb 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -247,6 +247,15 @@ static void riscv_restore_state_to_opc(CPUState *cs, } =20 #ifndef CONFIG_USER_ONLY +static void riscv_cpu_exec_enter(CPUState *cs) +{ + RISCVCPU *cpu =3D RISCV_CPU(cs); + + if (cpu->pmu_timer_stalled) { + riscv_pmu_rebuild_timer(&cpu->env); + } +} + static vaddr riscv_pointer_wrap(CPUState *cs, int mmu_idx, vaddr result, vaddr base) { @@ -283,6 +292,7 @@ const TCGCPUOps riscv_tcg_ops =3D { .mmu_index =3D riscv_cpu_mmu_index, =20 #ifndef CONFIG_USER_ONLY + .cpu_exec_enter =3D riscv_cpu_exec_enter, .tlb_fill =3D riscv_cpu_tlb_fill, .pointer_wrap =3D riscv_pointer_wrap, .cpu_exec_interrupt =3D riscv_cpu_exec_interrupt, diff --git a/tests/tcg/riscv64/pmu-cycle-controls.S b/tests/tcg/riscv64/pmu= -cycle-controls.S index cda477f6699899e4fd625a301aa146fa9fdac344..9de8d128ee2a99e1183c91c5bd5= 55c49e67b1f48 100644 --- a/tests/tcg/riscv64/pmu-cycle-controls.S +++ b/tests/tcg/riscv64/pmu-cycle-controls.S @@ -14,6 +14,8 @@ _start: * 1: mcycle changes while M-mode is filtered * 2: disabling MINH adds the filtered interval * 3: mcycle does not resume after disabling MINH + * 4: writing mhpmevent3 advances mcycle while CY is set + * 5: mcycle does not resume after clearing CY */ li t4, 0 csrw mcountinhibit, zero @@ -58,6 +60,31 @@ _start: slli t1, t1, 3 or t4, t4, t1 =20 + /* Changing HPM3's event must leave mcycle stopped while CY is set. */ + li t0, 1 /* mcountinhibit.CY */ + csrw mcountinhibit, t0 + csrr s4, mcycle + .rept 128 + nop + .endr + li t0, 1 /* HW_CPU_CYCLES */ + csrw 0x323, t0 /* mhpmevent3; rebuilds PMU timer */ + csrr s5, mcycle + xor t1, s4, s5 + sltu t1, zero, t1 + slli t1, t1, 4 + or t4, t4, t1 + csrw mcountinhibit, zero + csrr s6, mcycle + .rept 128 + nop + .endr + csrr t1, mcycle + sltu t1, s6, t1 + xori t1, t1, 1 + slli t1, t1, 5 + or t4, t4, t1 + csrw 0x323, zero lla a1, semiargs li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ sd t0, 0(a1) --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712831; cv=none; d=zohomail.com; s=zohoarc; b=KuLyAWx38k6l1GvKUJRWFirO8yCUGb+aRZe3K59O17b/wfzCch/rqEH+Aqf2CcNJvatwk/xhP/Je5zT9Zpq+pHXQk2F2WeLMlfAgJyDYbZG9Cidaq34zLpDZhvZJIHrsV7WGtOmsCdIbVUok0ng9rHYymoBwZaxHBIQUUtpIPMA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712831; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=aLfKMHQtuKWxCmqa7+mcnKEZ5ASR61Qqk63gRm09wM0=; b=DRf180DbUn9jG9bZjdAVI89n+lWat747cUS9E3imrr3IFAeCSSp8TzMkvzDe9ggvMbXoCxGp5ja8yMkqw20uPuZDNmn6GgvSD4wSGtO06DZ2hLFvxzxcpwzxHEKZ5dv+/GbPIrZp09LbPdWiBxVQ5shWLT6E0CLMdNNsZJy2LaA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17887128312011006.5503297327351; Sun, 6 Sep 2026 09:40:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsb-0002xr-6a; Sun, 06 Sep 2026 12:38:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsZ-0002vp-5x; Sun, 06 Sep 2026 12:38:03 -0400 Received: from [115.124.30.113] (helo=out30-113.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00034Y-A2; Sun, 06 Sep 2026 12:38:02 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIK2_1788712656 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:37 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712659; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=aLfKMHQtuKWxCmqa7+mcnKEZ5ASR61Qqk63gRm09wM0=; b=egotRxl7J4cRoT31nOtDWG9LGRDTeUNY2fGn8MZlDBe4B3WHVwBoZy2bjUQmZTR3VfAiGMxpaNrYaxtQBxh3+Cwovh+ar2aLVdwgyFTSLRoHCdb97EqynzUiAbHqRLqCvSq8blLYRYVK2gPhnuEt41s7Voipoibwnms+hNJWYo0= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R731e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033045098064; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIK2_1788712656; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:26 +0800 Subject: [PATCH 10/14] target/riscv: Apply minstret exception accounting to HPM counters MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-10-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=6668; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=PVESGujVoC3fFdIiQ566C1f02Z0w7Ugn57WpDN94i14=; b=Sw9IzH0K2G2Evb7uTdekQmK7J1pdTQgGKIRxJ+hJZ0MRXe0xtDU0izojqjFqydNHOsSEj5xyt TXS2KRVOi6JAy151FA7TQak01Z449TPf/5nF+C1FVyIToz+Aye1+E76 X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.113 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.113; envelope-from=lyndra@linux.alibaba.com; helo=out30-113.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712832467154100 With icount, helper_raise_exception() excludes faulting instructions from minstret but not HPM counters selecting HW_INSTRUCTIONS. Adjust the baseline of every running instruction counter that counts the current privilege mode. Do not read icount here: the helper can run inside a TB. Keep the existing timer, since excluding an instruction can only postpone overflow and expiry checks for an actual wrap. Extend the ECALL regression to compare both counters and add an LPAD fault test covering an exception inside a multi-instruction TB. Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support") Signed-off-by: TANG Tiancheng --- target/riscv/tcg/pmu.c | 35 ++++++++++++---- tests/tcg/riscv64/Makefile.softmmu-target | 6 ++- tests/tcg/riscv64/pmu-lpad.S | 69 +++++++++++++++++++++++++++= ++++ tests/tcg/riscv64/test-minstret-ecall.S | 26 ++++++++++++ 4 files changed, 128 insertions(+), 8 deletions(-) diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index f88f6ae671d877ed874d22c9d4b840edb6f433a5..08298010b6d06f5792fa14ff81f= e2f7a28c6476f 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -387,18 +387,39 @@ void riscv_pmu_write_inhibit(CPURISCVState *env, uint= 32_t value) =20 void riscv_pmu_decr_instret(CPURISCVState *env) { - if (!icount_enabled() || - (env->mcountinhibit & COUNTEREN_IR) || - riscv_pmu_counter_filtered(env, env->minstretcfg)) { + RISCVCPU *cpu =3D env_archcpu(env); + uint32_t ctr_mask; + + if (!icount_enabled()) { return; } =20 /* - * minstret is derived from icount, which includes the current - * instruction. Move the baseline forward to exclude an instruction - * that raises an exception and therefore does not retire. + * Fixed instruction events are derived from icount, which includes the + * current instruction. Move the baseline of each running + * instruction-source counter that counts the current privilege mode to + * exclude an instruction that raises an exception and does not retire. + * + * Do not read icount here: this helper can run in the middle of a TB. + * Excluding an instruction only postpones overflow, so keep the curre= nt + * timer deadline. The expiry handler checks for an actual counter wra= p. */ - env->pmu_ctrs[2].mhpmcounter_prev++; + ctr_mask =3D COUNTEREN_IR | + riscv_pmu_event_counter_mask( + cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS); + while (ctr_mask) { + uint32_t ctr_idx =3D ctz32(ctr_mask); + uint64_t cfg =3D ctr_idx =3D=3D 2 ? env->minstretcfg : + env->mhpmevent_val[ctr_idx]; + + ctr_mask &=3D ~BIT(ctr_idx); + if (!riscv_pmu_fixed_ctr_running(env, ctr_idx) || + riscv_pmu_counter_filtered(env, cfg)) { + continue; + } + + env->pmu_ctrs[ctr_idx].mhpmcounter_prev++; + } } =20 int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index b100f7a9ddf8e31fb104aa834b28aa64fc31f50e..deb44ece5feeb13756f9f3abcd3= 8258d75bd9ba1 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -24,10 +24,14 @@ EXTRA_RUNS +=3D run-test-mepc-masking run-test-mepc-masking: test-mepc-masking $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) =20 -EXTRA_RUNS +=3D run-test-minstret-ecall +TESTS +=3D test-minstret-ecall run-test-minstret-ecall: test-minstret-ecall $(call run-test, $<, $(QEMU) -icount shift=3D1 $(QEMU_OPTS)$<) =20 +TESTS +=3D pmu-lpad +run-pmu-lpad: pmu-lpad + $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) + RV32_CFLAGS =3D -march=3Drv32im_zicsr -mabi=3Dilp32 CLEANFILES +=3D test-mcycle-rv32 =20 diff --git a/tests/tcg/riscv64/pmu-lpad.S b/tests/tcg/riscv64/pmu-lpad.S new file mode 100644 index 0000000000000000000000000000000000000000..11a900fef2850b6c478126f123b= d036d4a258977 --- /dev/null +++ b/tests/tcg/riscv64/pmu-lpad.S @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* An LPAD fault must be deliverable with HPM instruction counting enabled= . */ + + .option norvc + .option norelax + + .text + .global _start +_start: + lla t0, trap + csrw mtvec, t0 + li t0, 2 /* HW_INSTRUCTIONS */ + csrw mhpmevent3, t0 + li t0, 1 << 10 /* mseccfg.MLPE */ + csrs 0x747, t0 + + /* x7[31:12] =3D 0 does not match the nonzero LPAD label. */ + li t2, 0 + lla a0, target + jalr ra, a0, 0 + j fail + + .balign 4 +target: + .word 0x00001017 /* lpad 1 */ + /* + * Keep the LPAD check inside a multi-instruction TB. Its exception + * helper must not read icount before leaving generated code. + */ + .rept 16 + nop + .endr + j fail + +trap: + csrr t0, mcause + li t1, 18 /* Software-check exception */ + bne t0, t1, fail + csrr t0, mtval + li t1, 2 /* Landing-pad fault */ + bne t0, t1, fail + csrr t0, mepc + lla t1, target + bne t0, t1, fail + li a0, 0 + j exit + +fail: + li a0, 1 + +exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 diff --git a/tests/tcg/riscv64/test-minstret-ecall.S b/tests/tcg/riscv64/te= st-minstret-ecall.S index ab268f7f22985820f19bde353215385608643f3a..b1857543d488df984b923ad1c13= 5edb35cb948c7 100644 --- a/tests/tcg/riscv64/test-minstret-ecall.S +++ b/tests/tcg/riscv64/test-minstret-ecall.S @@ -18,11 +18,37 @@ _start: li t1, 1 bne t0, t1, fail =20 + /* + * minstret and a counter selecting HW_INSTRUCTIONS must both exclude + * ECALL, so they must contain the same number of retired instructions. + */ + li t0, 12 /* mcountinhibit.IR | mcountinhibit.HPM3 */ + csrs mcountinhibit, t0 + csrw minstret, zero + csrw mhpmcounter3, zero + li t0, 2 /* RISCV_PMU_EVENT_HW_INSTRUCTIONS */ + csrw mhpmevent3, t0 + lla t0, trap_hpm + csrw mtvec, t0 + li t0, 12 + csrc mcountinhibit, t0 + ecall + bne s3, s4, fail + li a0, 0 j _exit =20 trap: csrr s1, minstret + j trap_check + +trap_hpm: + li t0, 12 + csrs mcountinhibit, t0 + csrr s3, minstret + csrr s4, mhpmcounter3 + +trap_check: csrr t0, mcause li t1, 11 /* Environment call from M-mode */ bne t0, t1, fail --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712792; cv=none; d=zohomail.com; s=zohoarc; b=L8g/G/LKnMefMarIQjj9iaroK2a4l0EFCVdRGCrTwtLgReqoJesQdGMdVkah2dJINycguxy2iOajG2rDgrcH4nmASPE1QfQ1ya2wogB/AzwnTYmmUoFRmYzXZ3V5E0M4Ph3JyAHDoycJUHSovzHtOBqXkhu7ZjzqkYp8uelEzpY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712792; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ksc6jpcXXgLeXQNaH+DYLymXmDnFTGRTvna+17U5yjo=; b=ISWClkVhGI82Kwcel+2ek4nPQbtROnAn2N6aOzPy6dG//C/9AZf7pmvolYlATQDzyQRdZHXtPxaWguzWHJ+Fkk3ljemEymdPH188rkU33d0vowLAKolPAxqpaOnJCu+ewOXgfC5x4g6sKr7DZtcSB0Ba5ytRIAeJdeQOwAaWXW0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17887127920721001.9798929545623; Sun, 6 Sep 2026 09:39:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsc-0002yo-Fr; Sun, 06 Sep 2026 12:38:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsZ-0002x5-VZ; Sun, 06 Sep 2026 12:38:04 -0400 Received: from [115.124.30.101] (helo=out30-101.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00034R-Qr; Sun, 06 Sep 2026 12:38:03 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIKQ_1788712657 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:37 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712658; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=ksc6jpcXXgLeXQNaH+DYLymXmDnFTGRTvna+17U5yjo=; b=JGmcCm96QddXbpTI6znnrKMNOy0UZkc4QU7pKa4v5A9b0EjSSFGNGITqBf7yL7xitbz4k4YeRDi05gZAYNjeHb2oxfwCSizQvDrUorLb9lJY1NxxMSnjje8u5pzpKn0MsSnpyZsErb8dpKCLqg0vIh25EpKKNz6nM9t3FXnQztg= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R171e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037033178; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIKQ_1788712657; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:27 +0800 Subject: [PATCH 11/14] target/riscv: Process PMU timer expiry on the owner vCPU MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-11-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=2433; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=xGqFDfh9IR3JQbU7GQ/PgD80X6pKA6c3w5l7P5xkpoI=; b=DoM+dtGJuWp0nPnNOEJe1rcDJvDncluVdFxmKgN0heBacWbKCX2FX3WrDjdeCZ1K8ncKKgvyg 1pYRk4rnYUlDBPjaPlOLiPHAyEdXDXYXgbvr8CSKn/lYzwMppLxoXyR X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.101 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.101; envelope-from=lyndra@linux.alibaba.com; helo=out30-101.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712794114158500 The PMU timer callback can race MTTCG execution and CSR writes while reading the event map and updating counters, OF and MIP. Queue counter checks on the owning vCPU. The callback atomically sets pmu_timer_work_pending and queues work only if it was previously false. The vCPU clears the flag before checking counters and rebuilding the timer. Earlier expiries are covered by that check; the first later expiry queues another check. Signed-off-by: TANG Tiancheng --- target/riscv/cpu.h | 1 + target/riscv/tcg/pmu.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 17b9929785f668487d2ec851b736d588e025fd91..a4d33f55c4e5cb6052cea6bee4c= 0afa46372b5c5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -583,6 +583,7 @@ struct ArchCPU { QEMUTimer *pmu_timer; uint64_t pmu_timer_instret_snapshot; bool pmu_timer_stalled; + bool pmu_timer_work_pending; /* A bitmask of Available programmable counters */ uint32_t pmu_avail_ctrs; /* Mapping of events to counters */ diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 08298010b6d06f5792fa14ff81fe2f7a28c6476f..6286552a4ebf614df0252f84ddf= adbc25d8d2258 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -663,15 +663,29 @@ void riscv_pmu_rebuild_timer(CPURISCVState *env) riscv_pmu_rebuild_timer_internal(env, false); } =20 +static void riscv_pmu_timer_work(CPUState *cs, run_on_cpu_data data) +{ + RISCVCPU *cpu =3D RISCV_CPU(cs); + + /* + * An expiry before this exchange is covered by the following counter + * check. The first expiry after it sets pmu_timer_work_pending and qu= eues + * another check. + */ + qatomic_xchg(&cpu->pmu_timer_work_pending, false); + riscv_pmu_rebuild_timer_internal(&cpu->env, true); +} + /* Timer callback for instret and cycle counter overflow */ void riscv_pmu_timer_cb(void *priv) { RISCVCPU *cpu =3D priv; =20 - riscv_pmu_rebuild_timer_internal(&cpu->env, true); + if (!qatomic_xchg(&cpu->pmu_timer_work_pending, true)) { + async_run_on_cpu(CPU(cpu), riscv_pmu_timer_work, RUN_ON_CPU_NULL); + } } =20 - void riscv_pmu_init(RISCVCPU *cpu, Error **errp) { if (cpu->cfg.pmu_mask & (COUNTEREN_CY | COUNTEREN_TM | COUNTEREN_IR)) { --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712777; cv=none; d=zohomail.com; s=zohoarc; b=Oix/q3exl/N2TeJ9ifCXFS1jEbm72LFTZziR6mSRUmU0T1EsrBOoPcydwFC7rXAav8b/50Rnj86vhfF8KbgptxS8b4JsBlLRZ/aPz9Gfrx2WoEfLtBGlvZDmayr10etNFbxnKPv2DCpEjHIcEQGF0IGaUm+MCzdBJrIhnsqeTR4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712777; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Dtl4329WIGQ6KdAb3x+7Thktvshec+Ih2mo5b0zZkOM=; b=BUgtIvYoTBFD+NxsfaKeuOB3UlAvoms+v2GF4DlHF3Cmj7/Za/6UQDVNYCPZProygfft3h8vsWHopI1wnqrnlSPsxy7E8lCy1NqpO1WpAUgtnmhy2KLt3WuXhrClNmF/Wnz0VSiWUQYc2608aQyREoZYdyk5LwNIaYwfTrftdRQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712777317814.0467463434273; Sun, 6 Sep 2026 09:39:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3Fsc-0002yn-Bb; Sun, 06 Sep 2026 12:38:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsZ-0002vr-7a; Sun, 06 Sep 2026 12:38:03 -0400 Received: from [115.124.30.99] (helo=out30-99.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00034b-8v; Sun, 06 Sep 2026 12:38:02 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIKY_1788712658 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:38 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712660; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=Dtl4329WIGQ6KdAb3x+7Thktvshec+Ih2mo5b0zZkOM=; b=YzJ//z/jRzoH1PoU53jEir8B55Bh5ND0M+J5OiCkIDD5N5SKX8hIf+XJekTyIpYV7oiuUXjLjX/i4PKclPbnUNJvQbWjTygCUWo/cKL4iUbc9/F02/7wlYEDVJ2C6MypyRciRfbi1GOqXr8gL9xwV4viHti5yaQTsHTnZE8mlww= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R191e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033045133197; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIKY_1788712658; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:28 +0800 Subject: [PATCH 12/14] target/riscv: Migrate fixed PMU counter state MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-12-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=10473; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=43yGLmw8GE/tnk472DUOQecx2s1MH5MfpKcrsqIdibs=; b=w7gPkOAg+e/LpZlqlHx4aV4F21lHbnaOHthMh+h2c+24JfcNTpfqD7NAhrrQ+nWODMNwlrtrY gT1rI0BPYvtDL+9lXpmx0xErni6cRVaoriyMH9ZrvdtIpQ+Y77LF2VN X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.99 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.99; envelope-from=lyndra@linux.alibaba.com; helo=out30-99.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712780159154100 Migration saves fixed-source baselines but not the per-mode totals they refer to, nor mcyclecfg/minstretcfg. TCG can therefore subtract an unrelated baseline or apply the wrong privilege filter after loading. Before saving, add pending increments allowed by the current filters to each enabled fixed-source counter, including HPM cycle/instruction counters. The per-mode totals then need not migrate. On load, clear those totals and establish destination-local baselines. Inhibited counters get a new baseline when enabled; other event counters get one when switched to a fixed source. This excludes migration downtime and avoids using the source QEMU's saved baselines. Rebuild the event map and overflow timer. Recompute interrupt requests because pre-save can set LCOFIP after cpu_common saved CPU_INTERRUPT_HARD. Keep the existing main-section fields and add cpu/pmu-fixed to carry mcyclecfg/minstretcfg and identify values that include pending increments. All TCG CPUs send and require it because mcycle/minstret exist even without Zicntr, Zihpm or HPM counters. Reject older TCG streams, whose counter values cannot be reconstructed reliably. KVM PMU migration is unchanged. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4422 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4425 Signed-off-by: TANG Tiancheng --- target/riscv/cpu.h | 1 + target/riscv/machine.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++= ---- target/riscv/tcg/pmu.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ target/riscv/tcg/pmu.h | 2 ++ 4 files changed, 163 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a4d33f55c4e5cb6052cea6bee4c0afa46372b5c5..788d5a3ced45b32be05e29eaeb9= ea3af0c0ccd6d 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -584,6 +584,7 @@ struct ArchCPU { uint64_t pmu_timer_instret_snapshot; bool pmu_timer_stalled; bool pmu_timer_work_pending; + bool pmu_fixed_subsection_present; /* A bitmask of Available programmable counters */ uint32_t pmu_avail_ctrs; /* Mapping of events to counters */ diff --git a/target/riscv/machine.c b/target/riscv/machine.c index b0ff2fc7f2ac10fab1f2ff845a953649091e1f43..7aa38b739cfd4d9274fe249eb91= 4411e8a65b91f 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -267,6 +267,30 @@ static const VMStateDescription vmstate_kvm_mp_state = =3D { }; #endif =20 +static int riscv_cpu_pre_load(void *opaque) +{ + RISCVCPU *cpu =3D opaque; + + cpu->pmu_fixed_subsection_present =3D false; +#ifdef CONFIG_KVM + return riscv_cpu_kvm_pre_load(opaque); +#else + return 0; +#endif +} + +static int riscv_cpu_pre_save(void *opaque) +{ +#ifdef CONFIG_TCG + RISCVCPU *cpu =3D opaque; + + if (tcg_enabled()) { + riscv_pmu_prepare_save(&cpu->env); + } +#endif + return 0; +} + static bool debug_needed(void *opaque) { RISCVCPU *cpu =3D opaque; @@ -308,16 +332,25 @@ static const VMStateDescription vmstate_debug =3D { } }; =20 -static int riscv_cpu_post_load(void *opaque, int version_id) +static bool riscv_cpu_post_load(void *opaque, int version_id, Error **errp) { RISCVCPU *cpu =3D opaque; CPURISCVState *env =3D &cpu->env; =20 env->xl =3D cpu_recompute_xl(env); #ifdef CONFIG_TCG - riscv_pmu_rebuild_event_map(env); + if (tcg_enabled()) { + if (!cpu->pmu_fixed_subsection_present) { + error_setg(errp, + "missing RISC-V fixed-counter PMU migration state"); + return false; + } + riscv_pmu_complete_load(env); + /* PMU pre-save can raise an interrupt after cpu_common was saved.= */ + riscv_cpu_interrupt(env); + } #endif - return 0; + return true; } =20 static bool smstateen_needed(void *opaque) @@ -404,6 +437,42 @@ static const VMStateDescription vmstate_pmu_ctr_state = =3D { } }; =20 +static int pmu_fixed_post_load(void *opaque, int version_id) +{ + RISCVCPU *cpu =3D opaque; + + /* Let the outer post-load distinguish this format from a legacy strea= m. */ + cpu->pmu_fixed_subsection_present =3D true; + return 0; +} + +static bool pmu_fixed_needed(void *opaque) +{ + /* + * KVM keeps PMU state in the kernel, not in the TCG counter model. + * TCG implements mcycle/minstret even without Zicntr, Zihpm or + * programmable counters. + */ + return tcg_enabled(); +} + +/* + * This subsection identifies TCG streams whose fixed-source counter values + * include pending deltas. It also carries mcyclecfg and minstretcfg. + */ +static const VMStateDescription vmstate_pmu_fixed =3D { + .name =3D "cpu/pmu-fixed", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D pmu_fixed_needed, + .post_load =3D pmu_fixed_post_load, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT64(env.mcyclecfg, RISCVCPU), + VMSTATE_UINT64(env.minstretcfg, RISCVCPU), + VMSTATE_END_OF_LIST() + } +}; + static bool jvt_needed(void *opaque) { RISCVCPU *cpu =3D opaque; @@ -505,10 +574,9 @@ const VMStateDescription vmstate_riscv_cpu =3D { .name =3D "cpu", .version_id =3D 12, .minimum_version_id =3D 12, -#ifdef CONFIG_KVM - .pre_load =3D riscv_cpu_kvm_pre_load, -#endif - .post_load =3D riscv_cpu_post_load, + .pre_load =3D riscv_cpu_pre_load, + .pre_save =3D riscv_cpu_pre_save, + .post_load_errp =3D riscv_cpu_post_load, .fields =3D (const VMStateField[]) { VMSTATE_UINT64_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), @@ -554,6 +622,11 @@ const VMStateDescription vmstate_riscv_cpu =3D { VMSTATE_UINT32(env.mcounteren, RISCVCPU), VMSTATE_UINT32(env.scountinhibit, RISCVCPU), VMSTATE_UINT32(env.mcountinhibit, RISCVCPU), + /* + * TCG includes pending fixed-source deltas in mhpmcounter_val + * before saving. After loading, it ignores mhpmcounter_prev and + * rebuilds the baseline from the destination source. + */ VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, = 0, vmstate_pmu_ctr_state, PMUCTRState), VMSTATE_UINT64_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENT= S), @@ -582,6 +655,7 @@ const VMStateDescription vmstate_riscv_cpu =3D { &vmstate_ctr, &vmstate_sstc, &vmstate_mseccfg, + &vmstate_pmu_fixed, NULL } }; diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 6286552a4ebf614df0252f84ddfadbc25d8d2258..df99b572a4c16cb1ac65c2f7cde= 35c6f8349e681 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -663,6 +663,85 @@ void riscv_pmu_rebuild_timer(CPURISCVState *env) riscv_pmu_rebuild_timer_internal(env, false); } =20 +static uint32_t riscv_pmu_fixed_source_counter_mask(CPURISCVState *env) +{ + RISCVCPU *cpu =3D env_archcpu(env); + uint32_t mask =3D COUNTEREN_CY | COUNTEREN_IR; + + mask |=3D riscv_pmu_event_counter_mask( + cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES); + mask |=3D riscv_pmu_event_counter_mask( + cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS); + return mask; +} + +static void riscv_pmu_accumulate_fixed_source_counters( + CPURISCVState *env, const RISCVPMUFixedSnapshot *snapshot) +{ + uint32_t mask =3D riscv_pmu_fixed_source_counter_mask(env); + + while (mask) { + uint32_t ctr_idx =3D ctz32(mask); + + mask &=3D ~BIT(ctr_idx); + if (riscv_pmu_fixed_ctr_running(env, ctr_idx)) { + riscv_pmu_accumulate_fixed_delta(env, ctr_idx, snapshot); + } + } +} + +void riscv_pmu_prepare_save(CPURISCVState *env) +{ + RISCVPMUFixedSnapshot snapshot; + + riscv_pmu_take_fixed_snapshot(env, &snapshot); + riscv_pmu_accumulate_fixed_source_counters(env, &snapshot); +} + +static void riscv_pmu_rebase_fixed_source_counters( + CPURISCVState *env, const RISCVPMUFixedSnapshot *snapshot) +{ + uint32_t mask; + + memset(env->pmu_fixed_ctrs, 0, sizeof(env->pmu_fixed_ctrs)); + if (env->virt_enabled) { + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_CYCLE] + .counter_virt_prev[env->priv] =3D snapshot->cycle; + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_INSTRET] + .counter_virt_prev[env->priv] =3D snapshot->instret; + } else { + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_CYCLE] + .counter_prev[env->priv] =3D snapshot->cycle; + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_INSTRET] + .counter_prev[env->priv] =3D snapshot->instret; + } + + mask =3D riscv_pmu_fixed_source_counter_mask(env); + while (mask) { + uint32_t ctr_idx =3D ctz32(mask); + + mask &=3D ~BIT(ctr_idx); + if (riscv_pmu_fixed_ctr_enabled(env, ctr_idx)) { + riscv_pmu_set_fixed_baseline(env, ctr_idx, snapshot); + } + } +} + +void riscv_pmu_complete_load(CPURISCVState *env) +{ + RISCVCPU *cpu =3D env_archcpu(env); + RISCVPMUFixedSnapshot snapshot; + + riscv_pmu_rebuild_event_map(env); + riscv_pmu_take_fixed_snapshot(env, &snapshot); + riscv_pmu_rebase_fixed_source_counters(env, &snapshot); + + qatomic_set(&cpu->pmu_timer_work_pending, false); + cpu->pmu_timer_stalled =3D false; + cpu->pmu_timer_instret_snapshot =3D snapshot.instret; + riscv_pmu_rebuild_timer(env); +} + static void riscv_pmu_timer_work(CPUState *cs, run_on_cpu_data data) { RISCVCPU *cpu =3D RISCV_CPU(cs); diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index d9238ae680f5e67031511db4f9afc2884212c5c2..1cfe6acf55b5468f5c00c4a136e= ce88981384341 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -45,6 +45,8 @@ void riscv_pmu_write_counter(CPURISCVState *env, uint32_t= ctr_idx, void riscv_pmu_write_inhibit(CPURISCVState *env, uint32_t value); void riscv_pmu_timer_cb(void *priv); void riscv_pmu_rebuild_timer(CPURISCVState *env); +void riscv_pmu_prepare_save(CPURISCVState *env); +void riscv_pmu_complete_load(CPURISCVState *env); void riscv_pmu_init(RISCVCPU *cpu, Error **errp); void riscv_pmu_rebuild_event_map(CPURISCVState *env); int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx); --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712846; cv=none; d=zohomail.com; s=zohoarc; b=XYtA384cYajDLNbDcJrkX56zp9b2Q/GIgfcC7ZC3HCMEb9f0YkNicWJL2wVPFiRAvZJrtGKWXBjesbKO+qViHD+4T9L6bcYMFOqxahhqJcJIbl/6fCkttujgP++VmK70sS4baH1qH2eqHvD698GkE+ybpR7JaKUVPo8dh1kCrhs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712846; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=tJ6f5rlvH63y4Ir/VIRa5cuvUpA/LiCcOhmeXXN0U+w=; b=da0NicBd5sbQITgX1jyke7Mj5GJn9nMDPtx8Cwwb4tK67PElst0gbOo6Ci1BQj5iXMzaK+No0RyTSPOsTogfrC0SFwypvxBXxg4EnVWd3Esw1+HsoaacrlzgcjrsC1CaqFvHKcqEpZ2/NF+BV6hgrHl5U55U9vxsRhCwwiMENZc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712845990275.2383596829509; Sun, 6 Sep 2026 09:40:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsX-0002tE-GQ; Sun, 06 Sep 2026 12:38:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsV-0002rR-Pf; Sun, 06 Sep 2026 12:37:59 -0400 Received: from [115.124.30.99] (helo=out30-99.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsP-00034V-Kg; Sun, 06 Sep 2026 12:37:59 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIKm_1788712658 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:39 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712659; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=tJ6f5rlvH63y4Ir/VIRa5cuvUpA/LiCcOhmeXXN0U+w=; b=rZ7CMws3HFnX9/BunahELXKtooJevO9cOct6Y2Y6Nct7RSVR/BmhPuCEkTEwV6iEBy1GPq4WY5ves8QLyMHPGFb/mw9La0a3jPN+FYifi2h7iDnMWy3a2CneJaq5pJgDm7fweMtBrRhsV2V9DiFin3dTyeSuTadUxvGb5Grew0E= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R171e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033037026112; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIKm_1788712658; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:29 +0800 Subject: [PATCH 13/14] target/riscv: Clear virtualization mode on reset MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-13-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=837; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=QW0Me4iDB+uwIwIt50Y3j/AqfGl9odnbZpGGFQviNTE=; b=EcFicaHXwSZUioDvqHxZBhHLjPIoo2Q0djnsQi3+8dWiYDMU4SZcAu/lH9BdcXyNQIhXIYAzI rcgUeON9dF0Av4SRz8GZ5GptTefLiAnMqDu68o7YWdkLbqxEpjouCMv X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.99 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.99; envelope-from=lyndra@linux.alibaba.com; helo=out30-99.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712846201158500 Reset enters M-mode without clearing virt_enabled, leaving an invalid M-mode, V=3D1 state after a reset from virtual mode. Clear virt_enabled alongside the privilege reset. Signed-off-by: TANG Tiancheng --- target/riscv/cpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 652311ddef2fae9503210e9afac11252b2ca615b..b7ce3ebd45d8467464654a8b856= 0e88deeea4ff9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -980,6 +980,7 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType= type) #ifndef CONFIG_USER_ONLY env->misa_mxl =3D mcc->def->misa_mxl_max; env->priv =3D PRV_M; + env->virt_enabled =3D false; env->mstatus &=3D ~(MSTATUS_MIE | MSTATUS_MPRV); if (env->misa_mxl > MXL_RV32) { /* --=20 2.43.0 From nobody Sat Sep 26 20:01:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.alibaba.com ARC-Seal: i=1; a=rsa-sha256; t=1788712777; cv=none; d=zohomail.com; s=zohoarc; b=Zo8J0Vi5VpIQGCWij9ubj01G4rhlcwAygAcUxeIrbp1KWvKrwjVasqRiYYQFEYmhFUb84D0pNKwvyiMt7dB0YxEmrJYdSFmhfbZvRSJ7VmA6CZvC0I4Gx5q+VgSUlG4cvtA6mN+moHIaT9OZZmphUttbo4j2OD8PhOLSCkMT2Cw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788712777; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=viOOe7smLkpWORSnnyjZ7fkNNcWDtL6fhqM5XkykUVY=; b=Kz8gtsQ71knQl19h52hgod+RzfXUgF91aD6P/MEiZ/KRDABf8CjXt0GHZB9gvCcDsKVxhOOVc1GS1eybATx/Q9kffJodjcehJw7lDyPxsZdzJYUHeuF03XXXtb9dg3dynm3DdUI4nfw7hs6kEYYfozFEm1UEZNaXBuTM/YOAal0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788712776962432.43972073263694; Sun, 6 Sep 2026 09:39:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x3FsY-0002tq-1T; Sun, 06 Sep 2026 12:38:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsW-0002rk-5K; Sun, 06 Sep 2026 12:38:00 -0400 Received: from [115.124.30.110] (helo=out30-110.freemail.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x3FsQ-00034r-1T; Sun, 06 Sep 2026 12:37:59 -0400 Received: from ea134-sw06.eng.xrvm.cn(mailfrom:lyndra@linux.alibaba.com fp:SMTPD_---0XANKIKw_1788712659 cluster:ay36) by smtp.aliyun-inc.com; Mon, 07 Sep 2026 00:37:39 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788712661; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To; bh=viOOe7smLkpWORSnnyjZ7fkNNcWDtL6fhqM5XkykUVY=; b=iWT5ke6zr0qxKa9MuZX8WBjcuTl4Ec/ebltXWepFRbzXeJs2VcQsZMo7Kr3OuKx44GWDULzl77TQT0V4IqG2mP4UHGnFD1b2qS75HEGJ7rCZvN5VEFDkre0Iw5Wb/e0LL5z6CDB8GRsjPX/gMfVDsXkGvO2wTP4nUAHxTImofwM= X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R121e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=maildocker-contentspam033045098064; MF=lyndra@linux.alibaba.com; NM=1; PH=DS; RN=13; SR=0; TI=SMTPD_---0XANKIKw_1788712659; From: TANG Tiancheng Date: Mon, 07 Sep 2026 00:37:30 +0800 Subject: [PATCH 14/14] target/riscv: Preserve fixed PMU state across reset MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260907-riscv-pmu-correctness-v1-14-5f1f41458989@linux.alibaba.com> References: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> In-Reply-To: <20260907-riscv-pmu-correctness-v1-0-5f1f41458989@linux.alibaba.com> To: qemu-devel@nongnu.org Cc: Zephyr Li , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-riscv@nongnu.org, Richard Henderson , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , TANG Tiancheng X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788712649; l=7074; i=lyndra@linux.alibaba.com; s=20250909; h=from:subject:message-id; bh=2enD98ZE6bl3nA0tsxaYMcS19QEg1Xx+ZgF2vOA5LYM=; b=R073xL1WvFir862XvJDQhJiTfXD07OyvVjhsl3n3xmUd63ApkQRcVFIX8EVV0y2oscdO9gOoT W4H0LKmiPbcBxZd9iQGnfTDP/g2BSrsG+VlOehCrFOGvGe7qp4SaKgc X-Developer-Key: i=lyndra@linux.alibaba.com; a=ed25519; pk=GQh4uOSLVucXGkaZfEuQ956CrYS14cn1TA3N8AiIjBw= X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.30.110 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=115.124.30.110; envelope-from=lyndra@linux.alibaba.com; helo=out30-110.freemail.mail.aliyun.com X-Spam_score_int: -166 X-Spam_score: -16.7 X-Spam_bar: ---------------- X-Spam_report: (-16.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, ENV_AND_HDR_SPF_MATCH=-0.5, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, USER_IN_DEF_DKIM_WL=-7.5, USER_IN_DEF_SPF_WL=-7.5 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.alibaba.com) X-ZM-MESSAGEID: 1788712780010154100 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=3D0 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 --- target/riscv/cpu.c | 16 +++++ target/riscv/tcg/pmu.c | 11 ++++ target/riscv/tcg/pmu.h | 1 + tests/tcg/riscv64/Makefile.softmmu-target | 6 ++ tests/tcg/riscv64/pmu-reset-vs.S | 102 ++++++++++++++++++++++++++= ++++ 5 files changed, 136 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b7ce3ebd45d8467464654a8b8560e88deeea4ff9..4355f72cdfda41ab4e9678a0668= 21c0f410fe17c 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 =20 /* RISC-V CPU definitions */ @@ -979,6 +982,16 @@ static void riscv_cpu_reset_hold(Object *obj, ResetTyp= e type) } #ifndef CONFIG_USER_ONLY env->misa_mxl =3D 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 =3D PRV_M; env->virt_enabled =3D false; env->mstatus &=3D ~(MSTATUS_MIE | MSTATUS_MPRV); @@ -1092,6 +1105,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetTy= pe type) =20 #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..1d692a0a8e3f7759e033214d579= 103627d070b5b 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= ); } =20 +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] =3D snapshot.cycle; + env->pmu_fixed_ctrs[RISCV_PMU_FIXED_DOMAIN_INSTRET] + .counter_prev[PRV_M] =3D 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..fac84dbb1a8a6c637f7241ca279= 10e5e212223e9 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_even= t_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 newp= riv, 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/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index deb44ece5feeb13756f9f3abcd38258d75bd9ba1..ef7641b16deb449e3a84e429dfc= a998dbd63a54e 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -95,6 +95,12 @@ TESTS +=3D pmu-cycle-controls run-pmu-cycle-controls: pmu-cycle-controls $(call run-test, $<, $(QEMU) -cpu max -icount shift=3D0 $(QEMU_OPTS)$<) =20 +TESTS +=3D pmu-reset-vs +run-pmu-reset-vs: pmu-reset-vs + $(call run-test, $<, $(QEMU) -M virt -bios none -kernel $< \ + -display none -semihosting -cpu max$(COMMA)smcntrpmf=3Dtrue \ + -icount shift=3D0) + EXTRA_RUNS +=3D run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/pmu-reset-vs.S b/tests/tcg/riscv64/pmu-reset= -vs.S new file mode 100644 index 0000000000000000000000000000000000000000..856ca003fa1115fdba5e789128a= a1d6fd0f950b6 --- /dev/null +++ b/tests/tcg/riscv64/pmu-reset-vs.S @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .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: + /* MTIMECMP retains the marker and saved count across the RAM reload. */ + 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 0x321, t0 /* mcyclecfg */ + 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 --=20 2.43.0