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/smcdeleg-minh-rv32.S | 78 ++++++++++++++++++++++++++++++++++
 tests/tcg/riscv32/system/meson.build   |  7 +++
 tests/tcg/riscv64/smcdeleg-minh.S      | 78 ++++++++++++++++++++++++++++++++++
 tests/tcg/riscv64/system/meson.build   |  7 +++
 5 files changed, 174 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/smcdeleg-minh-rv32.S 
b/tests/tcg/riscv32/smcdeleg-minh-rv32.S
new file mode 100644
index 
0000000000000000000000000000000000000000..db467b95cf1441e3440f59097401cf6956d294d3
--- /dev/null
+++ b/tests/tcg/riscv32/smcdeleg-minh-rv32.S
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* CSR numbers for older assemblers. */
+#define CSR_SISELECT         0x150
+#define CSR_SIREG5           0x156
+#define CSR_MENVCFGH         0x31a
+#define CSR_MCYCLECFGH       0x721
+#define CSR_MINSTRETCFGH     0x722
+
+       .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    CSR_MCYCLECFGH, t0
+       csrw    CSR_MINSTRETCFGH, t0
+       li      t1, 1
+       slli    t1, t1, 28              /* menvcfgh.CDE */
+       csrw    CSR_MENVCFGH, t1
+       li      t1, 5                   /* Delegate cycle and instret. */
+       csrw    mcounteren, t1
+
+       /* Check the delegated view, then the underlying machine register. */
+       li      t1, 0x40                /* siselect: cycle */
+       csrw    CSR_SISELECT, t1
+       csrr    t1, CSR_SIREG5
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       or      t4, t4, t1
+       csrr    t1, CSR_MCYCLECFGH
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       xori    t1, t1, 1
+       slli    t1, t1, 1
+       or      t4, t4, t1
+
+       li      t1, 0x42                /* siselect: instret */
+       csrw    CSR_SISELECT, t1
+       csrr    t1, CSR_SIREG5
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       slli    t1, t1, 2
+       or      t4, t4, t1
+       csrr    t1, CSR_MINSTRETCFGH
+       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 */
+       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/system/meson.build 
b/tests/tcg/riscv32/system/meson.build
index 
16f9a06c9485ed75b3d127d6b9d090f5eaad4486..cfe2d854b729a8dfdbce2373e73b91b470db6b4e
 100644
--- a/tests/tcg/riscv32/system/meson.build
+++ b/tests/tcg/riscv32/system/meson.build
@@ -22,6 +22,13 @@ tests += {
   },
 }
 
+tests += {
+  'smcdeleg-minh-rv32.S': {
+    'cflags': cflags,
+    'qemu_args': ['-cpu', 'max', qemu_args],
+  },
+}
+
 if 'qemu-system-riscv32' in emulators
   tcg_tests += {
     'riscv32-softmmu': {
diff --git a/tests/tcg/riscv64/smcdeleg-minh.S 
b/tests/tcg/riscv64/smcdeleg-minh.S
new file mode 100644
index 
0000000000000000000000000000000000000000..38d3c30f0afaa416a46322f2b892e5969172a60f
--- /dev/null
+++ b/tests/tcg/riscv64/smcdeleg-minh.S
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* CSR numbers for older assemblers. */
+#define CSR_SISELECT         0x150
+#define CSR_SIREG2           0x152
+#define CSR_MENVCFG          0x30a
+#define CSR_MCYCLECFG        0x321
+#define CSR_MINSTRETCFG      0x322
+
+       .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    CSR_MCYCLECFG, t0
+       csrw    CSR_MINSTRETCFG, t0
+       li      t1, 1
+       slli    t1, t1, 60              /* menvcfg.CDE */
+       csrw    CSR_MENVCFG, t1
+       li      t1, 5                   /* Delegate cycle and instret. */
+       csrw    mcounteren, t1
+
+       /* Check the delegated view, then the underlying machine register. */
+       li      t1, 0x40                /* siselect: cycle */
+       csrw    CSR_SISELECT, t1
+       csrr    t1, CSR_SIREG2
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       or      t4, t4, t1
+       csrr    t1, CSR_MCYCLECFG
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       xori    t1, t1, 1
+       slli    t1, t1, 1
+       or      t4, t4, t1
+
+       li      t1, 0x42                /* siselect: instret */
+       csrw    CSR_SISELECT, t1
+       csrr    t1, CSR_SIREG2
+       and     t1, t1, t0
+       sltu    t1, zero, t1
+       slli    t1, t1, 2
+       or      t4, t4, t1
+       csrr    t1, CSR_MINSTRETCFG
+       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
diff --git a/tests/tcg/riscv64/system/meson.build 
b/tests/tcg/riscv64/system/meson.build
index 
668a9a76070b6f16087b08ea84683d883312e951..5d91381c62d77ae7e37c129112d6367f692df660
 100644
--- a/tests/tcg/riscv64/system/meson.build
+++ b/tests/tcg/riscv64/system/meson.build
@@ -75,6 +75,13 @@ tests += {
   },
 }
 
+tests += {
+  'smcdeleg-minh.S': {
+    'cflags': cflags,
+    'qemu_args': ['-cpu', 'max', qemu_args],
+  },
+}
+
 if 'qemu-system-riscv64' in emulators
   tcg_tests += {
     'riscv64-softmmu': {

-- 
2.43.0


Reply via email to