kernel: backport MIPS changes introducing a separate IRQ stack
authorFelix Fietkau <nbd@nbd.name>
Wed, 11 Jan 2017 09:57:49 +0000 (10:57 +0100)
committerFelix Fietkau <nbd@nbd.name>
Sun, 15 Jan 2017 17:25:54 +0000 (18:25 +0100)
Prevents crashes when IRQs arrive when the current kernel stack context
already contains deeply nested function calls, e.g. when stacking lots
of network devices on top of each other

Signed-off-by: Felix Fietkau <nbd@nbd.name>
17 files changed:
target/linux/ar71xx/patches-4.4/500-MIPS-fw-myloader.patch
target/linux/ath25/patches-4.4/107-ar5312_gpio.patch
target/linux/brcm47xx/patches-4.4/159-cpu_fixes.patch
target/linux/brcm63xx/patches-4.4/322-MIPS-BCM63XX-switch-to-IRQ_DOMAIN.patch
target/linux/generic/patches-4.4/062-01-MIPS-Introduce-irq_stack.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/062-02-MIPS-Stack-unwinding-while-on-IRQ-stack.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/062-03-MIPS-Only-change-28-to-thread_info-if-coming-from-us.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/062-04-MIPS-Switch-to-the-irq_stack-in-interrupts.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/062-05-MIPS-Select-HAVE_IRQ_EXIT_ON_IRQ_STACK.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/092-MIPS-ZBOOT-copy-appended-dtb-to-the-end-of-the-kerne.patch
target/linux/generic/patches-4.4/132-mips_inline_dma_ops.patch
target/linux/generic/patches-4.4/300-mips_expose_boot_raw.patch
target/linux/generic/patches-4.4/301-mips_image_cmdline_hack.patch
target/linux/generic/patches-4.4/304-mips_disable_fpu.patch
target/linux/lantiq/patches-4.4/0152-lantiq-VPE.patch
target/linux/ramips/patches-4.4/0025-pinctrl-ralink-add-pinctrl-driver.patch
target/linux/ramips/patches-4.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch

index e877b0c..811a234 100644 (file)
@@ -10,7 +10,7 @@
  
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -1117,6 +1117,9 @@ config MIPS_MSC
+@@ -1118,6 +1118,9 @@ config MIPS_MSC
  config MIPS_NILE4
        bool
  
index 3627cee..e6196c8 100644 (file)
 +subsys_initcall(ar5312_gpio_init);
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -117,6 +117,7 @@ config ATH25
+@@ -118,6 +118,7 @@ config ATH25
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_HAS_EARLY_PRINTK
index cf72d66..795969b 100644 (file)
  #endif /* _ASM_R4KCACHE_H */
 --- a/arch/mips/include/asm/stackframe.h
 +++ b/arch/mips/include/asm/stackframe.h
-@@ -358,6 +358,10 @@
+@@ -365,6 +365,10 @@
                .macro  RESTORE_SP_AND_RET
                LONG_L  sp, PT_R29(sp)
                .set    arch=r4000
index f611ddc..c7c9c35 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -206,6 +206,9 @@ config BCM63XX
+@@ -207,6 +207,9 @@ config BCM63XX
        select SYNC_R4K
        select DMA_NONCOHERENT
        select IRQ_MIPS_CPU
diff --git a/target/linux/generic/patches-4.4/062-01-MIPS-Introduce-irq_stack.patch b/target/linux/generic/patches-4.4/062-01-MIPS-Introduce-irq_stack.patch
new file mode 100644 (file)
index 0000000..2a929aa
--- /dev/null
@@ -0,0 +1,70 @@
+From: Matt Redfearn <matt.redfearn@imgtec.com>
+Date: Mon, 19 Dec 2016 14:20:56 +0000
+Subject: [PATCH] MIPS: Introduce irq_stack
+
+Allocate a per-cpu irq stack for use within interrupt handlers.
+
+Also add a utility function on_irq_stack to determine if a given stack
+pointer is within the irq stack for that cpu.
+
+Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
+---
+
+--- a/arch/mips/include/asm/irq.h
++++ b/arch/mips/include/asm/irq.h
+@@ -17,6 +17,18 @@
+ #include <irq.h>
++#define IRQ_STACK_SIZE                        THREAD_SIZE
++
++extern void *irq_stack[NR_CPUS];
++
++static inline bool on_irq_stack(int cpu, unsigned long sp)
++{
++      unsigned long low = (unsigned long)irq_stack[cpu];
++      unsigned long high = low + IRQ_STACK_SIZE;
++
++      return (low <= sp && sp <= high);
++}
++
+ #ifdef CONFIG_I8259
+ static inline int irq_canonicalize(int irq)
+ {
+--- a/arch/mips/kernel/asm-offsets.c
++++ b/arch/mips/kernel/asm-offsets.c
+@@ -101,6 +101,7 @@ void output_thread_info_defines(void)
+       OFFSET(TI_REGS, thread_info, regs);
+       DEFINE(_THREAD_SIZE, THREAD_SIZE);
+       DEFINE(_THREAD_MASK, THREAD_MASK);
++      DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
+       BLANK();
+ }
+--- a/arch/mips/kernel/irq.c
++++ b/arch/mips/kernel/irq.c
+@@ -25,6 +25,8 @@
+ #include <linux/atomic.h>
+ #include <asm/uaccess.h>
++void *irq_stack[NR_CPUS];
++
+ /*
+  * 'what should we do if we get a hw irq event on an illegal vector'.
+  * each architecture has to answer this themselves.
+@@ -55,6 +57,15 @@ void __init init_IRQ(void)
+               irq_set_noprobe(i);
+       arch_init_irq();
++
++      for_each_possible_cpu(i) {
++              int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE;
++              void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages);
++
++              irq_stack[i] = s;
++              pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
++                      irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
++      }
+ }
+ #ifdef CONFIG_DEBUG_STACKOVERFLOW
diff --git a/target/linux/generic/patches-4.4/062-02-MIPS-Stack-unwinding-while-on-IRQ-stack.patch b/target/linux/generic/patches-4.4/062-02-MIPS-Stack-unwinding-while-on-IRQ-stack.patch
new file mode 100644 (file)
index 0000000..513e904
--- /dev/null
@@ -0,0 +1,42 @@
+From: Matt Redfearn <matt.redfearn@imgtec.com>
+Date: Mon, 19 Dec 2016 14:20:57 +0000
+Subject: [PATCH] MIPS: Stack unwinding while on IRQ stack
+
+Within unwind stack, check if the stack pointer being unwound is within
+the CPU's irq_stack and if so use that page rather than the task's stack
+page.
+
+Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
+---
+
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -32,6 +32,7 @@
+ #include <asm/cpu.h>
+ #include <asm/dsp.h>
+ #include <asm/fpu.h>
++#include <asm/irq.h>
+ #include <asm/msa.h>
+ #include <asm/pgtable.h>
+ #include <asm/mipsregs.h>
+@@ -507,7 +508,19 @@ EXPORT_SYMBOL(unwind_stack_by_address);
+ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
+                          unsigned long pc, unsigned long *ra)
+ {
+-      unsigned long stack_page = (unsigned long)task_stack_page(task);
++      unsigned long stack_page = 0;
++      int cpu;
++
++      for_each_possible_cpu(cpu) {
++              if (on_irq_stack(cpu, *sp)) {
++                      stack_page = (unsigned long)irq_stack[cpu];
++                      break;
++              }
++      }
++
++      if (!stack_page)
++              stack_page = (unsigned long)task_stack_page(task);
++
+       return unwind_stack_by_address(stack_page, sp, pc, ra);
+ }
+ #endif
diff --git a/target/linux/generic/patches-4.4/062-03-MIPS-Only-change-28-to-thread_info-if-coming-from-us.patch b/target/linux/generic/patches-4.4/062-03-MIPS-Only-change-28-to-thread_info-if-coming-from-us.patch
new file mode 100644 (file)
index 0000000..e13c67b
--- /dev/null
@@ -0,0 +1,48 @@
+From: Matt Redfearn <matt.redfearn@imgtec.com>
+Date: Mon, 19 Dec 2016 14:20:58 +0000
+Subject: [PATCH] MIPS: Only change $28 to thread_info if coming from user
+ mode
+
+The SAVE_SOME macro is used to save the execution context on all
+exceptions.
+If an exception occurs while executing user code, the stack is switched
+to the kernel's stack for the current task, and register $28 is switched
+to point to the current_thread_info, which is at the bottom of the stack
+region.
+If the exception occurs while executing kernel code, the stack is left,
+and this change ensures that register $28 is not updated. This is the
+correct behaviour when the kernel can be executing on the separate irq
+stack, because the thread_info will not be at the base of it.
+
+With this change, register $28 is only switched to it's kernel
+conventional usage of the currrent thread info pointer at the point at
+which execution enters kernel space. Doing it on every exception was
+redundant, but OK without an IRQ stack, but will be erroneous once that
+is introduced.
+
+Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
+Reviewed-by: Maciej W. Rozycki <macro@imgtec.com>
+---
+
+--- a/arch/mips/include/asm/stackframe.h
++++ b/arch/mips/include/asm/stackframe.h
+@@ -216,12 +216,19 @@
+               LONG_S  $25, PT_R25(sp)
+               LONG_S  $28, PT_R28(sp)
+               LONG_S  $31, PT_R31(sp)
++
++              /* Set thread_info if we're coming from user mode */
++              mfc0    k0, CP0_STATUS
++              sll     k0, 3           /* extract cu0 bit */
++              bltz    k0, 9f
++
+               ori     $28, sp, _THREAD_MASK
+               xori    $28, _THREAD_MASK
+ #ifdef CONFIG_CPU_CAVIUM_OCTEON
+               .set    mips64
+               pref    0, 0($28)       /* Prefetch the current pointer */
+ #endif
++9:
+               .set    pop
+               .endm
diff --git a/target/linux/generic/patches-4.4/062-04-MIPS-Switch-to-the-irq_stack-in-interrupts.patch b/target/linux/generic/patches-4.4/062-04-MIPS-Switch-to-the-irq_stack-in-interrupts.patch
new file mode 100644 (file)
index 0000000..9bd2336
--- /dev/null
@@ -0,0 +1,116 @@
+From: Matt Redfearn <matt.redfearn@imgtec.com>
+Date: Mon, 19 Dec 2016 14:20:59 +0000
+Subject: [PATCH] MIPS: Switch to the irq_stack in interrupts
+
+When enterring interrupt context via handle_int or except_vec_vi, switch
+to the irq_stack of the current CPU if it is not already in use.
+
+The current stack pointer is masked with the thread size and compared to
+the base or the irq stack. If it does not match then the stack pointer
+is set to the top of that stack, otherwise this is a nested irq being
+handled on the irq stack so the stack pointer should be left as it was.
+
+The in-use stack pointer is placed in the callee saved register s1. It
+will be saved to the stack when plat_irq_dispatch is invoked and can be
+restored once control returns here.
+
+Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
+---
+
+--- a/arch/mips/kernel/genex.S
++++ b/arch/mips/kernel/genex.S
+@@ -188,9 +188,44 @@ NESTED(handle_int, PT_SIZE, sp)
+       LONG_L  s0, TI_REGS($28)
+       LONG_S  sp, TI_REGS($28)
+-      PTR_LA  ra, ret_from_irq
+-      PTR_LA  v0, plat_irq_dispatch
+-      jr      v0
++
++      /*
++       * SAVE_ALL ensures we are using a valid kernel stack for the thread.
++       * Check if we are already using the IRQ stack.
++       */
++      move    s1, sp # Preserve the sp
++
++      /* Get IRQ stack for this CPU */
++      ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
++#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
++      lui     k1, %hi(irq_stack)
++#else
++      lui     k1, %highest(irq_stack)
++      daddiu  k1, %higher(irq_stack)
++      dsll    k1, 16
++      daddiu  k1, %hi(irq_stack)
++      dsll    k1, 16
++#endif
++      LONG_SRL        k0, SMP_CPUID_PTRSHIFT
++      LONG_ADDU       k1, k0
++      LONG_L  t0, %lo(irq_stack)(k1)
++
++      # Check if already on IRQ stack
++      PTR_LI  t1, ~(_THREAD_SIZE-1)
++      and     t1, t1, sp
++      beq     t0, t1, 2f
++
++      /* Switch to IRQ stack */
++      li      t1, _IRQ_STACK_SIZE
++      PTR_ADD sp, t0, t1
++
++2:
++      jal     plat_irq_dispatch
++
++      /* Restore sp */
++      move    sp, s1
++
++      j       ret_from_irq
+ #ifdef CONFIG_CPU_MICROMIPS
+       nop
+ #endif
+@@ -263,8 +298,44 @@ NESTED(except_vec_vi_handler, 0, sp)
+       LONG_L  s0, TI_REGS($28)
+       LONG_S  sp, TI_REGS($28)
+-      PTR_LA  ra, ret_from_irq
+-      jr      v0
++
++      /*
++       * SAVE_ALL ensures we are using a valid kernel stack for the thread.
++       * Check if we are already using the IRQ stack.
++       */
++      move    s1, sp # Preserve the sp
++
++      /* Get IRQ stack for this CPU */
++      ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
++#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
++      lui     k1, %hi(irq_stack)
++#else
++      lui     k1, %highest(irq_stack)
++      daddiu  k1, %higher(irq_stack)
++      dsll    k1, 16
++      daddiu  k1, %hi(irq_stack)
++      dsll    k1, 16
++#endif
++      LONG_SRL        k0, SMP_CPUID_PTRSHIFT
++      LONG_ADDU       k1, k0
++      LONG_L  t0, %lo(irq_stack)(k1)
++
++      # Check if already on IRQ stack
++      PTR_LI  t1, ~(_THREAD_SIZE-1)
++      and     t1, t1, sp
++      beq     t0, t1, 2f
++
++      /* Switch to IRQ stack */
++      li      t1, _IRQ_STACK_SIZE
++      PTR_ADD sp, t0, t1
++
++2:
++      jal     plat_irq_dispatch
++
++      /* Restore sp */
++      move    sp, s1
++
++      j       ret_from_irq
+       END(except_vec_vi_handler)
+ /*
diff --git a/target/linux/generic/patches-4.4/062-05-MIPS-Select-HAVE_IRQ_EXIT_ON_IRQ_STACK.patch b/target/linux/generic/patches-4.4/062-05-MIPS-Select-HAVE_IRQ_EXIT_ON_IRQ_STACK.patch
new file mode 100644 (file)
index 0000000..a4942b8
--- /dev/null
@@ -0,0 +1,21 @@
+From: Matt Redfearn <matt.redfearn@imgtec.com>
+Date: Mon, 19 Dec 2016 14:21:00 +0000
+Subject: [PATCH] MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK
+
+Since do_IRQ is now invoked on a separate IRQ stack, we select
+HAVE_IRQ_EXIT_ON_IRQ_STACK so that softirq's may be invoked directly
+from irq_exit(), rather than requiring do_softirq_own_stack.
+
+Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
+---
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -9,6 +9,7 @@ config MIPS
+       select HAVE_CONTEXT_TRACKING
+       select HAVE_GENERIC_DMA_COHERENT
+       select HAVE_IDE
++      select HAVE_IRQ_EXIT_ON_IRQ_STACK
+       select HAVE_OPROFILE
+       select HAVE_PERF_EVENTS
+       select PERF_USE_VMALLOC
index 71df429..78188dd 100644 (file)
@@ -27,7 +27,7 @@ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -2752,10 +2752,10 @@ choice
+@@ -2753,10 +2753,10 @@ choice
                  the documented boot protocol using a device tree.
  
        config MIPS_RAW_APPENDED_DTB
@@ -40,7 +40,7 @@ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
                  (e.g. cat vmlinux.bin <filename>.dtb > vmlinux_w_dtb).
  
                  This is meant as a backward compatibility convenience for those
-@@ -2767,24 +2767,6 @@ choice
+@@ -2768,24 +2768,6 @@ choice
                  look like a DTB header after a reboot if no actual DTB is appended
                  to vmlinux.bin.  Do not leave this option active in a production kernel
                  if you don't intend to always append a DTB.
index bf7dca6..143b0bb 100644 (file)
@@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -1618,6 +1618,7 @@ config CPU_CAVIUM_OCTEON
+@@ -1619,6 +1619,7 @@ config CPU_CAVIUM_OCTEON
        select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
        select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
        select MIPS_L1_CACHE_SHIFT_7
@@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        help
          The Cavium Octeon processor is a highly integrated chip containing
          many ethernet hardware widgets for networking tasks. The processor
-@@ -1913,6 +1914,9 @@ config MIPS_MALTA_PM
+@@ -1914,6 +1915,9 @@ config MIPS_MALTA_PM
        bool
        default y
  
index 76c7078..0980c26 100644 (file)
@@ -8,7 +8,7 @@ Acked-by: Rob Landley <rob@landley.net>
 ---
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -1032,9 +1032,6 @@ config FW_ARC
+@@ -1033,9 +1033,6 @@ config FW_ARC
  config ARCH_MAY_HAVE_PC_FDC
        bool
  
@@ -18,7 +18,7 @@ Acked-by: Rob Landley <rob@landley.net>
  config CEVT_BCM1480
        bool
  
-@@ -2792,6 +2789,18 @@ choice
+@@ -2793,6 +2790,18 @@ choice
                bool "Bootloader kernel arguments if available"
  endchoice
  
index 878f74d..625a84c 100644 (file)
@@ -1,6 +1,6 @@
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -1123,6 +1123,10 @@ config SYNC_R4K
+@@ -1124,6 +1124,10 @@ config SYNC_R4K
  config MIPS_MACHINE
        def_bool n
  
index aabb4f1..a08564d 100644 (file)
@@ -26,7 +26,7 @@ v2: incorporated changes suggested by Jonas Gorski
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -2724,6 +2724,20 @@ config MIPS_O32_FP64_SUPPORT
+@@ -2725,6 +2725,20 @@ config MIPS_O32_FP64_SUPPORT
  
          If unsure, say N.
  
index 8488d47..bf883c8 100644 (file)
@@ -1,6 +1,6 @@
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -2220,6 +2220,12 @@ config MIPS_VPE_LOADER
+@@ -2221,6 +2221,12 @@ config MIPS_VPE_LOADER
          Includes a loader for loading an elf relocatable object
          onto another VPE and running it.
  
index 315d956..f7fc932 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -585,6 +585,8 @@ config RALINK
+@@ -586,6 +586,8 @@ config RALINK
        select CLKDEV_LOOKUP
        select ARCH_HAS_RESET_CONTROLLER
        select RESET_CONTROLLER
index 46a1d9e..0f7f366 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
 
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -587,6 +587,9 @@ config RALINK
+@@ -588,6 +588,9 @@ config RALINK
        select RESET_CONTROLLER
        select PINCTRL
        select PINCTRL_RT2880