diff options
author | David S. Miller <davem@davemloft.net> | 2010-04-14 05:04:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-14 05:04:29 -0400 |
commit | ec687886de00e1e63f3d821ccade9a61590408ed (patch) | |
tree | 093e303475754d30b679bd35ae9cc5522832057e /arch/sparc | |
parent | 035df35d968323f6f463c8789553e8589efcbcd4 (diff) |
sparc64: Run NMIs on the hardirq stack.
Otherwise we can overflow the main stack with the function tracer
enabled.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/kernel/irq_64.c | 19 | ||||
-rw-r--r-- | arch/sparc/kernel/kstack.h | 19 | ||||
-rw-r--r-- | arch/sparc/kernel/nmi.c | 7 |
3 files changed, 27 insertions, 18 deletions
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 2b04c722cc3e..830d70a3e20b 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
@@ -47,6 +47,7 @@ | |||
47 | 47 | ||
48 | #include "entry.h" | 48 | #include "entry.h" |
49 | #include "cpumap.h" | 49 | #include "cpumap.h" |
50 | #include "kstack.h" | ||
50 | 51 | ||
51 | #define NUM_IVECS (IMAP_INR + 1) | 52 | #define NUM_IVECS (IMAP_INR + 1) |
52 | 53 | ||
@@ -713,24 +714,6 @@ void ack_bad_irq(unsigned int virt_irq) | |||
713 | void *hardirq_stack[NR_CPUS]; | 714 | void *hardirq_stack[NR_CPUS]; |
714 | void *softirq_stack[NR_CPUS]; | 715 | void *softirq_stack[NR_CPUS]; |
715 | 716 | ||
716 | static __attribute__((always_inline)) void *set_hardirq_stack(void) | ||
717 | { | ||
718 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
719 | |||
720 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
721 | if (orig_sp < sp || | ||
722 | orig_sp > (sp + THREAD_SIZE)) { | ||
723 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
724 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
725 | } | ||
726 | |||
727 | return orig_sp; | ||
728 | } | ||
729 | static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
730 | { | ||
731 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
732 | } | ||
733 | |||
734 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) | 717 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) |
735 | { | 718 | { |
736 | unsigned long pstate, bucket_pa; | 719 | unsigned long pstate, bucket_pa; |
diff --git a/arch/sparc/kernel/kstack.h b/arch/sparc/kernel/kstack.h index 5247283d1c03..53dfb92e09fb 100644 --- a/arch/sparc/kernel/kstack.h +++ b/arch/sparc/kernel/kstack.h | |||
@@ -61,4 +61,23 @@ check_magic: | |||
61 | 61 | ||
62 | } | 62 | } |
63 | 63 | ||
64 | static inline __attribute__((always_inline)) void *set_hardirq_stack(void) | ||
65 | { | ||
66 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
67 | |||
68 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
69 | if (orig_sp < sp || | ||
70 | orig_sp > (sp + THREAD_SIZE)) { | ||
71 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
72 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
73 | } | ||
74 | |||
75 | return orig_sp; | ||
76 | } | ||
77 | |||
78 | static inline __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
79 | { | ||
80 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
81 | } | ||
82 | |||
64 | #endif /* _KSTACK_H */ | 83 | #endif /* _KSTACK_H */ |
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 75a3d1a25356..a4bd7ba74c89 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <asm/ptrace.h> | 23 | #include <asm/ptrace.h> |
24 | #include <asm/pcr.h> | 24 | #include <asm/pcr.h> |
25 | 25 | ||
26 | #include "kstack.h" | ||
27 | |||
26 | /* We don't have a real NMI on sparc64, but we can fake one | 28 | /* We don't have a real NMI on sparc64, but we can fake one |
27 | * up using profiling counter overflow interrupts and interrupt | 29 | * up using profiling counter overflow interrupts and interrupt |
28 | * levels. | 30 | * levels. |
@@ -92,6 +94,7 @@ static void die_nmi(const char *str, struct pt_regs *regs, int do_panic) | |||
92 | notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | 94 | notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) |
93 | { | 95 | { |
94 | unsigned int sum, touched = 0; | 96 | unsigned int sum, touched = 0; |
97 | void *orig_sp; | ||
95 | 98 | ||
96 | clear_softint(1 << irq); | 99 | clear_softint(1 << irq); |
97 | 100 | ||
@@ -99,6 +102,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
99 | 102 | ||
100 | nmi_enter(); | 103 | nmi_enter(); |
101 | 104 | ||
105 | orig_sp = set_hardirq_stack(); | ||
106 | |||
102 | if (notify_die(DIE_NMI, "nmi", regs, 0, | 107 | if (notify_die(DIE_NMI, "nmi", regs, 0, |
103 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) | 108 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) |
104 | touched = 1; | 109 | touched = 1; |
@@ -124,6 +129,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
124 | pcr_ops->write(pcr_enable); | 129 | pcr_ops->write(pcr_enable); |
125 | } | 130 | } |
126 | 131 | ||
132 | restore_hardirq_stack(orig_sp); | ||
133 | |||
127 | nmi_exit(); | 134 | nmi_exit(); |
128 | } | 135 | } |
129 | 136 | ||