aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/dumpstack_64.c30
-rw-r--r--arch/x86/kernel/entry_64.S27
2 files changed, 15 insertions, 42 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 788295cbe4a7..19853ad8afc5 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -105,34 +105,6 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
105} 105}
106 106
107/* 107/*
108 * We are returning from the irq stack and go to the previous one.
109 * If the previous stack is also in the irq stack, then bp in the first
110 * frame of the irq stack points to the previous, interrupted one.
111 * Otherwise we have another level of indirection: We first save
112 * the bp of the previous stack, then we switch the stack to the irq one
113 * and save a new bp that links to the previous one.
114 * (See save_args())
115 */
116static inline unsigned long
117fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
118 unsigned long *irq_stack, unsigned long *irq_stack_end)
119{
120#ifdef CONFIG_FRAME_POINTER
121 struct stack_frame *frame = (struct stack_frame *)bp;
122 unsigned long next;
123
124 if (!in_irq_stack(stack, irq_stack, irq_stack_end)) {
125 if (!probe_kernel_address(&frame->next_frame, next))
126 return next;
127 else
128 WARN_ONCE(1, "Perf: bad frame pointer = %p in "
129 "callchain\n", &frame->next_frame);
130 }
131#endif
132 return bp;
133}
134
135/*
136 * x86-64 can have up to three kernel stacks: 108 * x86-64 can have up to three kernel stacks:
137 * process stack 109 * process stack
138 * interrupt stack 110 * interrupt stack
@@ -208,8 +180,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
208 * pointer (index -1 to end) in the IRQ stack: 180 * pointer (index -1 to end) in the IRQ stack:
209 */ 181 */
210 stack = (unsigned long *) (irq_stack_end[-1]); 182 stack = (unsigned long *) (irq_stack_end[-1]);
211 bp = fixup_bp_irq_link(bp, stack, irq_stack,
212 irq_stack_end);
213 irq_stack_end = NULL; 183 irq_stack_end = NULL;
214 ops->stack(data, "EOI"); 184 ops->stack(data, "EOI");
215 continue; 185 continue;
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 6131432c5afa..d656f68371a4 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -310,8 +310,11 @@ ENDPROC(native_usergs_sysret64)
310 movq_cfi r10, R10-RBP 310 movq_cfi r10, R10-RBP
311 movq_cfi r11, R11-RBP 311 movq_cfi r11, R11-RBP
312 312
313 movq_cfi rbp, 0 /* push %rbp */ 313 /* Save rbp so that we can unwind from get_irq_regs() */
314 movq %rsp, %rbp 314 movq_cfi rbp, 0
315
316 /* Save previous stack value */
317 movq %rsp, %rsi
315 318
316 leaq -RBP(%rsp),%rdi /* arg1 for handler */ 319 leaq -RBP(%rsp),%rdi /* arg1 for handler */
317 testl $3, CS(%rdi) 320 testl $3, CS(%rdi)
@@ -327,10 +330,11 @@ ENDPROC(native_usergs_sysret64)
327 jne 2f 330 jne 2f
328 mov PER_CPU_VAR(irq_stack_ptr),%rsp 331 mov PER_CPU_VAR(irq_stack_ptr),%rsp
329 EMPTY_FRAME 0 332 EMPTY_FRAME 0
330 /* 333
331 * We entered an interrupt context - irqs are off: 3342: /* Store previous stack value */
332 */ 335 pushq %rsi
3332: TRACE_IRQS_OFF 336 /* We entered an interrupt context - irqs are off: */
337 TRACE_IRQS_OFF
334 .endm 338 .endm
335 339
336ENTRY(save_rest) 340ENTRY(save_rest)
@@ -804,15 +808,14 @@ ret_from_intr:
804 DISABLE_INTERRUPTS(CLBR_NONE) 808 DISABLE_INTERRUPTS(CLBR_NONE)
805 TRACE_IRQS_OFF 809 TRACE_IRQS_OFF
806 decl PER_CPU_VAR(irq_count) 810 decl PER_CPU_VAR(irq_count)
807 leaveq
808 811
809 CFI_RESTORE rbp 812 /* Restore saved previous stack */
813 popq %rsi
814 leaq 16(%rsi), %rsp
815
810 CFI_DEF_CFA_REGISTER rsp 816 CFI_DEF_CFA_REGISTER rsp
811 CFI_ADJUST_CFA_OFFSET -8 817 CFI_ADJUST_CFA_OFFSET -16
812 818
813 /* we did not save rbx, restore only from ARGOFFSET */
814 addq $8, %rsp
815 CFI_ADJUST_CFA_OFFSET -8
816exit_intr: 819exit_intr:
817 GET_THREAD_INFO(%rcx) 820 GET_THREAD_INFO(%rcx)
818 testl $3,CS-ARGOFFSET(%rsp) 821 testl $3,CS-ARGOFFSET(%rsp)