Random corruption on SpacemiT K1 (and K3) with RVV

Vivian Wang wangruikang at iscas.ac.cn
Mon Sep 28 21:07:44 PDT 2026


On 9/28/26 12:32, Aurelien Jarno wrote:
> Hi,
>
> On 2026-09-25 06:40, Aurelien Jarno wrote:
>
> [...]
>
> That said Han Gao pointed me to this patch:
> https://lore.kernel.org/linux-riscv/20260807-vector_fpu_regs_status_rmw_fix-v1-1-0c16848b60db@intel.com/
>
> I have been testing it, and so far it seems to fix my issue with both 
> CONFIG_RISCV_ISA_V_PREEMPTIVE enable and disabled. Or maybe it just 
> hides the issue by changing the timing, as at this point, I haven't 
> fully understood how the bug fixed by this patch can completely explain 
> my observations.

I don't know how that would cause what you have observed either, but it
does superficially appears to fix a real bug.

> Unfortunately, I have been able to reproduce the issue, even with this 
> patch applied. It just significantly reduces the frequency of the issue.
>
But this, I suppose, is still useful information that we just *might* be
on the right track.

Can you perhaps try this hacked together patch below and see if it does
anything? I just put guard(preempt)() or something around a bunch of
places I could find that access regs->status. It should apply to 7.1 and
7.2 as is. (The coding style is deliberately horrible to minimize diff
lines and discourage others from shipping it)

(This adds some more widely-scoped guards, and AFAICT /replaces/ the
above linked patch from Guobin Zhang.)

vvv DO NOT USE EXCEPT FOR TESTING vvv

diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 04f10a949066..6486f9fe0ac5 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -6,6 +6,7 @@
 #ifndef _ASM_RISCV_SWITCH_TO_H
 #define _ASM_RISCV_SWITCH_TO_H
 
+#include <linux/cleanup.h>
 #include <linux/jump_label.h>
 #include <linux/sched/task_stack.h>
 #include <linux/mm_types.h>
@@ -28,12 +29,14 @@ static inline void __fstate_clean(struct pt_regs *regs)
 static inline void fstate_off(struct task_struct *task,
 			      struct pt_regs *regs)
 {
+	guard(preempt)();
 	regs->status = (regs->status & ~SR_FS) | SR_FS_OFF;
 }
 
 static inline void fstate_save(struct task_struct *task,
 			       struct pt_regs *regs)
 {
+	guard(preempt)();
 	if ((regs->status & SR_FS) == SR_FS_DIRTY) {
 		__fstate_save(task);
 		__fstate_clean(regs);
@@ -43,6 +46,7 @@ static inline void fstate_save(struct task_struct *task,
 static inline void fstate_restore(struct task_struct *task,
 				  struct pt_regs *regs)
 {
+	guard(preempt)();
 	if ((regs->status & SR_FS) != SR_FS_OFF) {
 		__fstate_restore(task);
 		__fstate_clean(regs);
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index fffe72a77208..30fc51713542 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -97,11 +97,13 @@ static inline void __riscv_v_vstate_dirty(struct pt_regs *regs)
 
 static inline void riscv_v_vstate_off(struct pt_regs *regs)
 {
+	guard(preempt)();
 	regs->status = __riscv_v_vstate_or(regs->status, OFF);
 }
 
 static inline void riscv_v_vstate_on(struct pt_regs *regs)
 {
+	guard(preempt)();
 	regs->status = __riscv_v_vstate_or(regs->status, INITIAL);
 }
 
@@ -302,6 +304,7 @@ static inline void __riscv_v_vstate_discard(void)
 
 static inline void riscv_v_vstate_discard(struct pt_regs *regs)
 {
+	guard(preempt)();
 	if (riscv_v_vstate_query(regs)) {
 		__riscv_v_vstate_discard();
 		__riscv_v_vstate_dirty(regs);
@@ -311,6 +314,7 @@ static inline void riscv_v_vstate_discard(struct pt_regs *regs)
 static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
 				       struct pt_regs *regs)
 {
+	guard(preempt)();
 	if (__riscv_v_vstate_check(regs->status, DIRTY)) {
 		__riscv_v_vstate_save(vstate, vstate->datap);
 		__riscv_v_vstate_clean(regs);
@@ -320,6 +324,7 @@ 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)
 {
+	guard(preempt)();
 	if (riscv_v_vstate_query(regs)) {
 		__riscv_v_vstate_restore(vstate, vstate->datap);
 		__riscv_v_vstate_clean(regs);
@@ -329,6 +334,7 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
 static inline void riscv_v_vstate_set_restore(struct task_struct *task,
 					      struct pt_regs *regs)
 {
+	guard(preempt)();
 	if (riscv_v_vstate_query(regs)) {
 		set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE);
 		riscv_v_vstate_on(regs);
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a..45963c7baebe 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -144,6 +144,7 @@ early_initcall(compat_mode_detect);
 void start_thread(struct pt_regs *regs, unsigned long pc,
 	unsigned long sp)
 {
+	guard(preempt)();
 	regs->status = SR_PIE;
 	if (has_fpu()) {
 		regs->status |= SR_FS_INITIAL;
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 59784dc117e4..623cc35d567c 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2012 Regents of the University of California
  */
 
+#include <linux/cleanup.h>
 #include <linux/compat.h>
 #include <linux/signal.h>
 #include <linux/uaccess.h>
@@ -76,6 +77,7 @@ static long save_v_state(struct pt_regs *regs, void __user *sc_vec)
 	void __user *datap;
 	long err;
 
+	scoped_guard(preempt)
 	if (!IS_ENABLED(CONFIG_RISCV_ISA_V) ||
 	    !((has_vector() || has_xtheadvector()) &&
 	    riscv_v_vstate_query(regs)))
@@ -287,6 +289,7 @@ static size_t get_rt_frame_size(bool cal_all)
 	frame_size = sizeof(*frame);
 
 	if (has_vector() || has_xtheadvector()) {
+		scoped_guard(preempt)
 		if (cal_all || riscv_v_vstate_query(task_pt_regs(current)))
 			total_context_size += riscv_v_sc_size;
 	}
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index b112166d51e9..27078b70b65b 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2023 SiFive
  * Author: Andy Chiu <andy.chiu at sifive.com>
  */
+#include <linux/cleanup.h>
 #include <linux/export.h>
 #include <linux/sched/signal.h>
 #include <linux/types.h>
@@ -194,6 +195,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
 	if (!riscv_v_vstate_ctrl_user_allowed())
 		return false;
 
+	scoped_guard(preempt)
 	/* If V has been enabled then it is not the first-use trap */
 	if (riscv_v_vstate_query(regs))
 		return false;

^^^ DO NOT USE EXCEPT FOR TESTING ^^^




More information about the linux-riscv mailing list