Skip to content

Commit 70fe25a

Browse files
KAGA-KOKOingomolnar
authored andcommitted
entry: Split up exit_to_user_mode_prepare()
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 separate the rseq exit work in the next step. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://patch.msgid.link/20251027084307.782234789@linutronix.de
1 parent 3db6b38 commit 70fe25a

3 files changed

Lines changed: 46 additions & 7 deletions

File tree

arch/arm64/kernel/entry-common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static __always_inline void arm64_enter_from_user_mode(struct pt_regs *regs)
100100
static __always_inline void arm64_exit_to_user_mode(struct pt_regs *regs)
101101
{
102102
local_irq_disable();
103-
exit_to_user_mode_prepare(regs);
103+
exit_to_user_mode_prepare_legacy(regs);
104104
local_daif_mask();
105105
mte_check_tfsr_exit();
106106
exit_to_user_mode();

include/linux/entry-common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
156156
if (unlikely(work & SYSCALL_WORK_EXIT))
157157
syscall_exit_work(regs, work);
158158
local_irq_disable_exit_to_user();
159-
exit_to_user_mode_prepare(regs);
159+
syscall_exit_to_user_mode_prepare(regs);
160160
}
161161

162162
/**

include/linux/irq-entry-common.h

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,16 +201,18 @@ void arch_do_signal_or_restart(struct pt_regs *regs);
201201
unsigned long exit_to_user_mode_loop(struct pt_regs *regs, unsigned long ti_work);
202202

203203
/**
204-
* exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
204+
* __exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
205205
* @regs: Pointer to pt_regs on entry stack
206206
*
207207
* 1) check that interrupts are disabled
208208
* 2) call tick_nohz_user_enter_prepare()
209209
* 3) call exit_to_user_mode_loop() if any flags from
210210
* EXIT_TO_USER_MODE_WORK are set
211211
* 4) check that interrupts are still disabled
212+
*
213+
* Don't invoke directly, use the syscall/irqentry_ prefixed variants below
212214
*/
213-
static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
215+
static __always_inline void __exit_to_user_mode_prepare(struct pt_regs *regs)
214216
{
215217
unsigned long ti_work;
216218

@@ -224,15 +226,52 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
224226
ti_work = exit_to_user_mode_loop(regs, ti_work);
225227

226228
arch_exit_to_user_mode_prepare(regs, ti_work);
229+
}
227230

228-
rseq_exit_to_user_mode();
229-
231+
static __always_inline void __exit_to_user_mode_validate(void)
232+
{
230233
/* Ensure that kernel state is sane for a return to userspace */
231234
kmap_assert_nomap();
232235
lockdep_assert_irqs_disabled();
233236
lockdep_sys_exit();
234237
}
235238

239+
/* Temporary workaround to keep ARM64 alive */
240+
static __always_inline void exit_to_user_mode_prepare_legacy(struct pt_regs *regs)
241+
{
242+
__exit_to_user_mode_prepare(regs);
243+
rseq_exit_to_user_mode();
244+
__exit_to_user_mode_validate();
245+
}
246+
247+
/**
248+
* syscall_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
249+
* @regs: Pointer to pt_regs on entry stack
250+
*
251+
* Wrapper around __exit_to_user_mode_prepare() to separate the exit work for
252+
* syscalls and interrupts.
253+
*/
254+
static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
255+
{
256+
__exit_to_user_mode_prepare(regs);
257+
rseq_exit_to_user_mode();
258+
__exit_to_user_mode_validate();
259+
}
260+
261+
/**
262+
* irqentry_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
263+
* @regs: Pointer to pt_regs on entry stack
264+
*
265+
* Wrapper around __exit_to_user_mode_prepare() to separate the exit work for
266+
* syscalls and interrupts.
267+
*/
268+
static __always_inline void irqentry_exit_to_user_mode_prepare(struct pt_regs *regs)
269+
{
270+
__exit_to_user_mode_prepare(regs);
271+
rseq_exit_to_user_mode();
272+
__exit_to_user_mode_validate();
273+
}
274+
236275
/**
237276
* exit_to_user_mode - Fixup state when exiting to user mode
238277
*
@@ -297,7 +336,7 @@ static __always_inline void irqentry_enter_from_user_mode(struct pt_regs *regs)
297336
static __always_inline void irqentry_exit_to_user_mode(struct pt_regs *regs)
298337
{
299338
instrumentation_begin();
300-
exit_to_user_mode_prepare(regs);
339+
irqentry_exit_to_user_mode_prepare(regs);
301340
instrumentation_end();
302341
exit_to_user_mode();
303342
}

0 commit comments

Comments
 (0)