mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
arm64: reduce stack use in irq_handler
The code for switching to irq_stack stores three pieces of information on the stack, fp+lr, as a fake stack frame (that lets us walk back onto the interrupted tasks stack frame), and the address of the struct pt_regs that contains the register values from kernel entry. (which dump_backtrace() will print in any stack trace). To reduce this, we store fp, and the pointer to the struct pt_regs. unwind_frame() can recognise this as the irq_stack dummy frame, (as it only appears at the top of the irq_stack), and use the struct pt_regs values to find the missing interrupted link-register. Suggested-by: Will Deacon <will.deacon@arm.com> Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
@@ -70,17 +70,30 @@ int notrace unwind_frame(struct stackframe *frame)
|
||||
* Check whether we are going to walk through from interrupt stack
|
||||
* to task stack.
|
||||
* If we reach the end of the stack - and its an interrupt stack,
|
||||
* read the original task stack pointer from the dummy frame.
|
||||
* unpack the dummy frame to find the original elr.
|
||||
*
|
||||
* Check the frame->fp we read from the bottom of the irq_stack,
|
||||
* and the original task stack pointer are both in current->stack.
|
||||
*/
|
||||
if (frame->sp == irq_stack_ptr) {
|
||||
struct pt_regs *irq_args;
|
||||
unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
|
||||
|
||||
if(object_is_on_stack((void *)orig_sp) &&
|
||||
object_is_on_stack((void *)frame->fp))
|
||||
if (object_is_on_stack((void *)orig_sp) &&
|
||||
object_is_on_stack((void *)frame->fp)) {
|
||||
frame->sp = orig_sp;
|
||||
|
||||
/* orig_sp is the saved pt_regs, find the elr */
|
||||
irq_args = (struct pt_regs *)orig_sp;
|
||||
frame->pc = irq_args->pc;
|
||||
} else {
|
||||
/*
|
||||
* This frame has a non-standard format, and we
|
||||
* didn't fix it, because the data looked wrong.
|
||||
* Refuse to output this frame.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user