[RFC PATCH] riscv: clarify vector state semantics on syscall and context switch
Andy Chiu
tchiu at tenstorrent.com
Wed May 20 23:48:55 PDT 2026
On Thu, Mar 19, 2026 at 03:37:09PM +0800, daichengrong wrote:
> The RISC-V vector specification states that executing a system call
> causes all caller-saved vector registers (v0-v31, vl, vtype) and vstart
> to become unspecified.
>
> Currently, after calling riscv_v_vstate_discard(), the vector state
> may still be marked as DIRTY, which can mislead the context switch
> logic into treating the registers as containing valid user data.
>
> This patch clarifies and tightens the kernel-side semantics:
>
> 1. On syscall entry, the kernel checks the vector state via mstatus
> and discards it if necessary. After discard, the state is explicitly
> set to INIT instead of DIRTY, indicating that the vector registers
> no longer contain meaningful user data.
>
> 2. During context switch, the vector state is interpreted as follows:
> - INIT: no valid user data is present, so vector register data does
> not need to be saved.
> - non-INIT (e.g. DIRTY): vector register data must be saved.
>
> 3. On restore, if the state is INIT, the vector registers are treated
> as invalid and are not restored from memory. Instead, they are
> overwritten with a known initial value to avoid potential data
> leakage from a previous task.
>
> This aligns the kernel's vector state tracking with the architectural
> "unspecified" semantics while ensuring correct lazy context switching
> and preventing cross-task data leakage.
Hi daichengrong,
Good catch on spotting this optimization opportunity!
I have a patch series[1] that happens to be very similar as yours, but I
think your coding style make the code more readable (I like the way you
use _vstate_check for CLEAN on restore path).
Here are some issues where this patch breaks:
- first-use trap returns discarded vregs instead of zero'ed.
- ptrace gets stale vregs in PTRACE_SYSCALL
- context modifications through signal handler are dropped at syscall
stops.
I will merge your patch into my v3 with all the above fixed. Hope that
sounds good to you!
[1]: https://lore.kernel.org/linux-riscv/20260402043414.2421916-2-andybnac@gmail.com/
>
> Signed-off-by: daichengrong <daichengrong at iscas.ac.cn>
> ---
> arch/riscv/include/asm/vector.h | 15 +++++++--------
> 1 file changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index 00cb9c0982b1..93c68a549b72 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -298,8 +298,9 @@ static inline void __riscv_v_vstate_discard(void)
> static inline void riscv_v_vstate_discard(struct pt_regs *regs)
> {
> if (riscv_v_vstate_query(regs)) {
> - __riscv_v_vstate_discard();
> - __riscv_v_vstate_dirty(regs);
We can skip discarding vstate here as it will be done in the restore path
> + if (!__riscv_v_vstate_check(regs->status, INITIAL))
> + __riscv_v_vstate_discard();
> + riscv_v_vstate_on(regs);
> }
> }
>
> @@ -315,19 +316,17 @@ static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
> static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
> struct pt_regs *regs)
> {
> - if (riscv_v_vstate_query(regs)) {
> + if (__riscv_v_vstate_check(regs->status, INITIAL))
> + __riscv_v_vstate_discard();
> + else if (__riscv_v_vstate_check(regs->status, CLEAN))
> __riscv_v_vstate_restore(vstate, vstate->datap);
> - __riscv_v_vstate_clean(regs);
> - }
> }
>
> static inline void riscv_v_vstate_set_restore(struct task_struct *task,
> struct pt_regs *regs)
> {
> - if (riscv_v_vstate_query(regs)) {
> + if (riscv_v_vstate_query(regs))
> set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE);
> - riscv_v_vstate_on(regs);
> - }
> }
>
> #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
> --
> 2.25.1
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
Cheers,
Andy
More information about the linux-riscv
mailing list