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 <[email protected]>
---
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..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/Makefile.softmmu-target
b/tests/tcg/riscv64/Makefile.softmmu-target
index
5a94a90c40f838e4e78268f8cedc480d5e2ff3bf..b100f7a9ddf8e31fb104aa834b28aa64fc31f50e
100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -69,6 +69,16 @@ TESTS += sscofpmf-overflow
run-sscofpmf-overflow: sscofpmf-overflow
$(call run-test, $<, $(QEMU) -cpu max -icount shift=0 $(QEMU_OPTS)$<)
+sscofpmf-event-overflow-off: sscofpmf-event-overflow.S $(LINK_SCRIPT)
+ $(CC) $(CFLAGS) -DEXPECT_SSCOFPMF=0 $< -Wa,--noexecstack -c -o [email protected]
+ $(LD) $(LDFLAGS) [email protected] -o $@
+
+TESTS += 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=false
$(QEMU_OPTS)$<)
+
TESTS += sscofpmf-cycle-overflow
run-sscofpmf-cycle-overflow: sscofpmf-cycle-overflow
$(call run-test, $<, $(QEMU) -cpu max -icount shift=3 $(QEMU_OPTS)$<)
diff --git a/tests/tcg/riscv64/sscofpmf-event-overflow.S
b/tests/tcg/riscv64/sscofpmf-event-overflow.S
new file mode 100644
index
0000000000000000000000000000000000000000..5bbcb060ae87124349151a14c6db815755c6e58d
--- /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
--
2.43.0