[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250212-arm-generic-entry-v4-30-a457ff0a61d6@linaro.org>
Date: Wed, 12 Feb 2025 12:23:24 +0100
From: Linus Walleij <linus.walleij@...aro.org>
To: Dmitry Vyukov <dvyukov@...gle.com>, 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 v4 30/31] ARM: entry: Block IRQs in early IRQ context
When dabt, pabt or und exceptions occur on ARM, ordinary
interrupts (IRQs) can still happen. This isn't nice for the
kernels context tracker, which expect (when using generic
entry at least) that any nested IRQs happens
between irqentry_enter() and irqentry_exit(), else it
thinks something is fishy.
This change blocks interrupts in the pabt, dabt, und and
abt exception paths (all of them really) by unconditionally
setting PSR_I_BIT in the early exception handler, until
after context has been established with irqentry_enter()
and before it is exited with irqentry_exit(). Inside the
context-tracked exception handler we enable IRQs again,
and once we leave it we disable them while exiting the
exception.
The local_irq_disable() in bad_mode() can be dropped
since we are now disabling IRQs in the early assembly
exception handler for all exceptions.
This seems like not perfect: it seems an interrupt
could still occur right before CPSR is set, or right after
the userspace registers are restored in ret_from_exception.
I would like to know if there is some
way to set up these exceptions to inherently block IRQs
when handled, until we explicitly allow them between
irqentry_enter() and irqentry_exit() or if this is simply
the best we can do on ARM for these exceptions to make the
context tracker happy.
Signed-off-by: Linus Walleij <linus.walleij@...aro.org>
---
arch/arm/kernel/entry-armv.S | 6 +-----
arch/arm/kernel/entry.c | 18 ++++++++++++++++++
arch/arm/kernel/traps.c | 1 -
3 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index ae2f952beea7611f0abc7bd299fc944335a21219..3dae35b0bb3f440ecaf157a45687bf4690fb8f88 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -416,11 +416,6 @@ ENDPROC(__irq_usr)
__und_usr:
usr_entry uaccess=0
- @ IRQs must be enabled before attempting to read the instruction from
- @ user space since that could cause a page/translation fault if the
- @ page table was modified by another CPU.
- enable_irq
-
tst r5, #PSR_T_BIT @ Thumb mode?
mov r1, #2 @ set insn size to 2 for Thumb
bne 0f @ handle as Thumb undef exception
@@ -847,6 +842,7 @@ vector_\name:
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+ orr r0, r0, #PSR_I_BIT
msr spsr_cxsf, r0
@
diff --git a/arch/arm/kernel/entry.c b/arch/arm/kernel/entry.c
index 01e4339ccdb4951e04a89fb91ad7c6e1991e09af..3881670e0987ee40be6fff32f412edcf4f3ec80a 100644
--- a/arch/arm/kernel/entry.c
+++ b/arch/arm/kernel/entry.c
@@ -17,8 +17,18 @@ noinstr asmlinkage void arm_und_handler(struct pt_regs *regs)
{
irqentry_state_t state = irqentry_enter(regs);
+ /*
+ * IRQs must be enabled before attempting to read the instruction from
+ * user space since that could cause a page/translation fault if the
+ * page table was modified by another CPU.
+ */
+
+ local_irq_enable();
+
do_undefinstr(regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
@@ -27,8 +37,12 @@ noinstr asmlinkage void arm_dabt_handler(unsigned long addr, unsigned int fsr,
{
irqentry_state_t state = irqentry_enter(regs);
+ local_irq_enable();
+
do_DataAbort(addr, fsr, regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
@@ -37,8 +51,12 @@ noinstr asmlinkage void arm_pabt_handler(unsigned long addr, unsigned int ifsr,
{
irqentry_state_t state = irqentry_enter(regs);
+ local_irq_enable();
+
do_PrefetchAbort(addr, ifsr, regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index d3a689bd05955f1ae46a6341e456bb097e831311..b2eaab9cc4977c448f77faa4e6bc22a0749d1f9c 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -515,7 +515,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason)
pr_crit("Bad mode in %s handler detected\n", handler[reason]);
die("Oops - bad mode", regs, 0);
- local_irq_disable();
panic("bad mode");
}
--
2.48.1
Powered by blists - more mailing lists