[RFC PATCH] riscv: clarify vector state semantics on syscall and context switch

daichengrong daichengrong at iscas.ac.cn
Thu May 7 18:42:44 PDT 2026



On 3/19/26 15:37, 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.
> 
> 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);
> +		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

Hi all,

Just a gentle ping on this patch.

I would also like to add some additional motivation from the RISC-V vector spec, which may help clarify the rationale behind this change.

The spec states:

During a context restore, the context need only be loaded from
memory if the status is Clean (it should never be Dirty at restore).
If the status is Initial, the context must be set to an initial
constant value on context restore to avoid a security hole, but
this can be done without accessing memory.

This indicates that the architectural Initial vector state is treated
specially during restore: instead of reloading vector register contents
from memory, the state can be restored by resetting it to the defined
initial value.

The motivation of this patch is related to this behavior. Allowing
userspace to explicitly release vector state when it is no longer needed
may help reduce unnecessary vector context restore overhead on later
context switches. It may also help avoid repeatedly reinitializing the
vector state when applications frequently enter and exit syscalls without
actually requiring vector state preservation across those transitions.

The original RFC discussion and motivation can be found here:

https://lists.infradead.org/pipermail/linux-riscv/2026-March/087678.html

If there are other preferred or more suitable mechanisms for allowing
userspace to voluntarily relinquish ownership/control of vector state,
I would also be very interested in further suggestions or discussion.

Thanks.




More information about the linux-riscv mailing list