[PATCH] target/riscv: mask vsepc according to IALIGN

Zephyr Li posted 1 patch 1 week, 4 days ago
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>, Chao Liu <chao.liu@processmission.com>
target/riscv/tcg/csr.c                 |  4 +-
tests/tcg/riscv64/system/meson.build   | 11 ++++++
tests/tcg/riscv64/test-vsepc-masking.S | 54 ++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 2 deletions(-)
create mode 100644 tests/tcg/riscv64/test-vsepc-masking.S
[PATCH] target/riscv: mask vsepc according to IALIGN
Posted by Zephyr Li 1 week, 4 days ago
vsepc is the VS-mode counterpart of sepc and is a WARL register, but
unlike mepc and sepc its accessors do not mask the low address bits
according to IALIGN.  As a result, values with invalid low bits can be
observed through vsepc.

Apply get_xepc_mask() to both vsepc reads and writes, matching the
existing mepc/sepc handling.

Add a TCG regression test covering both IALIGN=16 and IALIGN=32.

Fixes: 8747c9eeb2aa ("target/riscv: Add Hypervisor virtual CSRs accesses")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4420
Signed-off-by: Zephyr Li <fritchleybohrer@gmail.com>
---
 target/riscv/tcg/csr.c                 |  4 +-
 tests/tcg/riscv64/system/meson.build   | 11 ++++++
 tests/tcg/riscv64/test-vsepc-masking.S | 54 ++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
 create mode 100644 tests/tcg/riscv64/test-vsepc-masking.S

diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
index bd4b6dc114..274c5cfbf4 100644
--- a/target/riscv/tcg/csr.c
+++ b/target/riscv/tcg/csr.c
@@ -5299,14 +5299,14 @@ static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
 static RISCVException read_vsepc(CPURISCVState *env, int csrno,
                                  target_ulong *val)
 {
-    *val = env->vsepc;
+    *val = env->vsepc & get_xepc_mask(env);
     return RISCV_EXCP_NONE;
 }
 
 static RISCVException write_vsepc(CPURISCVState *env, int csrno,
                                   target_ulong val, uintptr_t ra)
 {
-    env->vsepc = val;
+    env->vsepc = val & get_xepc_mask(env);
     return RISCV_EXCP_NONE;
 }
 
diff --git a/tests/tcg/riscv64/system/meson.build b/tests/tcg/riscv64/system/meson.build
index 8604c2a45a..5d633a266a 100644
--- a/tests/tcg/riscv64/system/meson.build
+++ b/tests/tcg/riscv64/system/meson.build
@@ -24,6 +24,17 @@ tests += {
   'test-crc32.S': setup + {'qemu_args': ['-cpu', 'rv64,xlrbr=true', qemu_args]},
   'test-minstret-ecall.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]},
   'test-misa-w.S': setup + {'qemu_args': ['-cpu', 'rv64,x-misa-w=true,c=true,v=true', qemu_args]},
+  'test-vsepc-masking.S': setup + {
+    'test_name': 'test-vsepc-masking-c',
+    'qemu_args': ['-cpu', 'rv64,h=true,c=true', qemu_args],
+  },
+}
+
+tests += {
+  'test-vsepc-masking.S': {
+    'test_name': 'test-vsepc-masking-no-c',
+    'qemu_args': ['-cpu', 'rv64,h=true,c=false,zca=false', qemu_args],
+  },
 }
 
 tests += {
diff --git a/tests/tcg/riscv64/test-vsepc-masking.S b/tests/tcg/riscv64/test-vsepc-masking.S
new file mode 100644
index 0000000000..e5460f8aee
--- /dev/null
+++ b/tests/tcg/riscv64/test-vsepc-masking.S
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#define MISA_C          (1 << 2)
+
+	.option	norvc
+	.text
+	.global	_start
+_start:
+	csrr	s0, misa
+	andi	s0, s0, MISA_C
+
+	lla	s1, test_addr
+	ori	t0, s1, 3
+	csrw	vsepc, t0
+	csrr	t1, vsepc
+
+	beqz	s0, ialign32
+	addi	t2, s1, 2	/* IALIGN=16: bit 0 reads as zero. */
+	j	check
+
+ialign32:
+	/* IALIGN=32: bits [1:0] read as zero. */
+	mv	t2, s1
+
+check:
+	li	a0, 2
+	bne	t1, t2, _exit
+
+	li	a0, 0
+	j	_exit
+
+	.balign	4
+test_addr:
+	nop
+
+/* Exit code in a0. */
+_exit:
+	lla	a1, semiargs
+	li	t0, 0x20026	/* ADP_Stopped_ApplicationExit */
+	sd	t0, 0(a1)
+	sd	a0, 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
Re: [PATCH] target/riscv: mask vsepc according to IALIGN
Posted by Daniel Henrique Barboza 1 day, 4 hours ago

On 9/14/2026 11:49 PM, Zephyr Li wrote:
> vsepc is the VS-mode counterpart of sepc and is a WARL register, but
> unlike mepc and sepc its accessors do not mask the low address bits
> according to IALIGN.  As a result, values with invalid low bits can be
> observed through vsepc.
> 
> Apply get_xepc_mask() to both vsepc reads and writes, matching the
> existing mepc/sepc handling.
> 
> Add a TCG regression test covering both IALIGN=16 and IALIGN=32.
> 
> Fixes: 8747c9eeb2aa ("target/riscv: Add Hypervisor virtual CSRs accesses")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4420
> Signed-off-by: Zephyr Li <fritchleybohrer@gmail.com>
> ---

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

>   target/riscv/tcg/csr.c                 |  4 +-
>   tests/tcg/riscv64/system/meson.build   | 11 ++++++
>   tests/tcg/riscv64/test-vsepc-masking.S | 54 ++++++++++++++++++++++++++
>   3 files changed, 67 insertions(+), 2 deletions(-)
>   create mode 100644 tests/tcg/riscv64/test-vsepc-masking.S
> 
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index bd4b6dc114..274c5cfbf4 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -5299,14 +5299,14 @@ static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
>   static RISCVException read_vsepc(CPURISCVState *env, int csrno,
>                                    target_ulong *val)
>   {
> -    *val = env->vsepc;
> +    *val = env->vsepc & get_xepc_mask(env);
>       return RISCV_EXCP_NONE;
>   }
>   
>   static RISCVException write_vsepc(CPURISCVState *env, int csrno,
>                                     target_ulong val, uintptr_t ra)
>   {
> -    env->vsepc = val;
> +    env->vsepc = val & get_xepc_mask(env);
>       return RISCV_EXCP_NONE;
>   }
>   
> diff --git a/tests/tcg/riscv64/system/meson.build b/tests/tcg/riscv64/system/meson.build
> index 8604c2a45a..5d633a266a 100644
> --- a/tests/tcg/riscv64/system/meson.build
> +++ b/tests/tcg/riscv64/system/meson.build
> @@ -24,6 +24,17 @@ tests += {
>     'test-crc32.S': setup + {'qemu_args': ['-cpu', 'rv64,xlrbr=true', qemu_args]},
>     'test-minstret-ecall.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]},
>     'test-misa-w.S': setup + {'qemu_args': ['-cpu', 'rv64,x-misa-w=true,c=true,v=true', qemu_args]},
> +  'test-vsepc-masking.S': setup + {
> +    'test_name': 'test-vsepc-masking-c',
> +    'qemu_args': ['-cpu', 'rv64,h=true,c=true', qemu_args],
> +  },
> +}
> +
> +tests += {
> +  'test-vsepc-masking.S': {
> +    'test_name': 'test-vsepc-masking-no-c',
> +    'qemu_args': ['-cpu', 'rv64,h=true,c=false,zca=false', qemu_args],
> +  },
>   }
>   
>   tests += {
> diff --git a/tests/tcg/riscv64/test-vsepc-masking.S b/tests/tcg/riscv64/test-vsepc-masking.S
> new file mode 100644
> index 0000000000..e5460f8aee
> --- /dev/null
> +++ b/tests/tcg/riscv64/test-vsepc-masking.S
> @@ -0,0 +1,54 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#define MISA_C          (1 << 2)
> +
> +	.option	norvc
> +	.text
> +	.global	_start
> +_start:
> +	csrr	s0, misa
> +	andi	s0, s0, MISA_C
> +
> +	lla	s1, test_addr
> +	ori	t0, s1, 3
> +	csrw	vsepc, t0
> +	csrr	t1, vsepc
> +
> +	beqz	s0, ialign32
> +	addi	t2, s1, 2	/* IALIGN=16: bit 0 reads as zero. */
> +	j	check
> +
> +ialign32:
> +	/* IALIGN=32: bits [1:0] read as zero. */
> +	mv	t2, s1
> +
> +check:
> +	li	a0, 2
> +	bne	t1, t2, _exit
> +
> +	li	a0, 0
> +	j	_exit
> +
> +	.balign	4
> +test_addr:
> +	nop
> +
> +/* Exit code in a0. */
> +_exit:
> +	lla	a1, semiargs
> +	li	t0, 0x20026	/* ADP_Stopped_ApplicationExit */
> +	sd	t0, 0(a1)
> +	sd	a0, 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