aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/irq.c
diff options
context:
space:
mode:
authorArd Biesheuvel <[email protected]>2021-10-05 09:15:40 +0200
committerArd Biesheuvel <[email protected]>2021-12-03 15:11:31 +0100
commitd4664b6c987f80338407889c1e3f3abe7e16be94 (patch)
tree21565f50f64551f10a68d2df793711ac07962c53 /arch/arm/kernel/irq.c
parenteae9523fdd7a6c592e80666681962acbd913cda2 (diff)
ARM: implement IRQ stacks
Now that we no longer rely on the stack pointer to access the current task struct or thread info, we can implement support for IRQ stacks cleanly as well. Define a per-CPU IRQ stack and switch to this stack when taking an IRQ, provided that we were not already using that stack in the interrupted context. This is never the case for IRQs taken from user space, but ones taken while running in the kernel could fire while one taken from user space has not completed yet. Signed-off-by: Ard Biesheuvel <[email protected]> Acked-by: Linus Walleij <[email protected]> Tested-by: Keith Packard <[email protected]> Acked-by: Nick Desaulniers <[email protected]> Tested-by: Marc Zyngier <[email protected]> Tested-by: Vladimir Murzin <[email protected]> # ARMv7M
Diffstat (limited to 'arch/arm/kernel/irq.c')
-rw-r--r--arch/arm/kernel/irq.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index b79975bd988c..abb0aa679bba 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -43,6 +43,25 @@
unsigned long irq_err_count;
+#ifdef CONFIG_IRQSTACKS
+
+asmlinkage DEFINE_PER_CPU_READ_MOSTLY(u8 *, irq_stack_ptr);
+
+static void __init init_irq_stacks(void)
+{
+ u8 *stack;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ stack = (u8 *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+ if (WARN_ON(!stack))
+ break;
+ per_cpu(irq_stack_ptr, cpu) = &stack[THREAD_SIZE];
+ }
+}
+
+#endif
+
int arch_show_interrupts(struct seq_file *p, int prec)
{
#ifdef CONFIG_FIQ
@@ -101,6 +120,10 @@ void __init init_IRQ(void)
{
int ret;
+#ifdef CONFIG_IRQSTACKS
+ init_irq_stacks();
+#endif
+
if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
irqchip_init();
else