1 | /* |
2 | * Originally written by Glenn Engel, Lake Stevens Instrument Division |
3 | * |
4 | * Contributed by HP Systems |
5 | * |
6 | * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse |
7 | * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> |
8 | * |
9 | * Copyright (C) 1995 Andreas Busse |
10 | * |
11 | * Copyright (C) 2003 MontaVista Software Inc. |
12 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net |
13 | * |
14 | * Copyright (C) 2004-2005 MontaVista Software Inc. |
15 | * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com |
16 | * |
17 | * Copyright (C) 2007-2008 Wind River Systems, Inc. |
18 | * Author/Maintainer: Jason Wessel, jason.wessel@windriver.com |
19 | * |
20 | * This file is licensed under the terms of the GNU General Public License |
21 | * version 2. This program is licensed "as is" without any warranty of any |
22 | * kind, whether express or implied. |
23 | */ |
24 | |
25 | #include <linux/ptrace.h> /* for linux pt_regs struct */ |
26 | #include <linux/kgdb.h> |
27 | #include <linux/kdebug.h> |
28 | #include <linux/sched.h> |
29 | #include <linux/smp.h> |
30 | #include <asm/inst.h> |
31 | #include <asm/fpu.h> |
32 | #include <asm/cacheflush.h> |
33 | #include <asm/processor.h> |
34 | #include <asm/sigcontext.h> |
35 | #include <asm/irq_regs.h> |
36 | |
37 | static struct hard_trap_info { |
38 | unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ |
39 | unsigned char signo; /* Signal that we map this trap into */ |
40 | } hard_trap_info[] = { |
41 | { 6, SIGBUS }, /* instruction bus error */ |
42 | { 7, SIGBUS }, /* data bus error */ |
43 | { 9, SIGTRAP }, /* break */ |
44 | /* { 11, SIGILL }, */ /* CPU unusable */ |
45 | { 12, SIGFPE }, /* overflow */ |
46 | { 13, SIGTRAP }, /* trap */ |
47 | { 14, SIGSEGV }, /* virtual instruction cache coherency */ |
48 | { 15, SIGFPE }, /* floating point exception */ |
49 | { 23, SIGSEGV }, /* watch */ |
50 | { 31, SIGSEGV }, /* virtual data cache coherency */ |
51 | { 0, 0} /* Must be last */ |
52 | }; |
53 | |
54 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
55 | { |
56 | { "zero" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, |
57 | { "at" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, |
58 | { "v0" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, |
59 | { "v1" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, |
60 | { "a0" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, |
61 | { "a1" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, |
62 | { "a2" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, |
63 | { "a3" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, |
64 | { "t0" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, |
65 | { "t1" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, |
66 | { "t2" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, |
67 | { "t3" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, |
68 | { "t4" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, |
69 | { "t5" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, |
70 | { "t6" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, |
71 | { "t7" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, |
72 | { "s0" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, |
73 | { "s1" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, |
74 | { "s2" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, |
75 | { "s3" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, |
76 | { "s4" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, |
77 | { "s5" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, |
78 | { "s6" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, |
79 | { "s7" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, |
80 | { "t8" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, |
81 | { "t9" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, |
82 | { "k0" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, |
83 | { "k1" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, |
84 | { "gp" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, |
85 | { "sp" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, |
86 | { "s8" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, |
87 | { "ra" , GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, |
88 | { "sr" , GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, |
89 | { "lo" , GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, |
90 | { "hi" , GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, |
91 | { "bad" , GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, |
92 | { "cause" , GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, |
93 | { "pc" , GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, |
94 | { "f0" , GDB_SIZEOF_REG, 0 }, |
95 | { "f1" , GDB_SIZEOF_REG, 1 }, |
96 | { "f2" , GDB_SIZEOF_REG, 2 }, |
97 | { "f3" , GDB_SIZEOF_REG, 3 }, |
98 | { "f4" , GDB_SIZEOF_REG, 4 }, |
99 | { "f5" , GDB_SIZEOF_REG, 5 }, |
100 | { "f6" , GDB_SIZEOF_REG, 6 }, |
101 | { "f7" , GDB_SIZEOF_REG, 7 }, |
102 | { "f8" , GDB_SIZEOF_REG, 8 }, |
103 | { "f9" , GDB_SIZEOF_REG, 9 }, |
104 | { "f10" , GDB_SIZEOF_REG, 10 }, |
105 | { "f11" , GDB_SIZEOF_REG, 11 }, |
106 | { "f12" , GDB_SIZEOF_REG, 12 }, |
107 | { "f13" , GDB_SIZEOF_REG, 13 }, |
108 | { "f14" , GDB_SIZEOF_REG, 14 }, |
109 | { "f15" , GDB_SIZEOF_REG, 15 }, |
110 | { "f16" , GDB_SIZEOF_REG, 16 }, |
111 | { "f17" , GDB_SIZEOF_REG, 17 }, |
112 | { "f18" , GDB_SIZEOF_REG, 18 }, |
113 | { "f19" , GDB_SIZEOF_REG, 19 }, |
114 | { "f20" , GDB_SIZEOF_REG, 20 }, |
115 | { "f21" , GDB_SIZEOF_REG, 21 }, |
116 | { "f22" , GDB_SIZEOF_REG, 22 }, |
117 | { "f23" , GDB_SIZEOF_REG, 23 }, |
118 | { "f24" , GDB_SIZEOF_REG, 24 }, |
119 | { "f25" , GDB_SIZEOF_REG, 25 }, |
120 | { "f26" , GDB_SIZEOF_REG, 26 }, |
121 | { "f27" , GDB_SIZEOF_REG, 27 }, |
122 | { "f28" , GDB_SIZEOF_REG, 28 }, |
123 | { "f29" , GDB_SIZEOF_REG, 29 }, |
124 | { "f30" , GDB_SIZEOF_REG, 30 }, |
125 | { "f31" , GDB_SIZEOF_REG, 31 }, |
126 | { "fsr" , GDB_SIZEOF_REG, 0 }, |
127 | { "fir" , GDB_SIZEOF_REG, 0 }, |
128 | }; |
129 | |
130 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
131 | { |
132 | int fp_reg; |
133 | |
134 | if (regno < 0 || regno >= DBG_MAX_REG_NUM) |
135 | return -EINVAL; |
136 | |
137 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { |
138 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
139 | dbg_reg_def[regno].size); |
140 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { |
141 | /* FP registers 38 -> 69 */ |
142 | if (!(regs->cp0_status & ST0_CU1)) |
143 | return 0; |
144 | if (regno == 70) { |
145 | /* Process the fcr31/fsr (register 70) */ |
146 | memcpy((void *)¤t->thread.fpu.fcr31, mem, |
147 | dbg_reg_def[regno].size); |
148 | goto out_save; |
149 | } else if (regno == 71) { |
150 | /* Ignore the fir (register 71) */ |
151 | goto out_save; |
152 | } |
153 | fp_reg = dbg_reg_def[regno].offset; |
154 | memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, |
155 | dbg_reg_def[regno].size); |
156 | out_save: |
157 | restore_fp(current); |
158 | } |
159 | |
160 | return 0; |
161 | } |
162 | |
163 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
164 | { |
165 | int fp_reg; |
166 | |
167 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
168 | return NULL; |
169 | |
170 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { |
171 | /* First 38 registers */ |
172 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
173 | dbg_reg_def[regno].size); |
174 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { |
175 | /* FP registers 38 -> 69 */ |
176 | if (!(regs->cp0_status & ST0_CU1)) |
177 | goto out; |
178 | save_fp(current); |
179 | if (regno == 70) { |
180 | /* Process the fcr31/fsr (register 70) */ |
181 | memcpy(mem, (void *)¤t->thread.fpu.fcr31, |
182 | dbg_reg_def[regno].size); |
183 | goto out; |
184 | } else if (regno == 71) { |
185 | /* Ignore the fir (register 71) */ |
186 | memset(mem, 0, dbg_reg_def[regno].size); |
187 | goto out; |
188 | } |
189 | fp_reg = dbg_reg_def[regno].offset; |
190 | memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], |
191 | dbg_reg_def[regno].size); |
192 | } |
193 | |
194 | out: |
195 | return dbg_reg_def[regno].name; |
196 | |
197 | } |
198 | |
199 | void arch_kgdb_breakpoint(void) |
200 | { |
201 | __asm__ __volatile__( |
202 | ".globl breakinst\n\t" |
203 | ".set\tnoreorder\n\t" |
204 | "nop\n" |
205 | "breakinst:\tbreak\n\t" |
206 | "nop\n\t" |
207 | ".set\treorder" ); |
208 | } |
209 | |
210 | static int compute_signal(int tt) |
211 | { |
212 | struct hard_trap_info *ht; |
213 | |
214 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) |
215 | if (ht->tt == tt) |
216 | return ht->signo; |
217 | |
218 | return SIGHUP; /* default for things we don't know about */ |
219 | } |
220 | |
221 | /* |
222 | * Similar to regs_to_gdb_regs() except that process is sleeping and so |
223 | * we may not be able to get all the info. |
224 | */ |
225 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
226 | { |
227 | int reg; |
228 | #if (KGDB_GDB_REG_SIZE == 32) |
229 | u32 *ptr = (u32 *)gdb_regs; |
230 | #else |
231 | u64 *ptr = (u64 *)gdb_regs; |
232 | #endif |
233 | |
234 | for (reg = 0; reg < 16; reg++) |
235 | *(ptr++) = 0; |
236 | |
237 | /* S0 - S7 */ |
238 | *(ptr++) = p->thread.reg16; |
239 | *(ptr++) = p->thread.reg17; |
240 | *(ptr++) = p->thread.reg18; |
241 | *(ptr++) = p->thread.reg19; |
242 | *(ptr++) = p->thread.reg20; |
243 | *(ptr++) = p->thread.reg21; |
244 | *(ptr++) = p->thread.reg22; |
245 | *(ptr++) = p->thread.reg23; |
246 | |
247 | for (reg = 24; reg < 28; reg++) |
248 | *(ptr++) = 0; |
249 | |
250 | /* GP, SP, FP, RA */ |
251 | *(ptr++) = (long)p; |
252 | *(ptr++) = p->thread.reg29; |
253 | *(ptr++) = p->thread.reg30; |
254 | *(ptr++) = p->thread.reg31; |
255 | |
256 | *(ptr++) = p->thread.cp0_status; |
257 | |
258 | /* lo, hi */ |
259 | *(ptr++) = 0; |
260 | *(ptr++) = 0; |
261 | |
262 | /* |
263 | * BadVAddr, Cause |
264 | * Ideally these would come from the last exception frame up the stack |
265 | * but that requires unwinding, otherwise we can't know much for sure. |
266 | */ |
267 | *(ptr++) = 0; |
268 | *(ptr++) = 0; |
269 | |
270 | /* |
271 | * PC |
272 | * use return address (RA), i.e. the moment after return from resume() |
273 | */ |
274 | *(ptr++) = p->thread.reg31; |
275 | } |
276 | |
277 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) |
278 | { |
279 | regs->cp0_epc = pc; |
280 | } |
281 | |
282 | /* |
283 | * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, |
284 | * then try to fall into the debugger |
285 | */ |
286 | static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, |
287 | void *ptr) |
288 | { |
289 | struct die_args *args = (struct die_args *)ptr; |
290 | struct pt_regs *regs = args->regs; |
291 | int trap = (regs->cp0_cause & 0x7c) >> 2; |
292 | |
293 | #ifdef CONFIG_KPROBES |
294 | /* |
295 | * Return immediately if the kprobes fault notifier has set |
296 | * DIE_PAGE_FAULT. |
297 | */ |
298 | if (cmd == DIE_PAGE_FAULT) |
299 | return NOTIFY_DONE; |
300 | #endif /* CONFIG_KPROBES */ |
301 | |
302 | /* Userspace events, ignore. */ |
303 | if (user_mode(regs)) |
304 | return NOTIFY_DONE; |
305 | |
306 | if (atomic_read(v: &kgdb_active) != -1) |
307 | kgdb_nmicallback(smp_processor_id(), regs); |
308 | |
309 | if (kgdb_handle_exception(ex_vector: trap, signo: compute_signal(tt: trap), err_code: cmd, regs)) |
310 | return NOTIFY_DONE; |
311 | |
312 | if (atomic_read(v: &kgdb_setting_breakpoint)) |
313 | if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst)) |
314 | regs->cp0_epc += 4; |
315 | |
316 | /* In SMP mode, __flush_cache_all does IPI */ |
317 | local_irq_enable(); |
318 | __flush_cache_all(); |
319 | |
320 | return NOTIFY_STOP; |
321 | } |
322 | |
323 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP |
324 | int kgdb_ll_trap(int cmd, const char *str, |
325 | struct pt_regs *regs, long err, int trap, int sig) |
326 | { |
327 | struct die_args args = { |
328 | .regs = regs, |
329 | .str = str, |
330 | .err = err, |
331 | .trapnr = trap, |
332 | .signr = sig, |
333 | |
334 | }; |
335 | |
336 | if (!kgdb_io_module_registered) |
337 | return NOTIFY_DONE; |
338 | |
339 | return kgdb_mips_notify(NULL, cmd, ptr: &args); |
340 | } |
341 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ |
342 | |
343 | static struct notifier_block kgdb_notifier = { |
344 | .notifier_call = kgdb_mips_notify, |
345 | }; |
346 | |
347 | /* |
348 | * Handle the 'c' command |
349 | */ |
350 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
351 | char *remcom_in_buffer, char *remcom_out_buffer, |
352 | struct pt_regs *regs) |
353 | { |
354 | char *ptr; |
355 | unsigned long address; |
356 | |
357 | switch (remcom_in_buffer[0]) { |
358 | case 'c': |
359 | /* handle the optional parameter */ |
360 | ptr = &remcom_in_buffer[1]; |
361 | if (kgdb_hex2long(ptr: &ptr, long_val: &address)) |
362 | regs->cp0_epc = address; |
363 | |
364 | return 0; |
365 | } |
366 | |
367 | return -1; |
368 | } |
369 | |
370 | const struct kgdb_arch arch_kgdb_ops = { |
371 | #ifdef CONFIG_CPU_BIG_ENDIAN |
372 | .gdb_bpt_instr = { spec_op << 2, 0x00, 0x00, break_op }, |
373 | #else |
374 | .gdb_bpt_instr = { break_op, 0x00, 0x00, spec_op << 2 }, |
375 | #endif |
376 | }; |
377 | |
378 | int kgdb_arch_init(void) |
379 | { |
380 | register_die_notifier(nb: &kgdb_notifier); |
381 | |
382 | return 0; |
383 | } |
384 | |
385 | /* |
386 | * kgdb_arch_exit - Perform any architecture specific uninitalization. |
387 | * |
388 | * This function will handle the uninitalization of any architecture |
389 | * specific callbacks, for dynamic registration and unregistration. |
390 | */ |
391 | void kgdb_arch_exit(void) |
392 | { |
393 | unregister_die_notifier(nb: &kgdb_notifier); |
394 | } |
395 | |