[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20241029-arm-generic-entry-v2-24-573519abef38@linaro.org>
Date: Tue, 29 Oct 2024 11:53:04 +0100
From: Linus Walleij <linus.walleij@...aro.org>
To: Oleg Nesterov <oleg@...hat.com>, Russell King <linux@...linux.org.uk>,
Kees Cook <kees@...nel.org>, Andy Lutomirski <luto@...capital.net>,
Will Drewry <wad@...omium.org>, Frederic Weisbecker <frederic@...nel.org>,
"Paul E. McKenney" <paulmck@...nel.org>,
Jinjie Ruan <ruanjinjie@...wei.com>, Arnd Bergmann <arnd@...db.de>,
Ard Biesheuvel <ardb@...nel.org>, Al Viro <viro@...iv.linux.org.uk>
Cc: linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org,
Linus Walleij <linus.walleij@...aro.org>
Subject: [PATCH RFC v2 24/28] ARM: entry: Complete syscall and IRQ
transition to C
This moves over the last few lines of assembly to C. The
subtle change is that in return to userspace from syscall
(SWI) or interrupt, we need to call do_work_pending()
as soon as the thread flags are != 0, just checking for
work with _TIF_SYSCALL_WORK is not enough (the machine will
freeze if we do that).
This is because do_work_pending() does not just handle
work: it handles _TIF_NEED_RESCHED, _TIF_SIGPENDING,
_TIF_NOTIFY_SIGNAL and _TIF_UPROBE as well.
Signed-off-by: Linus Walleij <linus.walleij@...aro.org>
---
arch/arm/kernel/entry-common.S | 13 +------------
arch/arm/kernel/entry.c | 19 +++++++++++++------
arch/arm/kernel/signal.c | 3 +--
3 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e2ac6d3216b6..6b0f86786a7d 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -61,12 +61,7 @@ ENTRY(ret_to_user)
enable_irq_notrace @ enable interrupts
mov r0, sp @ 'regs'
bl syscall_exit_to_user_mode
- ldr r1, [tsk, #TI_FLAGS]
- movs r1, r1, lsl #16
- beq 1f
- mov r0, sp @ 'regs'
- bl do_work_pending
-1:
+
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
bl stackleak_erase_on_task_stack
#endif
@@ -74,12 +69,6 @@ ENTRY(ret_to_user)
ENDPROC(ret_to_user)
ENTRY(ret_to_user_from_irq)
- ldr r1, [tsk, #TI_FLAGS]
- movs r1, r1, lsl #16
- beq no_work_pending
- mov r0, sp @ 'regs'
- bl do_work_pending
-no_work_pending:
asm_irqentry_exit_to_user_mode
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
diff --git a/arch/arm/kernel/entry.c b/arch/arm/kernel/entry.c
index 88a7a699306a..d7fdb9df3331 100644
--- a/arch/arm/kernel/entry.c
+++ b/arch/arm/kernel/entry.c
@@ -6,11 +6,6 @@
#include <linux/irqflags.h>
#include <linux/rseq.h>
-static inline bool has_syscall_work(unsigned long flags)
-{
- return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
{
trace_hardirqs_on();
@@ -28,7 +23,11 @@ void syscall_exit_to_user_mode(struct pt_regs *regs)
rseq_syscall(regs);
local_irq_disable();
- if (has_syscall_work(flags))
+ /*
+ * It really matters that we check for flags != 0 and not
+ * just for pending work here!
+ */
+ if (flags)
do_work_pending(regs, flags);
trace_hardirqs_on();
@@ -45,6 +44,14 @@ noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
noinstr void irqentry_exit_to_user_mode(struct pt_regs *regs)
{
+ unsigned long flags = read_thread_flags();
+
+ /*
+ * It really matters that we check for flags != 0 and not
+ * just for pending work here!
+ */
+ if (flags)
+ do_work_pending(regs, flags);
trace_hardirqs_on();
/* This context tracking call has inverse naming */
user_enter_callable();
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 03b20637a2e1..a39ee14ec5b7 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -598,8 +598,7 @@ static void arch_do_signal_or_restart(struct pt_regs *regs)
return;
}
-asmlinkage void
-do_work_pending(struct pt_regs *regs, unsigned int thread_flags)
+void do_work_pending(struct pt_regs *regs, unsigned int thread_flags)
{
/*
* The assembly code enters us with IRQs off, but it hasn't
--
2.46.2
Powered by blists - more mailing lists