ARM: add support for IRQ stacks
v2 cover ARM: add support for IRQ stacks
Compared to user space, the kernel's task stacks are tiny and inflexible, as we don't grow them dynamically using demand paging. This is the reason we tend to obsess about functions with disproportionately large stack frames, given that it is hard to predict statically how calls to those functions may combine at runtime, and exhaust the stack and crash the kernel.
This becomes even less predictable when taking interrupt handling into account, as their handlers are normally executed on the stack of the task that was interrupted, regardless of how deep its call stack was at the time of the interruption. To decouple these, and reduce the risk of hitting a pathological worst case where IRQ handling and the task below it happen to exhaust the available stack space when combined, we can switch to a different stack when taking interrupts, similar to how this is done already on some other architectures. This series implements this approach for ARM.
Note that a good chunk of the changes below are related to supporting non-contiguous call stacks, which is also relevant in the context of vmap'ed stacks, which use a separate overflow stack to handle stack overflows. The changes preserve all functionality related to walking the call stack and dumping exception stacks and register contents, with one small exception: when using CONFIG_UNWINDER_FRAME_POINTER=y with Clang, (which does not record the SP value at function entry), we cannot dump the exception stack passed by the IRQ entry code if a stack switch occurred. All other scenarios have been tested and should work as before.
Changes since v1:
- drop the first bugfix patch, which has been queued as a fix in the meantime;
- preserve/restore FP in the irq_handler entry code;
- add missing include to arch/arm/kernel/irq.c to silence warnings about missing prototypes.
Patch #1 removes some code that I spotted that is no longer used.
Patch #2 introduces a pair of macros that will be used later in the series to emit the optimal indirect call sequence for older and newer cores.
Patch #3 tweaks the IRQ asm entry point to generate better code for v7 CPUs.
Patch #4 updates the unwind info based unwinder so it can deal with call stacks that are non-contiguous.
Patch #5 exports dump_mem() to other compilation units so the ARM unwinder can cal it directly. This is needed by the next patch.
Patch #6 refactors the ARM unwinder to dump the exception stack from a context where it can figure out if it lives on the current stack or on the task stack.
Patch #7 implements the actual IRQ stacks support, by allocating one for each CPU, and adding the code to switch to it in the IRQ entry path. It also contains some related changes to allow the frame pointer based unwinder to deal with the new situation.
Patch #8 modifies call_with_stack() so both the frame pointer unwinder as well as the ARM unwinder know how to deal with it.
Patch #9 adds the IRQ stack switching for softIRQ handling initiated from task context.
The patches are based on my arm32-ti-in-task-v5 branch [0], which is a prerequisite for these changes, given that we can no longer rely on thread_info being accessible by masking the stack pointer when we are jumping between stacks. A pull request is outstanding for those changes.
[0] https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=arm32-ti-in-task-v5
Ard Biesheuvel (9):
ARM: remove some dead code
ARM: assembler: introduce bl_r and bl_m macros
ARM: optimize indirect call to handle_arch_irq for v7 cores
ARM: unwind: support unwinding across multiple stacks
ARM: export dump_mem() to other objects
ARM: unwind: dump exception stack from calling frame
ARM: implement IRQ stacks
ARM: call_with_stack: add unwind support
ARM: run softirqs on the per-CPU IRQ stack
arch/arm/Kconfig | 6 +++ arch/arm/include/asm/assembler.h | 37 +++++++++++++++ arch/arm/include/asm/entry-macro-multi.S | 24 ---------- arch/arm/include/asm/smp.h | 5 -- arch/arm/include/asm/stacktrace.h | 13 ++++++ arch/arm/kernel/entry-armv.S | 48 +++++++++++++++++--- arch/arm/kernel/irq.c | 32 +++++++++++++ arch/arm/kernel/smp.c | 5 -- arch/arm/kernel/traps.c | 25 +++++++--- arch/arm/kernel/unwind.c | 33 ++++++++++---- arch/arm/lib/backtrace-clang.S | 8 ++++ arch/arm/lib/backtrace.S | 8 ++++ arch/arm/lib/call_with_stack.S | 44 +++++++++++++++--- 13 files changed, 225 insertions(+), 63 deletions(-)
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 1/9 ARM: remove some dead code
This code appears to be no longer used so let's get rid of it.
--- arch/arm/include/asm/entry-macro-multi.S | 24 -------------------- arch/arm/include/asm/smp.h | 5 ---- arch/arm/kernel/smp.c | 5 ---- 3 files changed, 34 deletions(-)
arch/arm/include/asm/entry-macro-multi.S +0 -24
@@ -13,28 +13,4 @@ @ badrne lr, 1b bne asm_do_IRQ - -#ifdef CONFIG_SMP - /* - * XXX - * - * this macro assumes that irqstat (r2) and base (r6) are - * preserved from get_irqnr_and_base above - */ - ALT_SMP(test_for_ipi r0, r2, r6, lr) - ALT_UP_B(9997f) - movne r1, sp - badrne lr, 1b - bne do_IPI -#endif -9997: - .endm - - .macro arch_irq_handler, symbol_name - .align 5 - .global \symbol_name -\symbol_name: - mov r8, lr - arch_irq_handler_default - ret r8 .endm
arch/arm/include/asm/smp.h +0 -5
@@ -24,11 +24,6 @@ struct seq_file;*/ extern void show_ipi_list (struct seq_file *,int ); -/* -* Called from assembly code, this handles an IPI. -*/ -asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); -/* * Called from C code, this handles an IPI. */
arch/arm/kernel/smp.c +0 -5
@@ -631,11 +631,6 @@ static void ipi_complete(unsigned int cpu)/* * Main handler for inter-processor interrupts */ -asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) -{ -handle_IPI (ipinr, regs); -} -static void do_handle_IPI (int ipinr) {unsigned int cpu =smp_processor_id ();
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 1/9] ARM: remove some dead code
Quoted 4 lines · Ard Biesheuvel
This code appears to be no longer used so let's get rid of it.
Signed-off-by Ard Biesheuvel <[email protected]>
I didn't see at first why this is unused, but eventually figured out that it's because
all ARMv6+ platforms use CONFIG_GENERIC_IRQ_MULTI_HANDLER, the last one that provided a custom test_for_ipi was removed in 2015 with commit 59b89af1d555 ("ARM: shmobile: sh7372: Remove Legacy C SoC code").
FWIW, the only remaining platforms with a custom entry-macro.S are rpc, iop320 and footbridge.
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 2/9 ARM: assembler: introduce bl_r and bl_m macros
In reply to Ard BiesheuvelAdd some macros that abstract the difference between the ways indirect calls are performed on older and newer ARM architecture revisions.
The main difference is to prefer blx instructions over explicit LR assignments when possible, as these tend to confuse the prediction logic in out-of-order cores when speculating across a function return.
--- arch/arm/include/asm/assembler.h | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+)
arch/arm/include/asm/assembler.h +37 -0
@@ -624,4 +624,41 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) .endif .endm + /* + * bl_r - branch and link to register + * + * @dst: target to branch to + * @c: conditional opcode suffix + */ + .macro bl_r, dst:req, c + .if __LINUX_ARM_ARCH__ < 6 + mov\c lr, pc + mov\c pc, \dst + .else + blx\c \dst + .endif + .endm + +/* +* bl_m - branch and link to address held in memory +* +* @dst: memory reference to load the branch target from +* +* This uses the same syntax as ldr instructions, including things like +* register writeback (where it makes sense). For example, +* +* bl_m [ip, #<offset>] +* +* Note that @dst should not reference lr as it may be clobbered early. +*/ + .macro bl_m, dst:vararg + .if __LINUX_ARM_ARCH__ < 6 + mov lr, pc + ldr pc, \dst + .else + ldr lr, \dst + blx lr + .endif + .endm + #endif /* __ASM_ASSEMBLER_H__ */
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 2/9] ARM: assembler: introduce bl_r and bl_m macros
Quoted 9 lines · Ard Biesheuvel
Add some macros that abstract the difference between the ways indirect calls are performed on older and newer ARM architecture revisions.
The main difference is to prefer blx instructions over explicit LR assignments when possible, as these tend to confuse the prediction logic in out-of-order cores when speculating across a function return.
Signed-off-by Ard Biesheuvel <[email protected]>
arch/arm/include/asm/assembler.h THUMB( orr \reg , \reg , #PSR_T_BIT ) · line 640
Quoted 8 lines
arch/arm/include/asm/assembler.h +8
-0+ .macro bl_r, dst:req, c + .if __LINUX_ARM_ARCH__ < 6 + mov\c lr, pc + mov\c pc, \dst + .else + blx\c \dst + .endif + .endm
I suppose we could use blx on ARMv5 as well, but it wouldn't make a difference there, right?
Arnd
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 2/9] ARM: assembler: introduce bl_r and bl_m macros
Quoted 23 lines · Arnd Bergmann
Quoted 9 lines · Ard Biesheuvel
Add some macros that abstract the difference between the ways indirect calls are performed on older and newer ARM architecture revisions.
The main difference is to prefer blx instructions over explicit LR assignments when possible, as these tend to confuse the prediction logic in out-of-order cores when speculating across a function return.
Signed-off-by Ard Biesheuvel <[email protected]>Reviewed-by Arnd Bergmann <[email protected]>arch/arm/include/asm/assembler.h THUMB( orr \reg , \reg , #PSR_T_BIT ) · line 640
Quoted 8 lines
arch/arm/include/asm/assembler.h +8
-0+ .macro bl_r, dst:req, c + .if __LINUX_ARM_ARCH__ < 6 + mov\c lr, pc + mov\c pc, \dst + .else + blx\c \dst + .endif + .endm
Quoted 3 lines
I suppose we could use blx on ARMv5 as well, but it wouldn't make a difference there, right?
No, it wouldn't. And the only reason for using '6' here is so that we use blx in code that may run on both v6 and v7.
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 3/9 ARM: optimize indirect call to handle_arch_irq for v7 cores
In reply to Ard BiesheuvelThe current irq_handler macro uses a literal load followed by an explicit assignment of lr before an indirect call, both of which are sub-optimal on recent ARM cores. Replace it by a mov_l call, which will evaluate to a movw/movt pair on v7 cores, avoiding one of the two loads, followed by a call to a newly introduced 'bl_m' macro, which will evaluate to a blx instruction on cores that support it. (Setting lr explicitly rather than via a bl or blx instruction confuses the return address prediction that modern out-of-order cores use to speculatively perform the function return.)
--- arch/arm/kernel/entry-armv.S | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/arm/kernel/entry-armv.S +2 -4
@@ -38,14 +38,12 @@ */ .macro irq_handler #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER - ldr r1, =handle_arch_irq + mov_l r1, handle_arch_irq mov r0, sp - badr lr, 9997f - ldr pc, [r1] + bl_m [r1] #else arch_irq_handler_default #endif -9997: .endm .macro pabt_helper
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 3/9] ARM: optimize indirect call to handle_arch_irq for v7 cores
Quoted 11 lines · Ard Biesheuvel
The current
irq_handlermacro uses a literal load followed by an explicit assignment of lr before an indirect call, both of which are sub-optimal on recent ARM cores. Replace it by amov_lcall, which will evaluate to a movw/movt pair on v7 cores, avoiding one of the two loads, followed by a call to a newly introduced 'bl_m' macro, which will evaluate to a blx instruction on cores that support it. (Setting lr explicitly rather than via a bl or blx instruction confuses the return address prediction that modern out-of-order cores use to speculatively perform the function return.)
Quoted 1 line
Signed-off-by Ard Biesheuvel <[email protected]>
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 4/9 ARM: unwind: support unwinding across multiple stacks
In reply to Ard BiesheuvelImplement support in the unwinder for dealing with multiple stacks. This will be needed once we add support for IRQ stacks, or for the overflow stack used by the vmap'ed stacks code.
This involves tracking the unwind opcodes that either update the virtual stack pointer from another virtual register, or perform an explicit subtract on the virtual stack pointer, and updating the low and high bounds that we use to sanitize the stack pointer accordingly.
--- arch/arm/kernel/unwind.c | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-)
arch/arm/kernel/unwind.c +16 -9
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);struct unwind_ctrl_block {unsigned long vrs[16 ];/* virtual register set */ const unsigned long *insn;/* pointer to the current instructions word */ +unsigned long sp_low;/* lowest value of sp allowed */ unsigned long sp_high;/* highest value of sp allowed */ /* * 1 : check for stack overflow for each register pop.
@@ -256,8 +257,12 @@ static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl, mask >>=1 ; reg++; } -if (!load_sp) +if (!load_sp) { ctrl->vrs[SP ] = (unsigned long )vsp; + }else { + ctrl->sp_low = ctrl->vrs[SP ]; + ctrl->sp_high =ALIGN (ctrl->sp_low,THREAD_SIZE ); + }return URC_OK ; }
@@ -313,9 +318,10 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)if ((insn &0xc0 ) ==0x00 ) ctrl->vrs[SP ] += ((insn &0x3f ) <<2 ) +4 ; -else if ((insn &0xc0 ) ==0x40 ) +else if ((insn &0xc0 ) ==0x40 ) { ctrl->vrs[SP ] -= ((insn &0x3f ) <<2 ) +4 ; -else if ((insn &0xf0 ) ==0x80 ) { + ctrl->sp_low = ctrl->vrs[SP ]; + }else if ((insn &0xf0 ) ==0x80 ) {unsigned long mask; insn = (insn <<8 ) |unwind_get_byte (ctrl);
@@ -330,9 +336,11 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)if (ret) goto error; }else if ((insn &0xf0 ) ==0x90 && - (insn &0x0d ) !=0x0d ) + (insn &0x0d ) !=0x0d ) { ctrl->vrs[SP ] = ctrl->vrs[insn &0x0f ]; -else if ((insn &0xf0 ) ==0xa0 ) { + ctrl->sp_low = ctrl->vrs[SP ]; + ctrl->sp_high =ALIGN (ctrl->sp_low,THREAD_SIZE ); + }else if ((insn &0xf0 ) ==0xa0 ) { ret =unwind_exec_pop_r4_to_rN (ctrl, insn);if (ret) goto error;
@@ -375,13 +383,12 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)*/ int unwind_frame (struct stackframe *frame) { -unsigned long low;const struct unwind_idx *idx;struct unwind_ctrl_block ctrl;/* store the highest address on the stack to avoid crossing it*/ - low = frame->sp; - ctrl.sp_high =ALIGN (low,THREAD_SIZE ); + ctrl.sp_low = frame->sp; + ctrl.sp_high =ALIGN (ctrl.sp_low,THREAD_SIZE );pr_debug ("%s(pc = %08lx lr = %08lx sp = %08lx)\n" , __func__, frame->pc, frame->lr, frame->sp);
@@ -437,7 +444,7 @@ int unwind_frame(struct stackframe *frame) urc =unwind_exec_insn (&ctrl);if (urc <0 )return urc; -if (ctrl.vrs[SP ] < low || ctrl.vrs[SP ] >= ctrl.sp_high) +if (ctrl.vrs[SP ] < ctrl.sp_low || ctrl.vrs[SP ] > ctrl.sp_high)return -URC_FAILURE ; }
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 4/9] ARM: unwind: support unwinding across multiple stacks
Quoted 11 lines · Ard Biesheuvel
Implement support in the unwinder for dealing with multiple stacks. This will be needed once we add support for IRQ stacks, or for the overflow stack used by the vmap'ed stacks code.
This involves tracking the unwind opcodes that either update the virtual stack pointer from another virtual register, or perform an explicit subtract on the virtual stack pointer, and updating the low and high bounds that we use to sanitize the stack pointer accordingly.
Signed-off-by Ard Biesheuvel <[email protected]>
I can't say I understand the code in detail, but I see nothing wrong here either.
arch/arm/kernel/unwind.c static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) · line 343
Quoted 4 lines
arch/arm/kernel/unwind.c +3
-1-else if ((insn &0xf0 ) ==0xa0 ) { + ctrl->sp_low = ctrl->vrs[SP ]; + ctrl->sp_high =ALIGN (ctrl->sp_low,THREAD_SIZE ); + }else if ((insn &0xf0 ) ==0xa0 ) {
Would this break if the IRQ stack is not aligned to THREAD_SIZE? If it would, it may be good to document this somewhere, probably in patch 7, not here.
Arnd
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 5/9 ARM: export dump_mem() to other objects
In reply to Ard BiesheuvelThe unwind info based stack unwinder will make its own call to dump_mem() to dump the exception stack, so give it external linkage.
--- arch/arm/include/asm/stacktrace.h | 2 ++ arch/arm/kernel/traps.c | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-)
arch/arm/include/asm/stacktrace.h +2 -0
@@ -27,5 +27,7 @@ void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)extern int unwind_frame (struct stackframe *frame);extern void walk_stackframe (struct stackframe *frame,int (*fn)(struct stackframe *,void *),void *data); +extern void dump_mem (const char *lvl,const char *str,unsigned long bottom, +unsigned long top);#endif /* __ASM_STACKTRACE_H */
arch/arm/kernel/traps.c +3 -4
@@ -35,6 +35,7 @@#include <asm/ptrace.h> #include <asm/unwind.h> #include <asm/tls.h> +#include <asm/stacktrace.h> #include <asm/system_misc.h> #include <asm/opcodes.h>
@@ -60,8 +61,6 @@ static int __init user_debug_setup(char *str)__setup ("user_debug=" , user_debug_setup);#endif -static void dump_mem (const char *,const char *,unsigned long ,unsigned long ); -void dump_backtrace_entry (unsigned long where,unsigned long from,unsigned long frame,const char *loglvl) {
@@ -118,8 +117,8 @@ static int verify_stack(unsigned long sp)/* * Dump out the contents of some memory nicely... */ -static void dump_mem (const char *lvl,const char *str,unsigned long bottom, -unsigned long top) +void dump_mem (const char *lvl,const char *str,unsigned long bottom, +unsigned long top) {unsigned long first;int i;
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 5/9] ARM: export dump_mem() to other objects
Quoted 5 lines · Ard Biesheuvel
The unwind info based stack unwinder will make its own call to
dump_mem()to dump the exception stack, so give it external linkage.Signed-off-by Ard Biesheuvel <[email protected]>
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 6/9 ARM: unwind: dump exception stack from calling frame
In reply to Ard BiesheuvelThe existing code that dumps the contents of the pt_regs structure passed to __entry routines does so while unwinding the callee frame, and dereferences the stack pointer as a struct pt_regs*. This will no longer work when we enable support for IRQ or overflow stacks, because the struct pt_regs may live on the task stack, while we are executing from another stack.
The unwinder has access to this information, but only while unwinding the calling frame. So let's combine the exception stack dumping code with the handling of the calling frame as well. By printing it before dumping the caller/callee addresses, the output order is preserved.
--- arch/arm/include/asm/stacktrace.h | 11 +++++++++++ arch/arm/kernel/traps.c | 3 ++- arch/arm/kernel/unwind.c | 8 +++++++- 3 files changed, 20 insertions(+), 2 deletions(-)
arch/arm/include/asm/stacktrace.h +11 -0
@@ -13,6 +13,17 @@ struct stackframe {unsigned long sp;unsigned long lr;unsigned long pc; + +#ifdef CONFIG_ARM_UNWIND +/* +* This field is used to track the stack pointer value when calling +* __entry routines. This is needed when IRQ stacks and overflow stacks +* are used, because in that case, the struct pt_regs passed to these +* __entry routines may be at the top of the task stack, while we are +* executing from another stack. +*/ +unsigned long sp_low; +#endif }; static __always_inline
arch/arm/kernel/traps.c +2 -1
@@ -74,7 +74,8 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, loglvl, where, from);#endif -if (in_entry_text (from) && end <=ALIGN (frame,THREAD_SIZE )) +if (!IS_ENABLED (CONFIG_UNWINDER_ARM ) && +in_entry_text (from) && end <=ALIGN (frame,THREAD_SIZE ))dump_mem (loglvl,"Exception stack" , frame +4 , end); }
arch/arm/kernel/unwind.c +7 -1
@@ -29,6 +29,7 @@#include <linux/spinlock.h> #include <linux/list.h> +#include <asm/sections.h> #include <asm/stacktrace.h> #include <asm/traps.h> #include <asm/unwind.h>
@@ -459,6 +460,7 @@ int unwind_frame(struct stackframe *frame) frame->sp = ctrl.vrs[SP ]; frame->lr = ctrl.vrs[LR ]; frame->pc = ctrl.vrs[PC ]; + frame->sp_low = ctrl.sp_low;return URC_OK ; }
@@ -502,7 +504,11 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk, urc =unwind_frame (&frame);if (urc <0 )break ; -dump_backtrace_entry (where, frame.pc, frame.sp -4 , loglvl); +if (in_entry_text (where)) +dump_mem (loglvl,"Exception stack" , frame.sp_low, + frame.sp_low +sizeof (struct pt_regs )); + +dump_backtrace_entry (where, frame.pc,0 , loglvl); } }
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 6/9] ARM: unwind: dump exception stack from calling frame
Quoted 8 lines · Ard Biesheuvel
The existing code that dumps the contents of the
pt_regsstructure passed to__entryroutines does so while unwinding the callee frame, and dereferences the stack pointer as a struct pt_regs*. This will no longer work when we enable support for IRQ or overflow stacks, because the structpt_regsmay live on the task stack, while we are executing from another stack.
Quoted 6 lines
The unwinder has access to this information, but only while unwinding the calling frame. So let's combine the exception stack dumping code with the handling of the calling frame as well. By printing it before dumping the caller/callee addresses, the output order is preserved.
Signed-off-by Ard Biesheuvel <[email protected]>
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 7/9 ARM: implement IRQ stacks
In reply to Ard BiesheuvelNow 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.
--- arch/arm/Kconfig | 4 ++ arch/arm/kernel/entry-armv.S | 42 ++++++++++++++++++-- arch/arm/kernel/irq.c | 23 +++++++++++ arch/arm/kernel/traps.c | 15 ++++++- arch/arm/lib/backtrace-clang.S | 8 ++++ arch/arm/lib/backtrace.S | 8 ++++ 6 files changed, 96 insertions(+), 4 deletions(-)
arch/arm/Kconfig +4 -0
@@ -1163,6 +1163,10 @@ config CURRENT_POINTER_IN_TPIDRURO def_bool y depends on SMP && CPU_32v6K && !CPU_V6 +config IRQSTACKS + def_bool y + depends on GENERIC_IRQ_MULTI_HANDLER && THREAD_INFO_IN_TASK + config ARM_CPU_TOPOLOGY bool "Support cpu topology definition" depends on SMP && CPU_V7
arch/arm/kernel/entry-armv.S +39 -3
64 lines not on this page · raw message
arch/arm/kernel/irq.c +23 -0
@@ -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
@@ -99,6 +118,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
arch/arm/kernel/traps.c +14 -1
@@ -66,6 +66,19 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, {unsigned long end = frame +4 +sizeof (struct pt_regs ); +if (IS_ENABLED (CONFIG_UNWINDER_FRAME_POINTER ) && +IS_ENABLED (CONFIG_CC_IS_GCC ) && + end >ALIGN (frame,THREAD_SIZE )) { +/* +* If we are walking past the end of the stack, it may be due +* to the fact that we are on an IRQ or overflow stack. In this +* case, we can load the address of the other stack from the +* frame record. +*/ + frame = ((unsigned long *)frame)[-2 ] -4 ; + end = frame +4 +sizeof (struct pt_regs ); + } +#ifdef CONFIG_KALLSYMS printk ("%s[<%08lx>] (%ps) from [<%08lx>] (%pS)\n" , loglvl, where, (void *)where, from, (void *)from);
@@ -278,7 +291,7 @@ static int __die(const char *str, int err, struct pt_regs *regs)if (!user_mode (regs) ||in_interrupt ()) {dump_mem (KERN_EMERG ,"Stack: " , regs->ARM_sp, -THREAD_SIZE + (unsigned long )task_stack_page (tsk)); +ALIGN (regs->ARM_sp,THREAD_SIZE ));dump_backtrace (regs, tsk,KERN_EMERG );dump_instr (KERN_EMERG , regs); }
arch/arm/lib/backtrace-clang.S +8 -0
@@ -197,6 +197,14 @@ finished_setup: cmp sv_fp, frame @ next frame must be mov frame, sv_fp @ above the current frame +#ifdef CONFIG_IRQSTACKS + @ + @ Kernel stacks may be discontiguous in memory. If the next + @ frame is below the previous frame, accept it as long as it + @ lives in kernel memory. + @ + cmpls sv_fp, #PAGE_OFFSET +#endif bhi for_each_frame 1006: adr r0, .Lbad
arch/arm/lib/backtrace.S +8 -0
@@ -98,6 +98,14 @@ for_each_frame: tst frame, mask @ Check for address exceptions cmp sv_fp, frame @ next frame must be mov frame, sv_fp @ above the current frame +#ifdef CONFIG_IRQSTACKS + @ + @ Kernel stacks may be discontiguous in memory. If the next + @ frame is below the previous frame, accept it as long as it + @ lives in kernel memory. + @ + cmpls sv_fp, #PAGE_OFFSET +#endif bhi for_each_frame 1006: adr r0, .Lbad
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 7/9] ARM: implement IRQ stacks
Quoted 5 lines · Ard Biesheuvel
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.
Quoted 7 lines
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]>
This is where I get stuck in my review, I assume it's all good here, but I can't honestly claim to have reviewed it without a better understanding.
Hopefully one of the others on Cc can step in here and take a closer look.
Arnd
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v2 8/9 ARM: call_with_stack: add unwind support
In reply to Ard BiesheuvelRestructure the code and add the unwind annotations so that both the frame pointer unwinder as well as the ELF unwind info based unwinder will be able to follow the call stack through call_with_stack().
Note that the former cannot support GCC and Clang at the same time, as they use a different idiom for the prologue/epilogue. So the code uses the GCC idiom, adding full frame pointer based unwind support for GCC while preserving the existing behavior of the Clang version, which simply omits call_with_stack() from its call stack.
--- arch/arm/lib/call_with_stack.S | 44 +++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-)
arch/arm/lib/call_with_stack.S +38 -6
@@ -8,25 +8,57 @@ #include <linux/linkage.h> #include <asm/assembler.h> +#include <asm/unwind.h> /* * void call_with_stack(void (*fn)(void *), void *arg, void *sp) * * Change the stack to that pointed at by sp, then invoke fn(arg) with * the new stack. + * + * The sequence below follows the APCS frame convention for frame pointer + * unwinding, and implements the unwinder annotations needed by the EABI + * unwinder. + */ + +#if defined(CONFIG_THUMB2_KERNEL) || \ + (defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_CLANG)) +/* + * Thumb-2 builds must use R7 as the frame pointer due to the way our unwind + * info based unwinder is constructed. + * + * The code below uses the GCC idiom for managing the frame pointer in the + * function prologue and epilogue, which Clang does not support. So the best we + * can do here is not touch the frame pointer at all: this will simply omit + * this frame when unwinding the call stack. So use R7 in this case as well, + * and leave R11 unmodified. */ + fpreg .req r7 +#else + fpreg .req fp +#endif + ENTRY(call_with_stack) - str sp, [r2, #-4]! - str lr, [r2, #-4]! +UNWIND( .fnstart ) +UNWIND( .movsp ip ) + mov ip, sp + +UNWIND( .pad #4 ) +UNWIND( .save {fpreg, ip, lr} ) +THUMB( sub sp, #4 ) + push {fpreg, ip, lr ARM(, pc)} + +UNWIND( .setfp fpreg, ip, #-4 ) + sub fpreg, ip, #4 mov sp, r2 mov r2, r0 mov r0, r1 - badr lr, 1f - ret r2 + bl_r r2 -1: ldr lr, [sp] - ldr sp, [sp, #4] + ldmdb fpreg, {fpreg, ip, lr} + mov sp, ip ret lr +UNWIND( .fnend ) ENDPROC(call_with_stack)
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 8/9] ARM: call_with_stack: add unwind support
Quoted 5 lines · Ard Biesheuvel
Restructure the code and add the unwind annotations so that both the frame pointer unwinder as well as the ELF unwind info based unwinder will be able to follow the call stack through
call_with_stack().
Quoted 7 lines
Note that the former cannot support GCC and Clang at the same time, as they use a different idiom for the prologue/epilogue. So the code uses the GCC idiom, adding full frame pointer based unwind support for GCC while preserving the existing behavior of the Clang version, which simply omits
call_with_stack()from its call stack.Signed-off-by Ard Biesheuvel <[email protected]>
I would like Nick to take a look at this for the clang support, he spent some time on getting the frame pointer unwinder working with clang, so he may have additional comments about this.
Quoted 73 lines
--- arch/arm/lib/call_with_stack.S | 44 +++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-)arch/arm/lib/call_with_stack.S +38
-7@@ -8,25 +8,57 @@ #include <linux/linkage.h> #include <asm/assembler.h> +#include <asm/unwind.h> /* * void call_with_stack(void (*fn)(void *), void *arg, void *sp) * * Change the stack to that pointed at by sp, then invoke fn(arg) with * the new stack. + * + * The sequence below follows the APCS frame convention for frame pointer + * unwinding, and implements the unwinder annotations needed by the EABI + * unwinder. + */ + +#if defined(CONFIG_THUMB2_KERNEL) || \ + (defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_CLANG)) +/* + * Thumb-2 builds must use R7 as the frame pointer due to the way our unwind + * info based unwinder is constructed. + * + * The code below uses the GCC idiom for managing the frame pointer in the + * function prologue and epilogue, which Clang does not support. So the best we + * can do here is not touch the frame pointer at all: this will simply omit + * this frame when unwinding the call stack. So use R7 in this case as well, + * and leave R11 unmodified. */ + fpreg .req r7 +#else + fpreg .req fp +#endif + ENTRY(call_with_stack) - str sp, [r2, #-4]! - str lr, [r2, #-4]! +UNWIND( .fnstart ) +UNWIND( .movsp ip ) + mov ip, sp + +UNWIND( .pad #4 ) +UNWIND( .save {fpreg, ip, lr} ) +THUMB( sub sp, #4 ) + push {fpreg, ip, lr ARM(, pc)} + +UNWIND( .setfp fpreg, ip, #-4 ) + sub fpreg, ip, #4 mov sp, r2 mov r2, r0 mov r0, r1 - badr lr, 1f - ret r2 + bl_r r2 -1: ldr lr, [sp] - ldr sp, [sp, #4] + ldmdb fpreg, {fpreg, ip, lr} + mov sp, ip ret lr +UNWIND( .fnend ) ENDPROC(call_with_stack) --
Quoted 2 lines
2.30.2
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 8/9] ARM: call_with_stack: add unwind support
Quoted 33 lines · Arnd Bergmann
Quoted 5 lines · Ard Biesheuvel
Restructure the code and add the unwind annotations so that both the frame pointer unwinder as well as the ELF unwind info based unwinder will be able to follow the call stack through
call_with_stack().Quoted 7 lines
Note that the former cannot support GCC and Clang at the same time, as they use a different idiom for the prologue/epilogue. So the code uses the GCC idiom, adding full frame pointer based unwind support for GCC while preserving the existing behavior of the Clang version, which simply omits
call_with_stack()from its call stack.Signed-off-by Ard Biesheuvel <[email protected]>I would like Nick to take a look at this for the clang support, he spent some time on getting the frame pointer unwinder working with clang, so he may have additional comments about this.
Quoted 14 lines
--- arch/arm/lib/call_with_stack.S | 44 +++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-)arch/arm/lib/call_with_stack.S +1
-0@@ -8,25 +8,57 @@ #include <linux/linkage.h> #include <asm/assembler.h> +#include <asm/unwind.h>
Quoted 13 lines
arch/arm/lib/call_with_stack.S line 25
Quoted 13 lines
arch/arm/lib/call_with_stack.S +8
-0/* * void call_with_stack(void (*fn)(void *), void *arg, void *sp) * * Change the stack to that pointed at by sp, then invoke fn(arg) with * the new stack. + * + * The sequence below follows the APCS frame convention for frame pointer + * unwinding, and implements the unwinder annotations needed by the EABI + * unwinder. + */ + +#if defined(CONFIG_THUMB2_KERNEL) || \ + (defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_CLANG))
Doesn't clang use r11 (fp) as the frame pointer in ARM mode?
https://godbolt.org/z/1x4x99M1x
Or is this what you meant by "So the best we can do here is not touch the frame pointer at all"?
Quoted 6 lines
arch/arm/lib/call_with_stack.S line 31
Quoted 6 lines
arch/arm/lib/call_with_stack.S +6
-0+/* + * Thumb-2 builds must use R7 as the frame pointer due to the way our unwind + * info based unwinder is constructed. + * + * The code below uses the GCC idiom for managing the frame pointer in the + * function prologue and epilogue, which Clang does not support. So the best we
IIRC, it's only slightly different; it's just that FP points to the previous FP in clang, rather than LR; at a fixed offset. At least when looking through Doug's notes and diagrams:
https://lore.kernel.org/lkml/20210507135509.1.I5d969beafa0d7507f1e37fadaa6e4d88d428253d@changeid/
Though looking at the diagram, it looks like neither toolchain implements APCS...did I understand that correctly?
There's also some documentation in
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/kernel/stacktrace.c#n11
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/lib/backtrace-clang.S#n31
I guess I'm more so curious about this code when built with clang, both before and after this patch. Was it broken for either unwinder on ARM or THUMB2+UNWINDER_ARM? Does it regress with this patch? What's the best way to test/verify this?
Quoted 5 lines
arch/arm/lib/call_with_stack.S line 36
Quoted 5 lines
arch/arm/lib/call_with_stack.S +4
-0+ * can do here is not touch the frame pointer at all: this will simply omit + * this frame when unwinding the call stack. So use R7 in this case as well, + * and leave R11 unmodified. */ + fpreg .req r7
TIL about .req: https://sourceware.org/binutils/docs/as/ARM-Directives.html
This patch demonstrates the usage of quite a few of these!
Quoted 37 lines
Quoted 37 lines
arch/arm/lib/call_with_stack.S +19
-7+#else + fpreg .req fp +#endif + ENTRY(call_with_stack) - str sp, [r2, #-4]! - str lr, [r2, #-4]! +UNWIND( .fnstart ) +UNWIND( .movsp ip ) + mov ip, sp + +UNWIND( .pad #4 ) +UNWIND( .save {fpreg, ip, lr} ) +THUMB( sub sp, #4 ) + push {fpreg, ip, lr ARM(, pc)} + +UNWIND( .setfp fpreg, ip, #-4 ) + sub fpreg, ip, #4 mov sp, r2 mov r2, r0 mov r0, r1 - badr lr, 1f - ret r2 + bl_r r2 -1: ldr lr, [sp] - ldr sp, [sp, #4] + ldmdb fpreg, {fpreg, ip, lr} + mov sp, ip ret lr +UNWIND( .fnend ) ENDPROC(call_with_stack) --2.30.2
Signature · 2 lines
Thanks, ~Nick Desaulniers
Re: [PATCH v2 8/9] ARM: call_with_stack: add unwind support
Quoted 45 lines · Nick Desaulniers
Quoted 43 lines · Arnd Bergmann
Quoted 5 lines · Ard Biesheuvel
Restructure the code and add the unwind annotations so that both the frame pointer unwinder as well as the ELF unwind info based unwinder will be able to follow the call stack through
call_with_stack().Quoted 7 lines
Note that the former cannot support GCC and Clang at the same time, as they use a different idiom for the prologue/epilogue. So the code uses the GCC idiom, adding full frame pointer based unwind support for GCC while preserving the existing behavior of the Clang version, which simply omits
call_with_stack()from its call stack.Signed-off-by Ard Biesheuvel <[email protected]>I would like Nick to take a look at this for the clang support, he spent some time on getting the frame pointer unwinder working with clang, so he may have additional comments about this.
Quoted 24 lines
--- arch/arm/lib/call_with_stack.S | 44 +++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-)arch/arm/lib/call_with_stack.S +6
-0@@ -8,25 +8,57 @@ #include <linux/linkage.h> #include <asm/assembler.h> +#include <asm/unwind.h> /* * void call_with_stack(void (*fn)(void *), void *arg, void *sp) * * Change the stack to that pointed at by sp, then invoke fn(arg) with * the new stack. + * + * The sequence below follows the APCS frame convention for frame pointer + * unwinding, and implements the unwinder annotations needed by the EABI + * unwinder. + */
Quoted 9 lines
Quoted 3 lines
arch/arm/lib/call_with_stack.S line 25
Quoted 3 lines
arch/arm/lib/call_with_stack.S +3
-0+ +#if defined(CONFIG_THUMB2_KERNEL) || \ + (defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_CLANG))Doesn't clang use r11 (fp) as the frame pointer in ARM mode?
https://godbolt.org/z/1x4x99M1x
Or is this what you meant by "So the best we can do here is not touch the frame pointer at all"?
Yes. Both unwinders expect to see the exact prologue that the respective compiler generates, and there is no way we can do both at the same time.
So by using r7 instead of r11, the call_with_stack() frame simply disappears from the backtrace, which is unfortunate but not the end of the world.
If someone wants to create a Clang clone of call_with_stack.S to work around this, I wouldn't obje
Quoted 11 lines
Quoted 6 lines
arch/arm/lib/call_with_stack.S line 31
Quoted 6 lines
arch/arm/lib/call_with_stack.S +6
-0+/* + * Thumb-2 builds must use R7 as the frame pointer due to the way our unwind + * info based unwinder is constructed. + * + * The code below uses the GCC idiom for managing the frame pointer in the + * function prologue and epilogue, which Clang does not support. So the best weIIRC, it's only slightly different; it's just that FP points to the previous FP in clang, rather than LR; at a fixed offset. At least when looking through Doug's notes and diagrams:
GCC stores {fp, sp, lr, pc}, and makes FP point at PC. The fact that they are only slightly different doesn't help - we either emit one or the other, but we cannot do both.
https://lore.kernel.org/lkml/20210507135509.1.I5d969beafa0d7507f1e37fadaa6e4d88d428253d@changeid/
Quoted 12 lines
Though looking at the diagram, it looks like neither toolchain implements APCS...did I understand that correctly?
There's also some documentation in
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/kernel/stacktrace.c#n11
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/lib/backtrace-clang.S#n31I guess I'm more so curious about this code when built with clang, both before and after this patch. Was it broken for either unwinder on ARM or THUMB2+UNWINDER_ARM? Does it regress with this patch? What's the best way to test/verify this?
Unwinding using unwind info as definitely broken, since there is no way to track the SP change. Unwinding using frame pointers probably worked, but call_switch_stack() itself would just not show up. However, there are some heuristics in the frame pointer unwinder about the next frame always being above the previous one, and so it also depends on where the new stack lives in memory wrt to the old one.
The reason I am fixing this is so that the next patch doesn't result in cases where we cannot tell from a backtrace where do_softirq() was called from, which would be annoying.
Quoted 52 lines
Quoted 5 lines
arch/arm/lib/call_with_stack.S line 36
Quoted 5 lines
arch/arm/lib/call_with_stack.S +4
-0+ * can do here is not touch the frame pointer at all: this will simply omit + * this frame when unwinding the call stack. So use R7 in this case as well, + * and leave R11 unmodified. */ + fpreg .req r7TIL about
.req: https://sourceware.org/binutils/docs/as/ARM-Directives.html
This patch demonstrates the usage of quite a few of these!Quoted 27 lines
Quoted 27 lines
arch/arm/lib/call_with_stack.S +16
-4+#else + fpreg .req fp +#endif + ENTRY(call_with_stack) - str sp, [r2, #-4]! - str lr, [r2, #-4]! +UNWIND( .fnstart ) +UNWIND( .movsp ip ) + mov ip, sp + +UNWIND( .pad #4 ) +UNWIND( .save {fpreg, ip, lr} ) +THUMB( sub sp, #4 ) + push {fpreg, ip, lr ARM(, pc)} + +UNWIND( .setfp fpreg, ip, #-4 ) + sub fpreg, ip, #4 mov sp, r2 mov r2, r0 mov r0, r1 - badr lr, 1f - ret r2 + bl_r r2Quoted 10 lines
Quoted 10 lines
arch/arm/lib/call_with_stack.S +3
-3-1: ldr lr, [sp] - ldr sp, [sp, #4] + ldmdb fpreg, {fpreg, ip, lr} + mov sp, ip ret lr +UNWIND( .fnend ) ENDPROC(call_with_stack) --2.30.2
--
Thanks,
~Nick Desaulniers
PATCH v2 9/9 ARM: run softirqs on the per-CPU IRQ stack
In reply to Ard BiesheuvelNow that we have enabled IRQ stacks, any softIRQs that are handled over the back of a hard IRQ will run from the IRQ stack as well. However, any synchronous softirq processing that happens when re-enabling softIRQs from task context will still execute on that task's stack.
So let's wire up the existing infrastructure to run these softIRQs from the IRQ stack as well.
--- arch/arm/Kconfig | 2 ++ arch/arm/kernel/irq.c | 9 +++++++++ 2 files changed, 11 insertions(+)
arch/arm/Kconfig +2 -0
@@ -1166,6 +1166,8 @@ config CURRENT_POINTER_IN_TPIDRURO config IRQSTACKS def_bool y depends on GENERIC_IRQ_MULTI_HANDLER && THREAD_INFO_IN_TASK + select HAVE_IRQ_EXIT_ON_IRQ_STACK + select HAVE_SOFTIRQ_ON_OWN_STACK config ARM_CPU_TOPOLOGY bool "Support cpu topology definition"
arch/arm/kernel/irq.c +9 -0
@@ -36,11 +36,14 @@#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-uniphier.h> #include <asm/outercache.h> +#include <asm/softirq_stack.h> #include <asm/exception.h> #include <asm/mach/arch.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> +#include "reboot.h" +unsigned long irq_err_count;#ifdef CONFIG_IRQSTACKS
@@ -60,6 +63,12 @@ static void __init init_irq_stacks(void) } } +void do_softirq_own_stack (void ) +{ +call_with_stack ((void *)__do_softirq,NULL , +__this_cpu_read (irq_stack_ptr)); +} +#endif int arch_show_interrupts (struct seq_file *p,int prec)
Signature · 7 lines
2.30.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 9/9] ARM: run softirqs on the per-CPU IRQ stack
Quoted 10 lines · Ard Biesheuvel
Now that we have enabled IRQ stacks, any softIRQs that are handled over the back of a hard IRQ will run from the IRQ stack as well. However, any synchronous softirq processing that happens when re-enabling softIRQs from task context will still execute on that task's stack.
So let's wire up the existing infrastructure to run these softIRQs from the IRQ stack as well.
Signed-off-by Ard Biesheuvel <[email protected]>
The change looks reasonable, but maybe try to explain why it is a good idea to do this.
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 9/9] ARM: run softirqs on the per-CPU IRQ stack
Quoted 11 lines · Arnd Bergmann
Quoted 9 lines · Ard Biesheuvel
Now that we have enabled IRQ stacks, any softIRQs that are handled over the back of a hard IRQ will run from the IRQ stack as well. However, any synchronous softirq processing that happens when re-enabling softIRQs from task context will still execute on that task's stack.
So let's wire up the existing infrastructure to run these softIRQs from the IRQ stack as well.
Quoted 6 lines
Quoted 1 line
Signed-off-by Ard Biesheuvel <[email protected]>The change looks reasonable, but maybe try to explain why it is a good idea to do this.
Reviewed-by Arnd Bergmann <[email protected]>
Sure. I will add something along the lines of
"""
Since any call to local_bh_enable() at any level in the task's call stack may trigger a softIRQ processing run, which could potentially cause a task stack overflow if the combined stack footprints exceed the stack's size, let's run these synchronous invocations of do_softirq() on the IRQ stack as well.
"""
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Quoted 10 lines · Ard Biesheuvel
Ard Biesheuvel (9):
ARM: remove some dead code
ARM: assembler: introducebl_randbl_mmacros
ARM: optimize indirect call tohandle_arch_irqfor v7 cores
ARM: unwind: support unwinding across multiple stacks
ARM: exportdump_mem()to other objects
ARM: unwind: dump exception stack from calling frame
ARM: implement IRQ stacks
ARM:call_with_stack: add unwind support
ARM: run softirqs on the per-CPU IRQ stack
I've been testing these patches on a Raspberry PI 2B (quad v7), doing kernel builds and other modest workloads.
Signature · 1 line
-keith
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hi Ard,
Quoted 6 lines · Ard Biesheuvel
Compared to user space, the kernel's task stacks are tiny and inflexible, as we don't grow them dynamically using demand paging. This is the reason we tend to obsess about functions with disproportionately large stack frames, given that it is hard to predict statically how calls to those functions may combine at runtime, and exhaust the stack and crash the kernel.
While I do not have the bandwidth to make an in-depth review (and parse and run the assembly in my head...)
I do get the overall picture and this is overall a very nice improvement so FWIW:
for the entire patch series.
If you want me to test this on some exotic system (such as the ARMv4 footbridge or IXP4xx BE) tell me and I'll try to make time for it!
Yours,
Linus Walleij
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel