Linux-RISC-V Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] riscv: Optimize signal handling with sum enabled accesses
@ 2025-12-02  7:43 maohan4761
  2025-12-02  7:43 ` [PATCH 1/1] " maohan4761
  0 siblings, 1 reply; 3+ messages in thread
From: maohan4761 @ 2025-12-02  7:43 UTC (permalink / raw)
  To: pjw, palmer; +Cc: guoren, linux-riscv, linux-kernel, Mao Han

From: Mao Han <han_mao@linux.alibaba.com>

Currently, the signal function frequently toggles the SUM bit to control
user-space access within __get_user/__put_user.

        void __user *sc_ext_ptr = &sc->sc_extdesc.hdr;
ffffffff80005904:       44898a13                addi    s4,s3,1096
                err |= __get_user(magic, &head->magic);
ffffffff80005908:       8752                    mv      a4,s4
ffffffff8000590a:       00000013                nop
ffffffff8000590e:       1004a073                csrs    sstatus,s1
ffffffff80005912:       4781                    li      a5,0
ffffffff80005914:       4310                    lw      a2,0(a4)
ffffffff80005916:       2601                    sext.w  a2,a2
ffffffff80005918:       1004b073                csrc    sstatus,s1
                err |= __get_user(size, &head->size);
ffffffff8000591c:       004a0693                addi    a3,s4,4
ffffffff80005920:       00000013                nop
ffffffff80005924:       1004a073                csrs    sstatus,s1
ffffffff80005928:       4701                    li      a4,0
ffffffff8000592a:       428c                    lw      a1,0(a3)
ffffffff8000592c:       86ae                    mv      a3,a1
ffffffff8000592e:       2581                    sext.w  a1,a1
ffffffff80005930:       1004b073                csrc    sstatus,s1
ffffffff80005934:       8fd9                    or      a5,a5,a4

On modern out-of-order processors, frequent CSR (Control and Status Register)
operations introduce pipeline stalls, significantly degrading performance.

This patch attempts to enable the SUM bit only once at the beginning of
rt_sigreturn and setup_rt_frame, keep it enabled throughout frame handling,
and directly access user-space memory without repeatedly toggling the SUM bit.
This reduces the overhead caused by frequent CSR state changes.

Lmbench signal-related benchmarks show approximately a 20% performance improvement.

Mao Han (1):
  riscv: Optimize signal handling with sum enabled accesses

 arch/riscv/include/asm/uaccess.h | 75 ++++++++++++++++++++++++++++++++
 arch/riscv/kernel/signal.c       | 74 +++++++++++++++++++------------
 2 files changed, 121 insertions(+), 28 deletions(-)

-- 
2.25.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/1] riscv: Optimize signal handling with sum enabled accesses
  2025-12-02  7:43 [PATCH 0/1] riscv: Optimize signal handling with sum enabled accesses maohan4761
@ 2025-12-02  7:43 ` maohan4761
  2025-12-03 20:10   ` kernel test robot
  0 siblings, 1 reply; 3+ messages in thread
From: maohan4761 @ 2025-12-02  7:43 UTC (permalink / raw)
  To: pjw, palmer; +Cc: guoren, linux-riscv, linux-kernel, Mao Han

From: Mao Han <han_mao@linux.alibaba.com>

Introduce new __get_user_sum_enabled() and __put_user_sum_enabled() macros
in uaccess.h that perform user-space accesses assuming the SUM bit is
already enabled.

Explicitly manage SUM state around bulk user copies in rt_sigreturn() and
setup_rt_frame() by bracketing sequences of SUM-enabled operations with
a single pair of __enable_user_access() / __disable_user_access(), reducing
the number of CSR writes and improving performance. All callers ensure
access_ok() checks are performed for the signal frame.

Signed-off-by: Mao Han <han_mao@linux.alibaba.com>
---
 arch/riscv/include/asm/uaccess.h | 75 ++++++++++++++++++++++++++++++++
 arch/riscv/kernel/signal.c       | 74 +++++++++++++++++++------------
 2 files changed, 121 insertions(+), 28 deletions(-)

diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
index f5f4f7f..78f8a21 100644
--- a/arch/riscv/include/asm/uaccess.h
+++ b/arch/riscv/include/asm/uaccess.h
@@ -213,6 +213,43 @@ __gu_failed:								\
 		err = -EFAULT;						\
 } while (0)
 
+/**
+ * __get_user_sum_enabled - Get a simple variable from user space,
+ * assuming user access is already enabled (SUM bit enabled).
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This macro does NOT sleep.
+ *
+ * This variant of __get_user assumes that the CPU is already in a state
+ * where user-space addresses can be accessed directly from kernel mode.
+ * Therefore, it omits the __enable_user_access() / __disable_user_access()
+ * calls.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller MUST ensure:
+ *   - access_ok(ptr, sizeof(*ptr)) has been verified.
+ *   - The execution context permits direct user-space reads.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user_sum_enabled(x, ptr)                          \
+({                                                              \
+	const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
+	long __gu_err = 0;                                      \
+	__typeof__(x) __gu_val = (__typeof__(x))0;              \
+								\
+	__chk_user_ptr(__gu_ptr);                               \
+								\
+	__get_user_error(__gu_val, __gu_ptr, __gu_err);         \
+								\
+	(x) = __gu_val;                                         \
+	__gu_err;                                               \
+})
+
 /**
  * __get_user: - Get a simple variable from user space, with less checking.
  * @x:   Variable to store result.
@@ -343,6 +380,44 @@ err_label:							\
 	(err) = -EFAULT;					\
 } while (0)
 
+
+/**
+ * __put_user_sum_enabled - Write a simple value into user space,
+ * assuming user access is already enabled (SUM bit enabled).
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This macro does NOT sleep.
+ *
+ * This variant of __put_user_sum_enabled assumes that the CPU is already
+ * in a state where user-space addresses can be accessed directly from
+ * kernel mode. Therefore, it omits the
+ * __enable_user_access() / __disable_user_access() calls.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr. The value of @x is copied to avoid
+ * re-ordering where @x is evaluated inside the block that enables user-space
+ * access (thus bypassing user space protection if @x is a function).
+ *
+ * Caller MUST ensure:
+ *   - access_ok(ptr, sizeof(*ptr)) has been verified.
+ *   - The execution context permits direct user-space writes.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user_sum_enabled(x, ptr)                          \
+({                                                              \
+	__typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
+	__typeof__(*__gu_ptr) __val = (x);                      \
+	long __pu_err = 0;                                      \
+								\
+	__chk_user_ptr(__gu_ptr);                               \
+								\
+	__put_user_error(__val, __gu_ptr, __pu_err);            \
+								\
+	__pu_err;                                               \
+})
+
 /**
  * __put_user: - Write a simple value into user space, with less checking.
  * @x:   Value to copy to user space.
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 08378fe..a4a9395 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -45,7 +45,7 @@ static long restore_fp_state(struct pt_regs *regs,
 	long err;
 	struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
 
-	err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
+	err = __asm_copy_from_user_sum_enabled(&current->thread.fstate, state, sizeof(*state));
 	if (unlikely(err))
 		return err;
 
@@ -60,7 +60,7 @@ static long save_fp_state(struct pt_regs *regs,
 	struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
 
 	fstate_save(current, regs);
-	err = __copy_to_user(state, &current->thread.fstate, sizeof(*state));
+	err = __asm_copy_to_user_sum_enabled(state, &current->thread.fstate, sizeof(*state));
 	return err;
 }
 #else
@@ -91,15 +91,15 @@ static long save_v_state(struct pt_regs *regs, void __user **sc_vec)
 	put_cpu_vector_context();
 
 	/* Copy everything of vstate but datap. */
-	err = __copy_to_user(&state->v_state, &current->thread.vstate,
-			     offsetof(struct __riscv_v_ext_state, datap));
+	err = __asm_copy_to_user_sum_enabled(&state->v_state, &current->thread.vstate,
+					offsetof(struct __riscv_v_ext_state, datap));
 	/* Copy the pointer datap itself. */
-	err |= __put_user((__force void *)datap, &state->v_state.datap);
+	err |= __put_user_sum_enabled((__force void *)datap, &state->v_state.datap);
 	/* Copy the whole vector content to user space datap. */
-	err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize);
+	err |= __asm_copy_to_user_sum_enabled(datap, current->thread.vstate.datap, riscv_v_vsize);
 	/* Copy magic to the user space after saving  all vector conetext */
-	err |= __put_user(RISCV_V_MAGIC, &hdr->magic);
-	err |= __put_user(riscv_v_sc_size, &hdr->size);
+	err |= __put_user_sum_enabled(RISCV_V_MAGIC, &hdr->magic);
+	err |= __put_user_sum_enabled(riscv_v_sc_size, &hdr->size);
 	if (unlikely(err))
 		return err;
 
@@ -127,20 +127,20 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
 	riscv_v_vstate_set_restore(current, regs);
 
 	/* Copy everything of __sc_riscv_v_state except datap. */
-	err = __copy_from_user(&current->thread.vstate, &state->v_state,
-			       offsetof(struct __riscv_v_ext_state, datap));
+	err = __asm_copy_from_user_sum_enabled(&current->thread.vstate, &state->v_state,
+					offsetof(struct __riscv_v_ext_state, datap));
 	if (unlikely(err))
 		return err;
 
 	/* Copy the pointer datap itself. */
-	err = __get_user(datap, &state->v_state.datap);
+	err = __get_user_sum_enabled(datap, &state->v_state.datap);
 	if (unlikely(err))
 		return err;
 	/*
 	 * Copy the whole vector content from user space datap. Use
 	 * copy_from_user to prevent information leak.
 	 */
-	return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize);
+	return __asm_copy_from_user_sum_enabled(current->thread.vstate.datap, datap, riscv_v_vsize);
 }
 #else
 #define save_v_state(task, regs) (0)
@@ -154,7 +154,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 	__u32 rsvd;
 	long err;
 	/* sc_regs is structured the same as the start of pt_regs */
-	err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
+	err = __asm_copy_from_user_sum_enabled(regs, &sc->sc_regs, sizeof(sc->sc_regs));
 	if (unlikely(err))
 		return err;
 
@@ -166,7 +166,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 	}
 
 	/* Check the reserved word before extensions parsing */
-	err = __get_user(rsvd, &sc->sc_extdesc.reserved);
+	err = __get_user_sum_enabled(rsvd, &sc->sc_extdesc.reserved);
 	if (unlikely(err))
 		return err;
 	if (unlikely(rsvd))
@@ -176,8 +176,8 @@ static long restore_sigcontext(struct pt_regs *regs,
 		__u32 magic, size;
 		struct __riscv_ctx_hdr __user *head = sc_ext_ptr;
 
-		err |= __get_user(magic, &head->magic);
-		err |= __get_user(size, &head->size);
+		err |= __get_user_sum_enabled(magic, &head->magic);
+		err |= __get_user_sum_enabled(size, &head->size);
 		if (unlikely(err))
 			return err;
 
@@ -238,7 +238,8 @@ SYSCALL_DEFINE0(rt_sigreturn)
 	if (!access_ok(frame, frame_size))
 		goto badframe;
 
-	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+	__enable_user_access();
+	if (__asm_copy_from_user_sum_enabled(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
 
 	set_current_blocked(&set);
@@ -248,12 +249,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
 
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
+	__disable_user_access();
 
 	regs->cause = -1UL;
 
 	return regs->a0;
 
 badframe:
+	__disable_user_access();
 	task = current;
 	if (show_unhandled_signals) {
 		pr_info_ratelimited(
@@ -273,7 +276,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	long err;
 
 	/* sc_regs is structured the same as the start of pt_regs */
-	err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
+	err = __asm_copy_to_user_sum_enabled(&sc->sc_regs, regs, sizeof(sc->sc_regs));
 	/* Save the floating-point state. */
 	if (has_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
@@ -281,10 +284,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	if ((has_vector() || has_xtheadvector()) && riscv_v_vstate_query(regs))
 		err |= save_v_state(regs, (void __user **)&sc_ext_ptr);
 	/* Write zero to fp-reserved space and check it on restore_sigcontext */
-	err |= __put_user(0, &sc->sc_extdesc.reserved);
+	err |= __put_user_sum_enabled(0, &sc->sc_extdesc.reserved);
 	/* And put END __riscv_ctx_hdr at the end. */
-	err |= __put_user(END_MAGIC, &sc_ext_ptr->magic);
-	err |= __put_user(END_HDR_SIZE, &sc_ext_ptr->size);
+	err |= __put_user_sum_enabled(END_MAGIC, &sc_ext_ptr->magic);
+	err |= __put_user_sum_enabled(END_HDR_SIZE, &sc_ext_ptr->size);
 
 	return err;
 }
@@ -312,6 +315,15 @@ static inline void __user *get_sigframe(struct ksignal *ksig,
 	return (void __user *)sp;
 }
 
+static int __save_altstack_sum_enabled(stack_t __user *uss, unsigned long sp)
+{
+	struct task_struct *t = current;
+	int err = __put_user_sum_enabled((void __user *)t->sas_ss_sp, &uss->ss_sp) |
+		__put_user_sum_enabled(t->sas_ss_flags, &uss->ss_flags) |
+		__put_user_sum_enabled(t->sas_ss_size, &uss->ss_size);
+	return err;
+}
+
 static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 	struct pt_regs *regs)
 {
@@ -327,13 +339,16 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 
 	/* Create the ucontext. */
-	err |= __put_user(0, &frame->uc.uc_flags);
-	err |= __put_user(NULL, &frame->uc.uc_link);
-	err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+	__enable_user_access();
+	err |= __put_user_sum_enabled(0, &frame->uc.uc_flags);
+	err |= __put_user_sum_enabled(NULL, &frame->uc.uc_link);
+	err |= __save_altstack_sum_enabled(&frame->uc.uc_stack, regs->sp);
 	err |= setup_sigcontext(frame, regs);
-	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-	if (err)
+	err |= __asm_copy_to_user_sum_enabled(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err) {
+		__disable_user_access();
 		return -EFAULT;
+	}
 
 	/* Set up to return from userspace. */
 #ifdef CONFIG_MMU
@@ -344,9 +359,12 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 	 * For the nommu case we don't have a VDSO.  Instead we push two
 	 * instructions to call the rt_sigreturn syscall onto the user stack.
 	 */
-	if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn,
-			 sizeof(frame->sigreturn_code)))
+	if (__asm_copy_to_user_sum_enabled(&frame->sigreturn_code, __user_rt_sigreturn,
+					sizeof(frame->sigreturn_code))) {
+		__disable_user_access();
 		return -EFAULT;
+	}
+	__disable_user_access();
 
 	addr = (unsigned long)&frame->sigreturn_code;
 	/* Make sure the two instructions are pushed to icache. */
-- 
2.25.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/1] riscv: Optimize signal handling with sum enabled accesses
  2025-12-02  7:43 ` [PATCH 1/1] " maohan4761
@ 2025-12-03 20:10   ` kernel test robot
  0 siblings, 0 replies; 3+ messages in thread
From: kernel test robot @ 2025-12-03 20:10 UTC (permalink / raw)
  To: maohan4761, pjw, palmer
  Cc: oe-kbuild-all, guoren, linux-riscv, linux-kernel, Mao Han

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.18]
[cannot apply to next-20251203]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/maohan4761-gmail-com/riscv-Optimize-signal-handling-with-sum-enabled-accesses/20251202-154643
base:   linus/master
patch link:    https://lore.kernel.org/r/20251202074303.81485-2-maohan4761%40gmail.com
patch subject: [PATCH 1/1] riscv: Optimize signal handling with sum enabled accesses
config: riscv-nommu_k210_sdcard_defconfig (https://download.01.org/0day-ci/archive/20251204/202512040335.j2VwCIKL-lkp@intel.com/config)
compiler: riscv64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251204/202512040335.j2VwCIKL-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512040335.j2VwCIKL-lkp@intel.com/

All errors (new ones prefixed by >>):

   arch/riscv/kernel/signal.c: In function 'restore_fp_state':
>> arch/riscv/kernel/signal.c:48:15: error: implicit declaration of function '__asm_copy_from_user_sum_enabled' [-Wimplicit-function-declaration]
      48 |         err = __asm_copy_from_user_sum_enabled(&current->thread.fstate, state, sizeof(*state));
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/riscv/kernel/signal.c: In function 'save_fp_state':
>> arch/riscv/kernel/signal.c:63:15: error: implicit declaration of function '__asm_copy_to_user_sum_enabled' [-Wimplicit-function-declaration]
      63 |         err = __asm_copy_to_user_sum_enabled(state, &current->thread.fstate, sizeof(*state));
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/riscv/kernel/signal.c: In function 'save_v_state':
>> arch/riscv/kernel/signal.c:97:16: error: implicit declaration of function '__put_user_sum_enabled' [-Wimplicit-function-declaration]
      97 |         err |= __put_user_sum_enabled((__force void *)datap, &state->v_state.datap);
         |                ^~~~~~~~~~~~~~~~~~~~~~
   arch/riscv/kernel/signal.c: In function '__restore_v_state':
>> arch/riscv/kernel/signal.c:136:15: error: implicit declaration of function '__get_user_sum_enabled' [-Wimplicit-function-declaration]
     136 |         err = __get_user_sum_enabled(datap, &state->v_state.datap);
         |               ^~~~~~~~~~~~~~~~~~~~~~
   arch/riscv/kernel/signal.c: In function '__riscv_sys_rt_sigreturn':
>> arch/riscv/kernel/signal.c:241:9: error: implicit declaration of function '__enable_user_access' [-Wimplicit-function-declaration]
     241 |         __enable_user_access();
         |         ^~~~~~~~~~~~~~~~~~~~
>> arch/riscv/kernel/signal.c:252:9: error: implicit declaration of function '__disable_user_access' [-Wimplicit-function-declaration]
     252 |         __disable_user_access();
         |         ^~~~~~~~~~~~~~~~~~~~~


vim +/__asm_copy_from_user_sum_enabled +48 arch/riscv/kernel/signal.c

    40	
    41	#ifdef CONFIG_FPU
    42	static long restore_fp_state(struct pt_regs *regs,
    43				     union __riscv_fp_state __user *sc_fpregs)
    44	{
    45		long err;
    46		struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
    47	
  > 48		err = __asm_copy_from_user_sum_enabled(&current->thread.fstate, state, sizeof(*state));
    49		if (unlikely(err))
    50			return err;
    51	
    52		fstate_restore(current, regs);
    53		return 0;
    54	}
    55	
    56	static long save_fp_state(struct pt_regs *regs,
    57				  union __riscv_fp_state __user *sc_fpregs)
    58	{
    59		long err;
    60		struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
    61	
    62		fstate_save(current, regs);
  > 63		err = __asm_copy_to_user_sum_enabled(state, &current->thread.fstate, sizeof(*state));
    64		return err;
    65	}
    66	#else
    67	#define save_fp_state(task, regs) (0)
    68	#define restore_fp_state(task, regs) (0)
    69	#endif
    70	
    71	#ifdef CONFIG_RISCV_ISA_V
    72	
    73	static long save_v_state(struct pt_regs *regs, void __user **sc_vec)
    74	{
    75		struct __riscv_ctx_hdr __user *hdr;
    76		struct __sc_riscv_v_state __user *state;
    77		void __user *datap;
    78		long err;
    79	
    80		hdr = *sc_vec;
    81		/* Place state to the user's signal context space after the hdr */
    82		state = (struct __sc_riscv_v_state __user *)(hdr + 1);
    83		/* Point datap right after the end of __sc_riscv_v_state */
    84		datap = state + 1;
    85	
    86		/* datap is designed to be 16 byte aligned for better performance */
    87		WARN_ON(!IS_ALIGNED((unsigned long)datap, 16));
    88	
    89		get_cpu_vector_context();
    90		riscv_v_vstate_save(&current->thread.vstate, regs);
    91		put_cpu_vector_context();
    92	
    93		/* Copy everything of vstate but datap. */
    94		err = __asm_copy_to_user_sum_enabled(&state->v_state, &current->thread.vstate,
    95						offsetof(struct __riscv_v_ext_state, datap));
    96		/* Copy the pointer datap itself. */
  > 97		err |= __put_user_sum_enabled((__force void *)datap, &state->v_state.datap);
    98		/* Copy the whole vector content to user space datap. */
    99		err |= __asm_copy_to_user_sum_enabled(datap, current->thread.vstate.datap, riscv_v_vsize);
   100		/* Copy magic to the user space after saving  all vector conetext */
   101		err |= __put_user_sum_enabled(RISCV_V_MAGIC, &hdr->magic);
   102		err |= __put_user_sum_enabled(riscv_v_sc_size, &hdr->size);
   103		if (unlikely(err))
   104			return err;
   105	
   106		/* Only progress the sv_vec if everything has done successfully  */
   107		*sc_vec += riscv_v_sc_size;
   108		return 0;
   109	}
   110	
   111	/*
   112	 * Restore Vector extension context from the user's signal frame. This function
   113	 * assumes a valid extension header. So magic and size checking must be done by
   114	 * the caller.
   115	 */
   116	static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
   117	{
   118		long err;
   119		struct __sc_riscv_v_state __user *state = sc_vec;
   120		void __user *datap;
   121	
   122		/*
   123		 * Mark the vstate as clean prior performing the actual copy,
   124		 * to avoid getting the vstate incorrectly clobbered by the
   125		 *  discarded vector state.
   126		 */
   127		riscv_v_vstate_set_restore(current, regs);
   128	
   129		/* Copy everything of __sc_riscv_v_state except datap. */
   130		err = __asm_copy_from_user_sum_enabled(&current->thread.vstate, &state->v_state,
   131						offsetof(struct __riscv_v_ext_state, datap));
   132		if (unlikely(err))
   133			return err;
   134	
   135		/* Copy the pointer datap itself. */
 > 136		err = __get_user_sum_enabled(datap, &state->v_state.datap);
   137		if (unlikely(err))
   138			return err;
   139		/*
   140		 * Copy the whole vector content from user space datap. Use
   141		 * copy_from_user to prevent information leak.
   142		 */
   143		return __asm_copy_from_user_sum_enabled(current->thread.vstate.datap, datap, riscv_v_vsize);
   144	}
   145	#else
   146	#define save_v_state(task, regs) (0)
   147	#define __restore_v_state(task, regs) (0)
   148	#endif
   149	
   150	static long restore_sigcontext(struct pt_regs *regs,
   151		struct sigcontext __user *sc)
   152	{
   153		void __user *sc_ext_ptr = &sc->sc_extdesc.hdr;
   154		__u32 rsvd;
   155		long err;
   156		/* sc_regs is structured the same as the start of pt_regs */
   157		err = __asm_copy_from_user_sum_enabled(regs, &sc->sc_regs, sizeof(sc->sc_regs));
   158		if (unlikely(err))
   159			return err;
   160	
   161		/* Restore the floating-point state. */
   162		if (has_fpu()) {
   163			err = restore_fp_state(regs, &sc->sc_fpregs);
   164			if (unlikely(err))
   165				return err;
   166		}
   167	
   168		/* Check the reserved word before extensions parsing */
   169		err = __get_user_sum_enabled(rsvd, &sc->sc_extdesc.reserved);
   170		if (unlikely(err))
   171			return err;
   172		if (unlikely(rsvd))
   173			return -EINVAL;
   174	
   175		while (!err) {
   176			__u32 magic, size;
   177			struct __riscv_ctx_hdr __user *head = sc_ext_ptr;
   178	
   179			err |= __get_user_sum_enabled(magic, &head->magic);
   180			err |= __get_user_sum_enabled(size, &head->size);
   181			if (unlikely(err))
   182				return err;
   183	
   184			sc_ext_ptr += sizeof(*head);
   185			switch (magic) {
   186			case END_MAGIC:
   187				if (size != END_HDR_SIZE)
   188					return -EINVAL;
   189	
   190				return 0;
   191			case RISCV_V_MAGIC:
   192				if (!(has_vector() || has_xtheadvector()) || !riscv_v_vstate_query(regs) ||
   193				    size != riscv_v_sc_size)
   194					return -EINVAL;
   195	
   196				err = __restore_v_state(regs, sc_ext_ptr);
   197				break;
   198			default:
   199				return -EINVAL;
   200			}
   201			sc_ext_ptr = (void __user *)head + size;
   202		}
   203		return err;
   204	}
   205	
   206	static size_t get_rt_frame_size(bool cal_all)
   207	{
   208		struct rt_sigframe __user *frame;
   209		size_t frame_size;
   210		size_t total_context_size = 0;
   211	
   212		frame_size = sizeof(*frame);
   213	
   214		if (has_vector() || has_xtheadvector()) {
   215			if (cal_all || riscv_v_vstate_query(task_pt_regs(current)))
   216				total_context_size += riscv_v_sc_size;
   217		}
   218	
   219		frame_size += total_context_size;
   220	
   221		frame_size = round_up(frame_size, 16);
   222		return frame_size;
   223	}
   224	
   225	SYSCALL_DEFINE0(rt_sigreturn)
   226	{
   227		struct pt_regs *regs = current_pt_regs();
   228		struct rt_sigframe __user *frame;
   229		struct task_struct *task;
   230		sigset_t set;
   231		size_t frame_size = get_rt_frame_size(false);
   232	
   233		/* Always make any pending restarted system calls return -EINTR */
   234		current->restart_block.fn = do_no_restart_syscall;
   235	
   236		frame = (struct rt_sigframe __user *)regs->sp;
   237	
   238		if (!access_ok(frame, frame_size))
   239			goto badframe;
   240	
 > 241		__enable_user_access();
   242		if (__asm_copy_from_user_sum_enabled(&set, &frame->uc.uc_sigmask, sizeof(set)))
   243			goto badframe;
   244	
   245		set_current_blocked(&set);
   246	
   247		if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
   248			goto badframe;
   249	
   250		if (restore_altstack(&frame->uc.uc_stack))
   251			goto badframe;
   252		__disable_user_access();
   253	
   254		regs->cause = -1UL;
   255	
   256		return regs->a0;
   257	
   258	badframe:
   259		__disable_user_access();
   260		task = current;
   261		if (show_unhandled_signals) {
   262			pr_info_ratelimited(
   263				"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
   264				task->comm, task_pid_nr(task), __func__,
   265				frame, (void *)regs->epc, (void *)regs->sp);
   266		}
   267		force_sig(SIGSEGV);
   268		return 0;
   269	}
   270	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-12-03 20:11 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-02  7:43 [PATCH 0/1] riscv: Optimize signal handling with sum enabled accesses maohan4761
2025-12-02  7:43 ` [PATCH 1/1] " maohan4761
2025-12-03 20:10   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox