aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2011-11-29 19:23:13 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-12-07 22:02:23 -0500
commit760ca4dc90e624eb8f7ff85a5925151e25577758 (patch)
treeecdcf387c51b5752206fb546945b1f1ccd27b884 /arch/powerpc/kernel/traps.c
parent8c27474a252e84e8a71ae4a43e18f0193a08e3f7 (diff)
powerpc: Rework die()
Our die() code was based off a very old x86 version. Update it to mirror the current x86 code. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c128
1 files changed, 73 insertions, 55 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 014f88f03d3f..c091527efd89 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -98,18 +98,14 @@ static void pmac_backlight_unblank(void)
98static inline void pmac_backlight_unblank(void) { } 98static inline void pmac_backlight_unblank(void) { }
99#endif 99#endif
100 100
101int die(const char *str, struct pt_regs *regs, long err) 101static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
102static int die_owner = -1;
103static unsigned int die_nest_count;
104static int die_counter;
105
106static unsigned __kprobes long oops_begin(struct pt_regs *regs)
102{ 107{
103 static struct { 108 int cpu;
104 raw_spinlock_t lock;
105 u32 lock_owner;
106 int lock_owner_depth;
107 } die = {
108 .lock = __RAW_SPIN_LOCK_UNLOCKED(die.lock),
109 .lock_owner = -1,
110 .lock_owner_depth = 0
111 };
112 static int die_counter;
113 unsigned long flags; 109 unsigned long flags;
114 110
115 if (debugger(regs)) 111 if (debugger(regs))
@@ -117,50 +113,37 @@ int die(const char *str, struct pt_regs *regs, long err)
117 113
118 oops_enter(); 114 oops_enter();
119 115
120 if (die.lock_owner != raw_smp_processor_id()) { 116 /* racy, but better than risking deadlock. */
121 console_verbose(); 117 raw_local_irq_save(flags);
122 raw_spin_lock_irqsave(&die.lock, flags); 118 cpu = smp_processor_id();
123 die.lock_owner = smp_processor_id(); 119 if (!arch_spin_trylock(&die_lock)) {
124 die.lock_owner_depth = 0; 120 if (cpu == die_owner)
125 bust_spinlocks(1); 121 /* nested oops. should stop eventually */;
126 if (machine_is(powermac)) 122 else
127 pmac_backlight_unblank(); 123 arch_spin_lock(&die_lock);
128 } else {
129 local_save_flags(flags);
130 }
131
132 if (++die.lock_owner_depth < 3) {
133 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
134#ifdef CONFIG_PREEMPT
135 printk("PREEMPT ");
136#endif
137#ifdef CONFIG_SMP
138 printk("SMP NR_CPUS=%d ", NR_CPUS);
139#endif
140#ifdef CONFIG_DEBUG_PAGEALLOC
141 printk("DEBUG_PAGEALLOC ");
142#endif
143#ifdef CONFIG_NUMA
144 printk("NUMA ");
145#endif
146 printk("%s\n", ppc_md.name ? ppc_md.name : "");
147
148 if (notify_die(DIE_OOPS, str, regs, err, 255,
149 SIGSEGV) == NOTIFY_STOP)
150 return 1;
151
152 print_modules();
153 show_regs(regs);
154 } else {
155 printk("Recursive die() failure, output suppressed\n");
156 } 124 }
125 die_nest_count++;
126 die_owner = cpu;
127 console_verbose();
128 bust_spinlocks(1);
129 if (machine_is(powermac))
130 pmac_backlight_unblank();
131 return flags;
132}
157 133
134static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
135 int signr)
136{
158 bust_spinlocks(0); 137 bust_spinlocks(0);
159 die.lock_owner = -1; 138 die_owner = -1;
160 add_taint(TAINT_DIE); 139 add_taint(TAINT_DIE);
140 die_nest_count--;
161 oops_exit(); 141 oops_exit();
162 printk("\n"); 142 printk("\n");
163 raw_spin_unlock_irqrestore(&die.lock, flags); 143 if (!die_nest_count)
144 /* Nest count reaches zero, release the lock. */
145 arch_spin_unlock(&die_lock);
146 raw_local_irq_restore(flags);
164 147
165 /* 148 /*
166 * A system reset (0x100) is a request to dump, so we always send 149 * A system reset (0x100) is a request to dump, so we always send
@@ -177,6 +160,9 @@ int die(const char *str, struct pt_regs *regs, long err)
177 crash_kexec_secondary(regs); 160 crash_kexec_secondary(regs);
178 } 161 }
179 162
163 if (!signr)
164 return;
165
180 /* 166 /*
181 * While our oops output is serialised by a spinlock, output 167 * While our oops output is serialised by a spinlock, output
182 * from panic() called below can race and corrupt it. If we 168 * from panic() called below can race and corrupt it. If we
@@ -190,15 +176,46 @@ int die(const char *str, struct pt_regs *regs, long err)
190 176
191 if (in_interrupt()) 177 if (in_interrupt())
192 panic("Fatal exception in interrupt"); 178 panic("Fatal exception in interrupt");
193
194 if (panic_on_oops) 179 if (panic_on_oops)
195 panic("Fatal exception"); 180 panic("Fatal exception");
181 do_exit(signr);
182}
196 183
197 do_exit(err); 184static int __kprobes __die(const char *str, struct pt_regs *regs, long err)
185{
186 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
187#ifdef CONFIG_PREEMPT
188 printk("PREEMPT ");
189#endif
190#ifdef CONFIG_SMP
191 printk("SMP NR_CPUS=%d ", NR_CPUS);
192#endif
193#ifdef CONFIG_DEBUG_PAGEALLOC
194 printk("DEBUG_PAGEALLOC ");
195#endif
196#ifdef CONFIG_NUMA
197 printk("NUMA ");
198#endif
199 printk("%s\n", ppc_md.name ? ppc_md.name : "");
200
201 if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP)
202 return 1;
203
204 print_modules();
205 show_regs(regs);
198 206
199 return 0; 207 return 0;
200} 208}
201 209
210void die(const char *str, struct pt_regs *regs, long err)
211{
212 unsigned long flags = oops_begin(regs);
213
214 if (__die(str, regs, err))
215 err = 0;
216 oops_end(flags, regs, err);
217}
218
202void user_single_step_siginfo(struct task_struct *tsk, 219void user_single_step_siginfo(struct task_struct *tsk,
203 struct pt_regs *regs, siginfo_t *info) 220 struct pt_regs *regs, siginfo_t *info)
204{ 221{
@@ -217,10 +234,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
217 "at %016lx nip %016lx lr %016lx code %x\n"; 234 "at %016lx nip %016lx lr %016lx code %x\n";
218 235
219 if (!user_mode(regs)) { 236 if (!user_mode(regs)) {
220 if (die("Exception in kernel mode", regs, signr)) 237 die("Exception in kernel mode", regs, signr);
221 return; 238 return;
222 } else if (show_unhandled_signals && 239 }
223 unhandled_signal(current, signr)) { 240
241 if (show_unhandled_signals && unhandled_signal(current, signr)) {
224 printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32, 242 printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
225 current->comm, current->pid, signr, 243 current->comm, current->pid, signr,
226 addr, regs->nip, regs->link, code); 244 addr, regs->nip, regs->link, code);