Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * ppc-stub.c: KGDB support for the Linux kernel. | |
3 | * | |
4 | * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC | |
5 | * some stuff borrowed from Paul Mackerras' xmon | |
6 | * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) | |
7 | * | |
8 | * Modifications to run under Linux | |
9 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | |
10 | * | |
11 | * This file originally came from the gdb sources, and the | |
12 | * copyright notices have been retained below. | |
13 | */ | |
14 | ||
15 | /**************************************************************************** | |
16 | ||
17 | THIS SOFTWARE IS NOT COPYRIGHTED | |
18 | ||
19 | HP offers the following for use in the public domain. HP makes no | |
20 | warranty with regard to the software or its performance and the | |
21 | user accepts the software "AS IS" with all faults. | |
22 | ||
23 | HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD | |
24 | TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
25 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
26 | ||
27 | ****************************************************************************/ | |
28 | ||
29 | /**************************************************************************** | |
30 | * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ | |
31 | * | |
32 | * Module name: remcom.c $ | |
33 | * Revision: 1.34 $ | |
34 | * Date: 91/03/09 12:29:49 $ | |
35 | * Contributor: Lake Stevens Instrument Division$ | |
36 | * | |
37 | * Description: low level support for gdb debugger. $ | |
38 | * | |
39 | * Considerations: only works on target hardware $ | |
40 | * | |
41 | * Written by: Glenn Engel $ | |
42 | * ModuleState: Experimental $ | |
43 | * | |
44 | * NOTES: See Below $ | |
45 | * | |
46 | * Modified for SPARC by Stu Grossman, Cygnus Support. | |
47 | * | |
48 | * This code has been extensively tested on the Fujitsu SPARClite demo board. | |
49 | * | |
50 | * To enable debugger support, two things need to happen. One, a | |
51 | * call to set_debug_traps() is necessary in order to allow any breakpoints | |
52 | * or error conditions to be properly intercepted and reported to gdb. | |
53 | * Two, a breakpoint needs to be generated to begin communication. This | |
54 | * is most easily accomplished by a call to breakpoint(). Breakpoint() | |
55 | * simulates a breakpoint by executing a trap #1. | |
56 | * | |
57 | ************* | |
58 | * | |
59 | * The following gdb commands are supported: | |
60 | * | |
61 | * command function Return value | |
62 | * | |
63 | * g return the value of the CPU registers hex data or ENN | |
64 | * G set the value of the CPU registers OK or ENN | |
65 | * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz | |
66 | * | |
67 | * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | |
68 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | |
69 | * | |
70 | * c Resume at current address SNN ( signal NN) | |
71 | * cAA..AA Continue at address AA..AA SNN | |
72 | * | |
73 | * s Step one instruction SNN | |
74 | * sAA..AA Step one instruction from AA..AA SNN | |
75 | * | |
76 | * k kill | |
77 | * | |
78 | * ? What was the last sigval ? SNN (signal NN) | |
79 | * | |
80 | * bBB..BB Set baud rate to BB..BB OK or BNN, then sets | |
81 | * baud rate | |
82 | * | |
83 | * All commands and responses are sent with a packet which includes a | |
84 | * checksum. A packet consists of | |
85 | * | |
86 | * $<packet info>#<checksum>. | |
87 | * | |
88 | * where | |
89 | * <packet info> :: <characters representing the command or response> | |
90 | * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>> | |
91 | * | |
92 | * When a packet is received, it is first acknowledged with either '+' or '-'. | |
93 | * '+' indicates a successful transfer. '-' indicates a failed transfer. | |
94 | * | |
95 | * Example: | |
96 | * | |
97 | * Host: Reply: | |
98 | * $m0,10#2a +$00010203040506070809101112131415#42 | |
99 | * | |
100 | ****************************************************************************/ | |
101 | ||
1da177e4 LT |
102 | #include <linux/kernel.h> |
103 | #include <linux/string.h> | |
104 | #include <linux/mm.h> | |
105 | #include <linux/smp.h> | |
106 | #include <linux/smp_lock.h> | |
107 | #include <linux/init.h> | |
108 | #include <linux/sysrq.h> | |
109 | ||
110 | #include <asm/cacheflush.h> | |
111 | #include <asm/system.h> | |
112 | #include <asm/signal.h> | |
113 | #include <asm/kgdb.h> | |
114 | #include <asm/pgtable.h> | |
115 | #include <asm/ptrace.h> | |
116 | ||
117 | void breakinst(void); | |
118 | ||
119 | /* | |
120 | * BUFMAX defines the maximum number of characters in inbound/outbound buffers | |
121 | * at least NUMREGBYTES*2 are needed for register packets | |
122 | */ | |
123 | #define BUFMAX 2048 | |
124 | static char remcomInBuffer[BUFMAX]; | |
125 | static char remcomOutBuffer[BUFMAX]; | |
126 | ||
127 | static int initialized; | |
128 | static int kgdb_active; | |
129 | static int kgdb_started; | |
130 | static u_int fault_jmp_buf[100]; | |
131 | static int kdebug; | |
132 | ||
133 | ||
134 | static const char hexchars[]="0123456789abcdef"; | |
135 | ||
136 | /* Place where we save old trap entries for restoration - sparc*/ | |
137 | /* struct tt_entry kgdb_savettable[256]; */ | |
138 | /* typedef void (*trapfunc_t)(void); */ | |
139 | ||
140 | static void kgdb_fault_handler(struct pt_regs *regs); | |
141 | static int handle_exception (struct pt_regs *regs); | |
142 | ||
143 | #if 0 | |
144 | /* Install an exception handler for kgdb */ | |
145 | static void exceptionHandler(int tnum, unsigned int *tfunc) | |
146 | { | |
147 | /* We are dorking with a live trap table, all irqs off */ | |
148 | } | |
149 | #endif | |
150 | ||
151 | int | |
152 | kgdb_setjmp(long *buf) | |
153 | { | |
154 | asm ("mflr 0; stw 0,0(%0);" | |
155 | "stw 1,4(%0); stw 2,8(%0);" | |
156 | "mfcr 0; stw 0,12(%0);" | |
157 | "stmw 13,16(%0)" | |
158 | : : "r" (buf)); | |
159 | /* XXX should save fp regs as well */ | |
160 | return 0; | |
161 | } | |
162 | void | |
163 | kgdb_longjmp(long *buf, int val) | |
164 | { | |
165 | if (val == 0) | |
166 | val = 1; | |
167 | asm ("lmw 13,16(%0);" | |
168 | "lwz 0,12(%0); mtcrf 0x38,0;" | |
169 | "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" | |
170 | "mtlr 0; mr 3,%1" | |
171 | : : "r" (buf), "r" (val)); | |
172 | } | |
173 | /* Convert ch from a hex digit to an int */ | |
174 | static int | |
175 | hex(unsigned char ch) | |
176 | { | |
177 | if (ch >= 'a' && ch <= 'f') | |
178 | return ch-'a'+10; | |
179 | if (ch >= '0' && ch <= '9') | |
180 | return ch-'0'; | |
181 | if (ch >= 'A' && ch <= 'F') | |
182 | return ch-'A'+10; | |
183 | return -1; | |
184 | } | |
185 | ||
186 | /* Convert the memory pointed to by mem into hex, placing result in buf. | |
187 | * Return a pointer to the last char put in buf (null), in case of mem fault, | |
188 | * return 0. | |
189 | */ | |
190 | static unsigned char * | |
191 | mem2hex(const char *mem, char *buf, int count) | |
192 | { | |
193 | unsigned char ch; | |
194 | unsigned short tmp_s; | |
195 | unsigned long tmp_l; | |
196 | ||
197 | if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { | |
198 | debugger_fault_handler = kgdb_fault_handler; | |
199 | ||
200 | /* Accessing 16 bit and 32 bit objects in a single | |
201 | ** load instruction is required to avoid bad side | |
202 | ** effects for some IO registers. | |
203 | */ | |
204 | ||
205 | if ((count == 2) && (((long)mem & 1) == 0)) { | |
206 | tmp_s = *(unsigned short *)mem; | |
207 | mem += 2; | |
208 | *buf++ = hexchars[(tmp_s >> 12) & 0xf]; | |
209 | *buf++ = hexchars[(tmp_s >> 8) & 0xf]; | |
210 | *buf++ = hexchars[(tmp_s >> 4) & 0xf]; | |
211 | *buf++ = hexchars[tmp_s & 0xf]; | |
212 | ||
213 | } else if ((count == 4) && (((long)mem & 3) == 0)) { | |
214 | tmp_l = *(unsigned int *)mem; | |
215 | mem += 4; | |
216 | *buf++ = hexchars[(tmp_l >> 28) & 0xf]; | |
217 | *buf++ = hexchars[(tmp_l >> 24) & 0xf]; | |
218 | *buf++ = hexchars[(tmp_l >> 20) & 0xf]; | |
219 | *buf++ = hexchars[(tmp_l >> 16) & 0xf]; | |
220 | *buf++ = hexchars[(tmp_l >> 12) & 0xf]; | |
221 | *buf++ = hexchars[(tmp_l >> 8) & 0xf]; | |
222 | *buf++ = hexchars[(tmp_l >> 4) & 0xf]; | |
223 | *buf++ = hexchars[tmp_l & 0xf]; | |
224 | ||
225 | } else { | |
226 | while (count-- > 0) { | |
227 | ch = *mem++; | |
228 | *buf++ = hexchars[ch >> 4]; | |
229 | *buf++ = hexchars[ch & 0xf]; | |
230 | } | |
231 | } | |
232 | ||
233 | } else { | |
234 | /* error condition */ | |
235 | } | |
236 | debugger_fault_handler = NULL; | |
237 | *buf = 0; | |
238 | return buf; | |
239 | } | |
240 | ||
241 | /* convert the hex array pointed to by buf into binary to be placed in mem | |
242 | * return a pointer to the character AFTER the last byte written. | |
243 | */ | |
244 | static char * | |
245 | hex2mem(char *buf, char *mem, int count) | |
246 | { | |
247 | unsigned char ch; | |
248 | int i; | |
249 | char *orig_mem; | |
250 | unsigned short tmp_s; | |
251 | unsigned long tmp_l; | |
252 | ||
253 | orig_mem = mem; | |
254 | ||
255 | if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { | |
256 | debugger_fault_handler = kgdb_fault_handler; | |
257 | ||
258 | /* Accessing 16 bit and 32 bit objects in a single | |
259 | ** store instruction is required to avoid bad side | |
260 | ** effects for some IO registers. | |
261 | */ | |
262 | ||
263 | if ((count == 2) && (((long)mem & 1) == 0)) { | |
264 | tmp_s = hex(*buf++) << 12; | |
265 | tmp_s |= hex(*buf++) << 8; | |
266 | tmp_s |= hex(*buf++) << 4; | |
267 | tmp_s |= hex(*buf++); | |
268 | ||
269 | *(unsigned short *)mem = tmp_s; | |
270 | mem += 2; | |
271 | ||
272 | } else if ((count == 4) && (((long)mem & 3) == 0)) { | |
273 | tmp_l = hex(*buf++) << 28; | |
274 | tmp_l |= hex(*buf++) << 24; | |
275 | tmp_l |= hex(*buf++) << 20; | |
276 | tmp_l |= hex(*buf++) << 16; | |
277 | tmp_l |= hex(*buf++) << 12; | |
278 | tmp_l |= hex(*buf++) << 8; | |
279 | tmp_l |= hex(*buf++) << 4; | |
280 | tmp_l |= hex(*buf++); | |
281 | ||
282 | *(unsigned long *)mem = tmp_l; | |
283 | mem += 4; | |
284 | ||
285 | } else { | |
286 | for (i=0; i<count; i++) { | |
287 | ch = hex(*buf++) << 4; | |
288 | ch |= hex(*buf++); | |
289 | *mem++ = ch; | |
290 | } | |
291 | } | |
292 | ||
293 | ||
294 | /* | |
295 | ** Flush the data cache, invalidate the instruction cache. | |
296 | */ | |
297 | flush_icache_range((int)orig_mem, (int)orig_mem + count - 1); | |
298 | ||
299 | } else { | |
300 | /* error condition */ | |
301 | } | |
302 | debugger_fault_handler = NULL; | |
303 | return mem; | |
304 | } | |
305 | ||
306 | /* | |
307 | * While we find nice hex chars, build an int. | |
308 | * Return number of chars processed. | |
309 | */ | |
310 | static int | |
311 | hexToInt(char **ptr, int *intValue) | |
312 | { | |
313 | int numChars = 0; | |
314 | int hexValue; | |
315 | ||
316 | *intValue = 0; | |
317 | ||
318 | if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { | |
319 | debugger_fault_handler = kgdb_fault_handler; | |
320 | while (**ptr) { | |
321 | hexValue = hex(**ptr); | |
322 | if (hexValue < 0) | |
323 | break; | |
324 | ||
325 | *intValue = (*intValue << 4) | hexValue; | |
326 | numChars ++; | |
327 | ||
328 | (*ptr)++; | |
329 | } | |
330 | } else { | |
331 | /* error condition */ | |
332 | } | |
333 | debugger_fault_handler = NULL; | |
334 | ||
335 | return (numChars); | |
336 | } | |
337 | ||
338 | /* scan for the sequence $<data>#<checksum> */ | |
339 | static void | |
340 | getpacket(char *buffer) | |
341 | { | |
342 | unsigned char checksum; | |
343 | unsigned char xmitcsum; | |
344 | int i; | |
345 | int count; | |
346 | unsigned char ch; | |
347 | ||
348 | do { | |
349 | /* wait around for the start character, ignore all other | |
350 | * characters */ | |
351 | while ((ch = (getDebugChar() & 0x7f)) != '$') ; | |
352 | ||
353 | checksum = 0; | |
354 | xmitcsum = -1; | |
355 | ||
356 | count = 0; | |
357 | ||
358 | /* now, read until a # or end of buffer is found */ | |
359 | while (count < BUFMAX) { | |
360 | ch = getDebugChar() & 0x7f; | |
361 | if (ch == '#') | |
362 | break; | |
363 | checksum = checksum + ch; | |
364 | buffer[count] = ch; | |
365 | count = count + 1; | |
366 | } | |
367 | ||
368 | if (count >= BUFMAX) | |
369 | continue; | |
370 | ||
371 | buffer[count] = 0; | |
372 | ||
373 | if (ch == '#') { | |
374 | xmitcsum = hex(getDebugChar() & 0x7f) << 4; | |
375 | xmitcsum |= hex(getDebugChar() & 0x7f); | |
376 | if (checksum != xmitcsum) | |
377 | putDebugChar('-'); /* failed checksum */ | |
378 | else { | |
379 | putDebugChar('+'); /* successful transfer */ | |
380 | /* if a sequence char is present, reply the ID */ | |
381 | if (buffer[2] == ':') { | |
382 | putDebugChar(buffer[0]); | |
383 | putDebugChar(buffer[1]); | |
384 | /* remove sequence chars from buffer */ | |
385 | count = strlen(buffer); | |
386 | for (i=3; i <= count; i++) | |
387 | buffer[i-3] = buffer[i]; | |
388 | } | |
389 | } | |
390 | } | |
391 | } while (checksum != xmitcsum); | |
392 | } | |
393 | ||
394 | /* send the packet in buffer. */ | |
395 | static void putpacket(unsigned char *buffer) | |
396 | { | |
397 | unsigned char checksum; | |
398 | int count; | |
399 | unsigned char ch, recv; | |
400 | ||
401 | /* $<packet info>#<checksum>. */ | |
402 | do { | |
403 | putDebugChar('$'); | |
404 | checksum = 0; | |
405 | count = 0; | |
406 | ||
407 | while ((ch = buffer[count])) { | |
408 | putDebugChar(ch); | |
409 | checksum += ch; | |
410 | count += 1; | |
411 | } | |
412 | ||
413 | putDebugChar('#'); | |
414 | putDebugChar(hexchars[checksum >> 4]); | |
415 | putDebugChar(hexchars[checksum & 0xf]); | |
416 | recv = getDebugChar(); | |
417 | } while ((recv & 0x7f) != '+'); | |
418 | } | |
419 | ||
420 | static void kgdb_flush_cache_all(void) | |
421 | { | |
422 | flush_instruction_cache(); | |
423 | } | |
424 | ||
425 | /* Set up exception handlers for tracing and breakpoints | |
426 | * [could be called kgdb_init()] | |
427 | */ | |
428 | void set_debug_traps(void) | |
429 | { | |
430 | #if 0 | |
431 | unsigned char c; | |
432 | ||
433 | save_and_cli(flags); | |
434 | ||
435 | /* In case GDB is started before us, ack any packets (presumably | |
436 | * "$?#xx") sitting there. | |
437 | * | |
438 | * I've found this code causes more problems than it solves, | |
439 | * so that's why it's commented out. GDB seems to work fine | |
440 | * now starting either before or after the kernel -bwb | |
441 | */ | |
442 | ||
443 | while((c = getDebugChar()) != '$'); | |
444 | while((c = getDebugChar()) != '#'); | |
445 | c = getDebugChar(); /* eat first csum byte */ | |
446 | c = getDebugChar(); /* eat second csum byte */ | |
447 | putDebugChar('+'); /* ack it */ | |
448 | #endif | |
449 | debugger = kgdb; | |
450 | debugger_bpt = kgdb_bpt; | |
451 | debugger_sstep = kgdb_sstep; | |
452 | debugger_iabr_match = kgdb_iabr_match; | |
453 | debugger_dabr_match = kgdb_dabr_match; | |
454 | ||
455 | initialized = 1; | |
456 | } | |
457 | ||
458 | static void kgdb_fault_handler(struct pt_regs *regs) | |
459 | { | |
460 | kgdb_longjmp((long*)fault_jmp_buf, 1); | |
461 | } | |
462 | ||
463 | int kgdb_bpt(struct pt_regs *regs) | |
464 | { | |
465 | return handle_exception(regs); | |
466 | } | |
467 | ||
468 | int kgdb_sstep(struct pt_regs *regs) | |
469 | { | |
470 | return handle_exception(regs); | |
471 | } | |
472 | ||
473 | void kgdb(struct pt_regs *regs) | |
474 | { | |
475 | handle_exception(regs); | |
476 | } | |
477 | ||
478 | int kgdb_iabr_match(struct pt_regs *regs) | |
479 | { | |
480 | printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); | |
481 | return handle_exception(regs); | |
482 | } | |
483 | ||
484 | int kgdb_dabr_match(struct pt_regs *regs) | |
485 | { | |
486 | printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); | |
487 | return handle_exception(regs); | |
488 | } | |
489 | ||
490 | /* Convert the hardware trap type code to a unix signal number. */ | |
491 | /* | |
492 | * This table contains the mapping between PowerPC hardware trap types, and | |
493 | * signals, which are primarily what GDB understands. | |
494 | */ | |
495 | static struct hard_trap_info | |
496 | { | |
497 | unsigned int tt; /* Trap type code for powerpc */ | |
498 | unsigned char signo; /* Signal that we map this trap into */ | |
499 | } hard_trap_info[] = { | |
500 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | |
501 | { 0x100, SIGINT }, /* critical input interrupt */ | |
502 | { 0x200, SIGSEGV }, /* machine check */ | |
503 | { 0x300, SIGSEGV }, /* data storage */ | |
504 | { 0x400, SIGBUS }, /* instruction storage */ | |
505 | { 0x500, SIGINT }, /* interrupt */ | |
506 | { 0x600, SIGBUS }, /* alignment */ | |
507 | { 0x700, SIGILL }, /* program */ | |
508 | { 0x800, SIGILL }, /* reserved */ | |
509 | { 0x900, SIGILL }, /* reserved */ | |
510 | { 0xa00, SIGILL }, /* reserved */ | |
511 | { 0xb00, SIGILL }, /* reserved */ | |
512 | { 0xc00, SIGCHLD }, /* syscall */ | |
513 | { 0xd00, SIGILL }, /* reserved */ | |
514 | { 0xe00, SIGILL }, /* reserved */ | |
515 | { 0xf00, SIGILL }, /* reserved */ | |
516 | /* | |
517 | ** 0x1000 PIT | |
518 | ** 0x1010 FIT | |
519 | ** 0x1020 watchdog | |
520 | ** 0x1100 data TLB miss | |
521 | ** 0x1200 instruction TLB miss | |
522 | */ | |
523 | { 0x2002, SIGTRAP}, /* debug */ | |
524 | #else | |
525 | { 0x200, SIGSEGV }, /* machine check */ | |
526 | { 0x300, SIGSEGV }, /* address error (store) */ | |
527 | { 0x400, SIGBUS }, /* instruction bus error */ | |
528 | { 0x500, SIGINT }, /* interrupt */ | |
529 | { 0x600, SIGBUS }, /* alingment */ | |
530 | { 0x700, SIGTRAP }, /* breakpoint trap */ | |
531 | { 0x800, SIGFPE }, /* fpu unavail */ | |
532 | { 0x900, SIGALRM }, /* decrementer */ | |
533 | { 0xa00, SIGILL }, /* reserved */ | |
534 | { 0xb00, SIGILL }, /* reserved */ | |
535 | { 0xc00, SIGCHLD }, /* syscall */ | |
536 | { 0xd00, SIGTRAP }, /* single-step/watch */ | |
537 | { 0xe00, SIGFPE }, /* fp assist */ | |
538 | #endif | |
539 | { 0, 0} /* Must be last */ | |
540 | ||
541 | }; | |
542 | ||
543 | static int computeSignal(unsigned int tt) | |
544 | { | |
545 | struct hard_trap_info *ht; | |
546 | ||
547 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) | |
548 | if (ht->tt == tt) | |
549 | return ht->signo; | |
550 | ||
551 | return SIGHUP; /* default for things we don't know about */ | |
552 | } | |
553 | ||
554 | #define PC_REGNUM 64 | |
555 | #define SP_REGNUM 1 | |
556 | ||
557 | /* | |
558 | * This function does all command processing for interfacing to gdb. | |
559 | */ | |
560 | static int | |
561 | handle_exception (struct pt_regs *regs) | |
562 | { | |
563 | int sigval; | |
564 | int addr; | |
565 | int length; | |
566 | char *ptr; | |
567 | unsigned int msr; | |
568 | ||
569 | /* We don't handle user-mode breakpoints. */ | |
570 | if (user_mode(regs)) | |
571 | return 0; | |
572 | ||
573 | if (debugger_fault_handler) { | |
574 | debugger_fault_handler(regs); | |
575 | panic("kgdb longjump failed!\n"); | |
576 | } | |
577 | if (kgdb_active) { | |
578 | printk(KERN_ERR "interrupt while in kgdb, returning\n"); | |
579 | return 0; | |
580 | } | |
581 | ||
582 | kgdb_active = 1; | |
583 | kgdb_started = 1; | |
584 | ||
585 | #ifdef KGDB_DEBUG | |
586 | printk("kgdb: entering handle_exception; trap [0x%x]\n", | |
587 | (unsigned int)regs->trap); | |
588 | #endif | |
589 | ||
590 | kgdb_interruptible(0); | |
591 | lock_kernel(); | |
592 | msr = mfmsr(); | |
593 | mtmsr(msr & ~MSR_EE); /* disable interrupts */ | |
594 | ||
595 | if (regs->nip == (unsigned long)breakinst) { | |
596 | /* Skip over breakpoint trap insn */ | |
597 | regs->nip += 4; | |
598 | } | |
599 | ||
600 | /* reply to host that an exception has occurred */ | |
601 | sigval = computeSignal(regs->trap); | |
602 | ptr = remcomOutBuffer; | |
603 | ||
604 | *ptr++ = 'T'; | |
605 | *ptr++ = hexchars[sigval >> 4]; | |
606 | *ptr++ = hexchars[sigval & 0xf]; | |
607 | *ptr++ = hexchars[PC_REGNUM >> 4]; | |
608 | *ptr++ = hexchars[PC_REGNUM & 0xf]; | |
609 | *ptr++ = ':'; | |
610 | ptr = mem2hex((char *)®s->nip, ptr, 4); | |
611 | *ptr++ = ';'; | |
612 | *ptr++ = hexchars[SP_REGNUM >> 4]; | |
613 | *ptr++ = hexchars[SP_REGNUM & 0xf]; | |
614 | *ptr++ = ':'; | |
615 | ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); | |
616 | *ptr++ = ';'; | |
617 | *ptr++ = 0; | |
618 | ||
619 | putpacket(remcomOutBuffer); | |
620 | if (kdebug) | |
621 | printk("remcomOutBuffer: %s\n", remcomOutBuffer); | |
622 | ||
623 | /* XXX We may want to add some features dealing with poking the | |
624 | * XXX page tables, ... (look at sparc-stub.c for more info) | |
625 | * XXX also required hacking to the gdb sources directly... | |
626 | */ | |
627 | ||
628 | while (1) { | |
629 | remcomOutBuffer[0] = 0; | |
630 | ||
631 | getpacket(remcomInBuffer); | |
632 | switch (remcomInBuffer[0]) { | |
633 | case '?': /* report most recent signal */ | |
634 | remcomOutBuffer[0] = 'S'; | |
635 | remcomOutBuffer[1] = hexchars[sigval >> 4]; | |
636 | remcomOutBuffer[2] = hexchars[sigval & 0xf]; | |
637 | remcomOutBuffer[3] = 0; | |
638 | break; | |
639 | #if 0 | |
640 | case 'q': /* this screws up gdb for some reason...*/ | |
641 | { | |
642 | extern long _start, sdata, __bss_start; | |
643 | ||
644 | ptr = &remcomInBuffer[1]; | |
645 | if (strncmp(ptr, "Offsets", 7) != 0) | |
646 | break; | |
647 | ||
648 | ptr = remcomOutBuffer; | |
649 | sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", | |
650 | &_start, &sdata, &__bss_start); | |
651 | break; | |
652 | } | |
653 | #endif | |
654 | case 'd': | |
655 | /* toggle debug flag */ | |
656 | kdebug ^= 1; | |
657 | break; | |
658 | ||
659 | case 'g': /* return the value of the CPU registers. | |
660 | * some of them are non-PowerPC names :( | |
661 | * they are stored in gdb like: | |
662 | * struct { | |
663 | * u32 gpr[32]; | |
664 | * f64 fpr[32]; | |
665 | * u32 pc, ps, cnd, lr; (ps=msr) | |
666 | * u32 cnt, xer, mq; | |
667 | * } | |
668 | */ | |
669 | { | |
670 | int i; | |
671 | ptr = remcomOutBuffer; | |
672 | /* General Purpose Regs */ | |
673 | ptr = mem2hex((char *)regs, ptr, 32 * 4); | |
674 | /* Floating Point Regs - FIXME */ | |
675 | /*ptr = mem2hex((char *), ptr, 32 * 8);*/ | |
676 | for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ | |
677 | ptr[i] = '0'; | |
678 | } | |
679 | ptr += 32*8*2; | |
680 | /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ | |
681 | ptr = mem2hex((char *)®s->nip, ptr, 4); | |
682 | ptr = mem2hex((char *)®s->msr, ptr, 4); | |
683 | ptr = mem2hex((char *)®s->ccr, ptr, 4); | |
684 | ptr = mem2hex((char *)®s->link, ptr, 4); | |
685 | ptr = mem2hex((char *)®s->ctr, ptr, 4); | |
686 | ptr = mem2hex((char *)®s->xer, ptr, 4); | |
687 | } | |
688 | break; | |
689 | ||
690 | case 'G': /* set the value of the CPU registers */ | |
691 | { | |
692 | ptr = &remcomInBuffer[1]; | |
693 | ||
694 | /* | |
695 | * If the stack pointer has moved, you should pray. | |
696 | * (cause only god can help you). | |
697 | */ | |
698 | ||
699 | /* General Purpose Regs */ | |
700 | hex2mem(ptr, (char *)regs, 32 * 4); | |
701 | ||
702 | /* Floating Point Regs - FIXME?? */ | |
703 | /*ptr = hex2mem(ptr, ??, 32 * 8);*/ | |
704 | ptr += 32*8*2; | |
705 | ||
706 | /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ | |
707 | ptr = hex2mem(ptr, (char *)®s->nip, 4); | |
708 | ptr = hex2mem(ptr, (char *)®s->msr, 4); | |
709 | ptr = hex2mem(ptr, (char *)®s->ccr, 4); | |
710 | ptr = hex2mem(ptr, (char *)®s->link, 4); | |
711 | ptr = hex2mem(ptr, (char *)®s->ctr, 4); | |
712 | ptr = hex2mem(ptr, (char *)®s->xer, 4); | |
713 | ||
714 | strcpy(remcomOutBuffer,"OK"); | |
715 | } | |
716 | break; | |
717 | case 'H': | |
718 | /* don't do anything, yet, just acknowledge */ | |
719 | hexToInt(&ptr, &addr); | |
720 | strcpy(remcomOutBuffer,"OK"); | |
721 | break; | |
722 | ||
723 | case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ | |
724 | /* Try to read %x,%x. */ | |
725 | ||
726 | ptr = &remcomInBuffer[1]; | |
727 | ||
728 | if (hexToInt(&ptr, &addr) && *ptr++ == ',' | |
729 | && hexToInt(&ptr, &length)) { | |
730 | if (mem2hex((char *)addr, remcomOutBuffer, | |
731 | length)) | |
732 | break; | |
733 | strcpy(remcomOutBuffer, "E03"); | |
734 | } else | |
735 | strcpy(remcomOutBuffer, "E01"); | |
736 | break; | |
737 | ||
738 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ | |
739 | /* Try to read '%x,%x:'. */ | |
740 | ||
741 | ptr = &remcomInBuffer[1]; | |
742 | ||
743 | if (hexToInt(&ptr, &addr) && *ptr++ == ',' | |
744 | && hexToInt(&ptr, &length) | |
745 | && *ptr++ == ':') { | |
746 | if (hex2mem(ptr, (char *)addr, length)) | |
747 | strcpy(remcomOutBuffer, "OK"); | |
748 | else | |
749 | strcpy(remcomOutBuffer, "E03"); | |
750 | flush_icache_range(addr, addr+length); | |
751 | } else | |
752 | strcpy(remcomOutBuffer, "E02"); | |
753 | break; | |
754 | ||
755 | ||
756 | case 'k': /* kill the program, actually just continue */ | |
757 | case 'c': /* cAA..AA Continue; address AA..AA optional */ | |
758 | /* try to read optional parameter, pc unchanged if no parm */ | |
759 | ||
760 | ptr = &remcomInBuffer[1]; | |
761 | if (hexToInt(&ptr, &addr)) | |
762 | regs->nip = addr; | |
763 | ||
764 | /* Need to flush the instruction cache here, as we may have deposited a | |
765 | * breakpoint, and the icache probably has no way of knowing that a data ref to | |
766 | * some location may have changed something that is in the instruction cache. | |
767 | */ | |
768 | kgdb_flush_cache_all(); | |
769 | mtmsr(msr); | |
770 | ||
771 | kgdb_interruptible(1); | |
772 | unlock_kernel(); | |
773 | kgdb_active = 0; | |
774 | if (kdebug) { | |
775 | printk("remcomInBuffer: %s\n", remcomInBuffer); | |
776 | printk("remcomOutBuffer: %s\n", remcomOutBuffer); | |
777 | } | |
778 | return 1; | |
779 | ||
780 | case 's': | |
781 | kgdb_flush_cache_all(); | |
782 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | |
783 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); | |
784 | regs->msr |= MSR_DE; | |
785 | #else | |
786 | regs->msr |= MSR_SE; | |
787 | #endif | |
788 | unlock_kernel(); | |
789 | kgdb_active = 0; | |
790 | if (kdebug) { | |
791 | printk("remcomInBuffer: %s\n", remcomInBuffer); | |
792 | printk("remcomOutBuffer: %s\n", remcomOutBuffer); | |
793 | } | |
794 | return 1; | |
795 | ||
796 | case 'r': /* Reset (if user process..exit ???)*/ | |
797 | panic("kgdb reset."); | |
798 | break; | |
799 | } /* switch */ | |
800 | if (remcomOutBuffer[0] && kdebug) { | |
801 | printk("remcomInBuffer: %s\n", remcomInBuffer); | |
802 | printk("remcomOutBuffer: %s\n", remcomOutBuffer); | |
803 | } | |
804 | /* reply to the request */ | |
805 | putpacket(remcomOutBuffer); | |
806 | } /* while(1) */ | |
807 | } | |
808 | ||
809 | /* This function will generate a breakpoint exception. It is used at the | |
810 | beginning of a program to sync up with a debugger and can be used | |
811 | otherwise as a quick means to stop program execution and "break" into | |
812 | the debugger. */ | |
813 | ||
814 | void | |
815 | breakpoint(void) | |
816 | { | |
817 | if (!initialized) { | |
818 | printk("breakpoint() called b4 kgdb init\n"); | |
819 | return; | |
820 | } | |
821 | ||
822 | asm(" .globl breakinst \n\ | |
823 | breakinst: .long 0x7d821008"); | |
824 | } | |
825 | ||
826 | #ifdef CONFIG_KGDB_CONSOLE | |
827 | /* Output string in GDB O-packet format if GDB has connected. If nothing | |
828 | output, returns 0 (caller must then handle output). */ | |
829 | int | |
830 | kgdb_output_string (const char* s, unsigned int count) | |
831 | { | |
832 | char buffer[512]; | |
833 | ||
834 | if (!kgdb_started) | |
835 | return 0; | |
836 | ||
837 | count = (count <= (sizeof(buffer) / 2 - 2)) | |
838 | ? count : (sizeof(buffer) / 2 - 2); | |
839 | ||
840 | buffer[0] = 'O'; | |
841 | mem2hex (s, &buffer[1], count); | |
842 | putpacket(buffer); | |
843 | ||
844 | return 1; | |
845 | } | |
846 | #endif | |
847 | ||
848 | static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, | |
849 | struct tty_struct *tty) | |
850 | { | |
851 | printk("Entering GDB stub\n"); | |
852 | breakpoint(); | |
853 | } | |
854 | static struct sysrq_key_op sysrq_gdb_op = { | |
855 | .handler = sysrq_handle_gdb, | |
856 | .help_msg = "Gdb", | |
857 | .action_msg = "GDB", | |
858 | }; | |
859 | ||
860 | static int gdb_register_sysrq(void) | |
861 | { | |
862 | printk("Registering GDB sysrq handler\n"); | |
863 | register_sysrq_key('g', &sysrq_gdb_op); | |
864 | return 0; | |
865 | } | |
866 | module_init(gdb_register_sysrq); |