target/riscv/tcg/pmu.c | 6 +-
tests/tcg/riscv64/sscofpmf-event-overflow.S | 103 ++++++++++++++++++++++++++++
tests/tcg/riscv64/system/meson.build | 15 ++++
3 files changed, 119 insertions(+), 5 deletions(-)
diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c
index
16942e53489cd5a2d2dd055fdffef07d04d59465..2f600c5a0fc2d7ba380ef34f89af6366e3e27884
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_event_idx event_idx)
counter = &env->pmu_ctrs[ctr_idx];
if (counter->mhpmcounter_val == max_val) {
counter->mhpmcounter_val = 0;
- /* Generate interrupt only if OF bit is clear */
- if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) {
- env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
- riscv_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/sscofpmf-event-overflow.S
b/tests/tcg/riscv64/sscofpmf-event-overflow.S
new file mode 100644
index
0000000000000000000000000000000000000000..cce06da10f9c7c20c18c7863b58b6dd724c45182
--- /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 mhpmevent3, zero
+ li t0, -1
+ csrw mhpmcounter3, t0
+ li t0, 0x10019 /* DTLB read miss */
+ csrw mhpmevent3, 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, mhpmcounter3
+ bnez t0, exit
+
+ /* Only Sscofpmf turns that wrap into OF and LCOFIP. */
+ li t4, 2
+ csrr t0, mhpmevent3
+ 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 mhpmcounter3, t0
+ sfence.vma
+ lla t0, second_page
+ lw t1, 0(t0)
+ li t4, 4
+ csrr t0, mhpmcounter3
+ bnez t0, exit
+ li t4, 5
+ csrr t0, mhpmevent3
+ 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, mhpmcounter3
+ 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
diff --git a/tests/tcg/riscv64/system/meson.build
b/tests/tcg/riscv64/system/meson.build
index
1dd0402631036d0d377bb90d7cb1da2bae34ead4..13ee7954ef4f09559a02a3730fb017ccf2cfd882
100644
--- a/tests/tcg/riscv64/system/meson.build
+++ b/tests/tcg/riscv64/system/meson.build
@@ -99,6 +99,21 @@ tests += {
},
}
+tests += {
+ 'sscofpmf-event-overflow.S': {
+ 'cflags': cflags,
+ 'qemu_args': ['-cpu', 'max', qemu_args],
+ },
+}
+
+tests += {
+ 'sscofpmf-event-overflow.S': {
+ 'exe_name': 'sscofpmf-event-overflow-off',
+ 'cflags': cflags + ['-DEXPECT_SSCOFPMF=0'],
+ 'qemu_args': ['-cpu', 'max,sscofpmf=false', qemu_args],
+ },
+}
+
tests += {
'sscofpmf-cycle-overflow.S': {
'cflags': cflags,