On Thu, Sep 10, 2026 at 10:39:41PM +0800, TANG Tiancheng wrote:
> 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]>
Reviewed-by: Chao Liu <[email protected]>
Thanks,
Chao
> ---
> 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
>