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 sireg*
cfg CSR read")
Signed-off-by: TANG Tiancheng <[email protected]>
---
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..57030724f85a897e21e5082b9857411b50f932ac
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 &= ~MCYCLECFG_BIT_MINH;
env->mcyclecfg = (new_val & wr_mask) | (env->mcyclecfg & ~wr_mask);
} else {
- *val = env->mcyclecfg &= ~MHPMEVENT_BIT_MINH;
+ *val = 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 = (new_val & wr_mask) |
(env->minstretcfg & ~wr_mask);
} else {
- *val = env->minstretcfg &= ~MHPMEVENT_BIT_MINH;
+ *val = env->minstretcfg & ~MINSTRETCFG_BIT_MINH;
}
break;
default:
@@ -1642,7 +1642,7 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int
cfg_index, target_ulong *val,
cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask);
env->mcyclecfg = deposit64(env->mcyclecfg, 32, 32, cfgh);
} else {
- *val = cfgh;
+ *val = cfgh & ~MCYCLECFGH_BIT_MINH;
}
break;
case 2: /* INSTRETCFGH */
@@ -1652,7 +1652,7 @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int
cfg_index, target_ulong *val,
cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask);
env->minstretcfg = deposit64(env->minstretcfg, 32, 32, cfgh);
} else {
- *val = cfgh;
+ *val = 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..67d334974577e14ff36e7c51067ebcab4c1349bd
--- /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 = $(SRC_PATH)/tests/tcg/riscv32
+VPATH += $(TEST_SRC)
+
+LINK_SCRIPT = $(SRC_PATH)/tests/tcg/riscv64/semihost.ld
+LDFLAGS = -m elf32lriscv -T $(LINK_SCRIPT)
+CFLAGS += -g -Og $(EXTRA_CFLAGS) -march=rv32im_zicsr -mabi=ilp32
+
+%.o: %.S
+ $(CC) $(CFLAGS) $< -Wa,--noexecstack -c -o $@
+%: %.o $(LINK_SCRIPT)
+ $(LD) $(LDFLAGS) $< -o $@
+
+QEMU_OPTS += -M virt -display none -semihosting -device loader,file=
+
+TESTS += 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/smcdeleg-minh-rv32.S
new file mode 100644
index
0000000000000000000000000000000000000000..2e8ee394f5f8a4e01b1c9efc815d21af18de4b3c
--- /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..af6bc1aad8893726a3b26392da89f34319dd78a8
100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -48,6 +48,10 @@ TESTS += sscofpmf-cycle-overflow
run-sscofpmf-cycle-overflow: sscofpmf-cycle-overflow
$(call run-test, $<, $(QEMU) -cpu max -icount shift=3 $(QEMU_OPTS)$<)
+TESTS += smcdeleg-minh
+run-smcdeleg-minh: smcdeleg-minh
+ $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<)
+
EXTRA_RUNS += 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..41cbb580475b5dcd079d4542631dfe2474536d60
--- /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
--
2.43.0