Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1544560 > unrolled thread
| Started by | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| First post | 2016-12-19 15:30 +0100 |
| Last post | 2016-12-21 02:20 +0100 |
| Articles | 4 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v3 0/5] MIPS: Add per-cpu IRQ stack Matt Redfearn <matt.redfearn@imgtec.com> - 2016-12-19 15:30 +0100
[PATCH v3 2/5] MIPS: Stack unwinding while on IRQ stack Matt Redfearn <matt.redfearn@imgtec.com> - 2016-12-19 15:30 +0100
[PATCH v3 4/5] MIPS: Switch to the irq_stack in interrupts Matt Redfearn <matt.redfearn@imgtec.com> - 2016-12-19 15:30 +0100
Re: [PATCH v3 0/5] MIPS: Add per-cpu IRQ stack "Jason A. Donenfeld" <Jason@zx2c4.com> - 2016-12-21 02:20 +0100
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2016-12-19 15:30 +0100 |
| Subject | [PATCH v3 0/5] MIPS: Add per-cpu IRQ stack |
| Message-ID | <sQ76W-yD-17@gated-at.bofh.it> |
This series adds a separate stack for each CPU wihin the system to use when handling IRQs. Previously IRQs were handled on the kernel stack of the current task. If that task was deep down a call stack at the point of the interrupt, and handling the interrupt required a deep IRQ stack, then there was a likelihood of stack overflow. Since the kernel stack is in normal unmapped memory, overflowing it can lead to silent corruption of other kernel data, with weird and wonderful results. Before this patch series, ftracing the maximum stack size of a v4.9 kernel running on a Ci40 board gave: 4996 And with this series: 4084 Handling interrupts on a separate stack reduces the maximum kernel stack usage in this configuration by ~900 bytes. Since do_IRQ is now invoked on a separate stack, we select HAVE_IRQ_EXIT_ON_IRQ_STACK so that softirqs will also be executed on the irq stack rather than attempting to switch with do_softirq_own_stack(). This series has been tested on MIPS Boston, Malta and SEAD3 platforms, Pistachio on the Creator Ci40 board and Cavium Octeon III. Changes in v3: Drop superfluous nop that would have been in delay slot with .set noreorder but is no longer required now that the code is .set reorder. Changes in v2: Drop .set reorder/noreorder when updating $28 Matt Redfearn (5): MIPS: Introduce irq_stack MIPS: Stack unwinding while on IRQ stack MIPS: Only change $28 to thread_info if coming from user mode MIPS: Switch to the irq_stack in interrupts MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK arch/mips/Kconfig | 1 + arch/mips/include/asm/irq.h | 12 ++++++ arch/mips/include/asm/stackframe.h | 7 ++++ arch/mips/kernel/asm-offsets.c | 1 + arch/mips/kernel/genex.S | 81 +++++++++++++++++++++++++++++++++++--- arch/mips/kernel/irq.c | 11 ++++++ arch/mips/kernel/process.c | 15 ++++++- 7 files changed, 122 insertions(+), 6 deletions(-) -- 2.7.4
[toc] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2016-12-19 15:30 +0100 |
| Subject | [PATCH v3 2/5] MIPS: Stack unwinding while on IRQ stack |
| Message-ID | <sQ76W-yD-27@gated-at.bofh.it> |
| In reply to | #1544560 |
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>
---
Changes in v3: None
Changes in v2: None
arch/mips/kernel/process.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 9514e5f2209f..4fdbf7078071 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -33,6 +33,7 @@
#include <asm/dsemul.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>
@@ -511,7 +512,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
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2016-12-19 15:30 +0100 |
| Subject | [PATCH v3 4/5] MIPS: Switch to the irq_stack in interrupts |
| Message-ID | <sQ76W-yD-45@gated-at.bofh.it> |
| In reply to | #1544560 |
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> --- Changes in v3: None Changes in v2: None arch/mips/kernel/genex.S | 81 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index dc0b29612891..0a7ba4b2f687 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -187,9 +187,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 @@ -262,8 +297,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) /* -- 2.7.4
[toc] | [prev] | [next] | [standalone]
| From | "Jason A. Donenfeld" <Jason@zx2c4.com> |
|---|---|
| Date | 2016-12-21 02:20 +0100 |
| Message-ID | <sQDJv-52o-3@gated-at.bofh.it> |
| In reply to | #1544560 |
Hi Matt, Thanks for the v3. For the whole series: Acked-by: Jason A. Donenfeld <jason@zx2c4.com> Jason
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web