[patch V2 29/37] entry: Split up exit_to_user_mode_prepare()

Thomas Gleixner posted 37 patches 1 month, 1 week ago
There is a newer version of this series
[patch V2 29/37] entry: Split up exit_to_user_mode_prepare()
Posted by Thomas Gleixner 1 month, 1 week ago
exit_to_user_mode_prepare() is used for both interrupts and syscalls, but
there is extra rseq work, which is only required for in the interrupt exit
case.

Split up the function and provide wrappers for syscalls and interrupts,
which allows to seperate the rseq exit work in the next step.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/entry-common.h     |    2 -
 include/linux/irq-entry-common.h |   42 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 38 insertions(+), 6 deletions(-)

--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -156,7 +156,7 @@ static __always_inline void syscall_exit
 	if (unlikely(work & SYSCALL_WORK_EXIT))
 		syscall_exit_work(regs, work);
 	local_irq_disable_exit_to_user();
-	exit_to_user_mode_prepare(regs);
+	syscall_exit_to_user_mode_prepare(regs);
 }
 
 /**
--- a/include/linux/irq-entry-common.h
+++ b/include/linux/irq-entry-common.h
@@ -201,7 +201,7 @@ void arch_do_signal_or_restart(struct pt
 unsigned long exit_to_user_mode_loop(struct pt_regs *regs, unsigned long ti_work);
 
 /**
- * exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
+ * __exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
  * @regs:	Pointer to pt_regs on entry stack
  *
  * 1) check that interrupts are disabled
@@ -209,8 +209,10 @@ unsigned long exit_to_user_mode_loop(str
  * 3) call exit_to_user_mode_loop() if any flags from
  *    EXIT_TO_USER_MODE_WORK are set
  * 4) check that interrupts are still disabled
+ *
+ * Don't invoke directly, use the syscall/irqentry_ prefixed variants below
  */
-static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
+static __always_inline void __exit_to_user_mode_prepare(struct pt_regs *regs)
 {
 	unsigned long ti_work;
 
@@ -224,15 +226,45 @@ static __always_inline void exit_to_user
 		ti_work = exit_to_user_mode_loop(regs, ti_work);
 
 	arch_exit_to_user_mode_prepare(regs, ti_work);
+}
 
-	rseq_exit_to_user_mode();
-
+static __always_inline void __exit_to_user_mode_validate(void)
+{
 	/* Ensure that kernel state is sane for a return to userspace */
 	kmap_assert_nomap();
 	lockdep_assert_irqs_disabled();
 	lockdep_sys_exit();
 }
 
+
+/**
+ * syscall_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
+ * @regs:	Pointer to pt_regs on entry stack
+ *
+ * Wrapper around __exit_to_user_mode_prepare() to seperate the exit work for
+ * syscalls and interrupts.
+ */
+static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
+{
+	__exit_to_user_mode_prepare(regs);
+	rseq_exit_to_user_mode();
+	__exit_to_user_mode_validate();
+}
+
+/**
+ * irqentry_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
+ * @regs:	Pointer to pt_regs on entry stack
+ *
+ * Wrapper around __exit_to_user_mode_prepare() to seperate the exit work for
+ * syscalls and interrupts.
+ */
+static __always_inline void irqentry_exit_to_user_mode_prepare(struct pt_regs *regs)
+{
+	__exit_to_user_mode_prepare(regs);
+	rseq_exit_to_user_mode();
+	__exit_to_user_mode_validate();
+}
+
 /**
  * exit_to_user_mode - Fixup state when exiting to user mode
  *
@@ -297,7 +329,7 @@ static __always_inline void irqentry_ent
 static __always_inline void irqentry_exit_to_user_mode(struct pt_regs *regs)
 {
 	instrumentation_begin();
-	exit_to_user_mode_prepare(regs);
+	irqentry_exit_to_user_mode_prepare(regs);
 	instrumentation_end();
 	exit_to_user_mode();
 }
Re: [patch V2 29/37] entry: Split up exit_to_user_mode_prepare()
Posted by Mathieu Desnoyers 1 month, 1 week ago
On 2025-08-23 12:40, Thomas Gleixner wrote:
> exit_to_user_mode_prepare() is used for both interrupts and syscalls, but
> there is extra rseq work, which is only required for in the interrupt exit
> case.
> 
> Split up the function and provide wrappers for syscalls and interrupts,
> which allows to seperate the rseq exit work in the next step.

separate

> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
>   include/linux/entry-common.h     |    2 -
>   include/linux/irq-entry-common.h |   42 ++++++++++++++++++++++++++++++++++-----
>   2 files changed, 38 insertions(+), 6 deletions(-)
> 
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -156,7 +156,7 @@ static __always_inline void syscall_exit
>   	if (unlikely(work & SYSCALL_WORK_EXIT))
>   		syscall_exit_work(regs, work);
>   	local_irq_disable_exit_to_user();
> -	exit_to_user_mode_prepare(regs);
> +	syscall_exit_to_user_mode_prepare(regs);
>   }
>   
>   /**
> --- a/include/linux/irq-entry-common.h
> +++ b/include/linux/irq-entry-common.h
> @@ -201,7 +201,7 @@ void arch_do_signal_or_restart(struct pt
>   unsigned long exit_to_user_mode_loop(struct pt_regs *regs, unsigned long ti_work);
>   
>   /**
> - * exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
> + * __exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
>    * @regs:	Pointer to pt_regs on entry stack
>    *
>    * 1) check that interrupts are disabled
> @@ -209,8 +209,10 @@ unsigned long exit_to_user_mode_loop(str
>    * 3) call exit_to_user_mode_loop() if any flags from
>    *    EXIT_TO_USER_MODE_WORK are set
>    * 4) check that interrupts are still disabled
> + *
> + * Don't invoke directly, use the syscall/irqentry_ prefixed variants below
>    */
> -static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
> +static __always_inline void __exit_to_user_mode_prepare(struct pt_regs *regs)
>   {
>   	unsigned long ti_work;
>   
> @@ -224,15 +226,45 @@ static __always_inline void exit_to_user
>   		ti_work = exit_to_user_mode_loop(regs, ti_work);
>   
>   	arch_exit_to_user_mode_prepare(regs, ti_work);
> +}
>   
> -	rseq_exit_to_user_mode();
> -
> +static __always_inline void __exit_to_user_mode_validate(void)
> +{
>   	/* Ensure that kernel state is sane for a return to userspace */
>   	kmap_assert_nomap();
>   	lockdep_assert_irqs_disabled();
>   	lockdep_sys_exit();
>   }
>   
> +
> +/**
> + * syscall_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
> + * @regs:	Pointer to pt_regs on entry stack
> + *
> + * Wrapper around __exit_to_user_mode_prepare() to seperate the exit work for

separate

> + * syscalls and interrupts.
> + */
> +static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
> +{
> +	__exit_to_user_mode_prepare(regs);
> +	rseq_exit_to_user_mode();
> +	__exit_to_user_mode_validate();
> +}
> +
> +/**
> + * irqentry_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
> + * @regs:	Pointer to pt_regs on entry stack
> + *
> + * Wrapper around __exit_to_user_mode_prepare() to seperate the exit work for

separate

Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

> + * syscalls and interrupts.
> + */
> +static __always_inline void irqentry_exit_to_user_mode_prepare(struct pt_regs *regs)
> +{
> +	__exit_to_user_mode_prepare(regs);
> +	rseq_exit_to_user_mode();
> +	__exit_to_user_mode_validate();
> +}
> +
>   /**
>    * exit_to_user_mode - Fixup state when exiting to user mode
>    *
> @@ -297,7 +329,7 @@ static __always_inline void irqentry_ent
>   static __always_inline void irqentry_exit_to_user_mode(struct pt_regs *regs)
>   {
>   	instrumentation_begin();
> -	exit_to_user_mode_prepare(regs);
> +	irqentry_exit_to_user_mode_prepare(regs);
>   	instrumentation_end();
>   	exit_to_user_mode();
>   }
> 


-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com