]> git.ipfire.org Git - people/ms/u-boot.git/blob - common/kgdb.c
Move arch/ppc to arch/powerpc
[people/ms/u-boot.git] / common / kgdb.c
1 /* taken from arch/powerpc/kernel/ppc-stub.c */
2
3 /****************************************************************************
4
5 THIS SOFTWARE IS NOT COPYRIGHTED
6
7 HP offers the following for use in the public domain. HP makes no
8 warranty with regard to the software or its performance and the
9 user accepts the software "AS IS" with all faults.
10
11 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
12 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14
15 ****************************************************************************/
16
17 /****************************************************************************
18 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
19 *
20 * Module name: remcom.c $
21 * Revision: 1.34 $
22 * Date: 91/03/09 12:29:49 $
23 * Contributor: Lake Stevens Instrument Division$
24 *
25 * Description: low level support for gdb debugger. $
26 *
27 * Considerations: only works on target hardware $
28 *
29 * Written by: Glenn Engel $
30 * ModuleState: Experimental $
31 *
32 * NOTES: See Below $
33 *
34 * Modified for SPARC by Stu Grossman, Cygnus Support.
35 *
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
37 *
38 * To enable debugger support, two things need to happen. One, a
39 * call to set_debug_traps() is necessary in order to allow any breakpoints
40 * or error conditions to be properly intercepted and reported to gdb.
41 * Two, a breakpoint needs to be generated to begin communication. This
42 * is most easily accomplished by a call to breakpoint(). Breakpoint()
43 * simulates a breakpoint by executing a trap #1.
44 *
45 *************
46 *
47 * The following gdb commands are supported:
48 *
49 * command function Return value
50 *
51 * g return the value of the CPU registers hex data or ENN
52 * G set the value of the CPU registers OK or ENN
53 * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz
54 *
55 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
56 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 *
58 * c Resume at current address SNN ( signal NN)
59 * cAA..AA Continue at address AA..AA SNN
60 *
61 * s Step one instruction SNN
62 * sAA..AA Step one instruction from AA..AA SNN
63 *
64 * k kill
65 *
66 * ? What was the last sigval ? SNN (signal NN)
67 *
68 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
69 * baud rate
70 *
71 * All commands and responses are sent with a packet which includes a
72 * checksum. A packet consists of
73 *
74 * $<packet info>#<checksum>.
75 *
76 * where
77 * <packet info> :: <characters representing the command or response>
78 * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
79 *
80 * When a packet is received, it is first acknowledged with either '+' or '-'.
81 * '+' indicates a successful transfer. '-' indicates a failed transfer.
82 *
83 * Example:
84 *
85 * Host: Reply:
86 * $m0,10#2a +$00010203040506070809101112131415#42
87 *
88 ****************************************************************************/
89
90 #include <common.h>
91
92 #include <kgdb.h>
93 #include <command.h>
94
95 #undef KGDB_DEBUG
96
97 /*
98 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
99 */
100 #define BUFMAX 1024
101 static char remcomInBuffer[BUFMAX];
102 static char remcomOutBuffer[BUFMAX];
103 static char remcomRegBuffer[BUFMAX];
104
105 static int initialized = 0;
106 static int kgdb_active = 0, first_entry = 1;
107 static struct pt_regs entry_regs;
108 static long error_jmp_buf[BUFMAX/2];
109 static int longjmp_on_fault = 0;
110 #ifdef KGDB_DEBUG
111 static int kdebug = 1;
112 #endif
113
114 static const char hexchars[]="0123456789abcdef";
115
116 /* Convert ch from a hex digit to an int */
117 static int
118 hex(unsigned char ch)
119 {
120 if (ch >= 'a' && ch <= 'f')
121 return ch-'a'+10;
122 if (ch >= '0' && ch <= '9')
123 return ch-'0';
124 if (ch >= 'A' && ch <= 'F')
125 return ch-'A'+10;
126 return -1;
127 }
128
129 /* Convert the memory pointed to by mem into hex, placing result in buf.
130 * Return a pointer to the last char put in buf (null).
131 */
132 static unsigned char *
133 mem2hex(char *mem, char *buf, int count)
134 {
135 char *tmp;
136 unsigned char ch;
137
138 /*
139 * We use the upper half of buf as an intermediate buffer for the
140 * raw memory copy. Hex conversion will work against this one.
141 */
142 tmp = buf + count;
143 longjmp_on_fault = 1;
144
145 memcpy(tmp, mem, count);
146
147 while (count-- > 0) {
148 ch = *tmp++;
149 *buf++ = hexchars[ch >> 4];
150 *buf++ = hexchars[ch & 0xf];
151 }
152 *buf = 0;
153 longjmp_on_fault = 0;
154 return (unsigned char *)buf;
155 }
156
157 /* convert the hex array pointed to by buf into binary to be placed in mem
158 * return a pointer to the character AFTER the last byte fetched from buf.
159 */
160 static char *
161 hex2mem(char *buf, char *mem, int count)
162 {
163 int hexValue;
164 char *tmp_raw, *tmp_hex;
165
166 /*
167 * We use the upper half of buf as an intermediate buffer for the
168 * raw memory that is converted from hex.
169 */
170 tmp_raw = buf + count * 2;
171 tmp_hex = tmp_raw - 1;
172
173 longjmp_on_fault = 1;
174 while (tmp_hex >= buf) {
175 tmp_raw--;
176 hexValue = hex(*tmp_hex--);
177 if (hexValue < 0)
178 kgdb_error(KGDBERR_NOTHEXDIG);
179 *tmp_raw = hexValue;
180 hexValue = hex(*tmp_hex--);
181 if (hexValue < 0)
182 kgdb_error(KGDBERR_NOTHEXDIG);
183 *tmp_raw |= hexValue << 4;
184
185 }
186
187 memcpy(mem, tmp_raw, count);
188
189 kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
190 longjmp_on_fault = 0;
191
192 return buf;
193 }
194
195 /*
196 * While we find nice hex chars, build an int.
197 * Return number of chars processed.
198 */
199 static int
200 hexToInt(char **ptr, int *intValue)
201 {
202 int numChars = 0;
203 int hexValue;
204
205 *intValue = 0;
206
207 longjmp_on_fault = 1;
208 while (**ptr) {
209 hexValue = hex(**ptr);
210 if (hexValue < 0)
211 break;
212
213 *intValue = (*intValue << 4) | hexValue;
214 numChars ++;
215
216 (*ptr)++;
217 }
218 longjmp_on_fault = 0;
219
220 return (numChars);
221 }
222
223 /* scan for the sequence $<data>#<checksum> */
224 static void
225 getpacket(char *buffer)
226 {
227 unsigned char checksum;
228 unsigned char xmitcsum;
229 int i;
230 int count;
231 unsigned char ch;
232
233 do {
234 /* wait around for the start character, ignore all other
235 * characters */
236 while ((ch = (getDebugChar() & 0x7f)) != '$') {
237 #ifdef KGDB_DEBUG
238 if (kdebug)
239 putc(ch);
240 #endif
241 ;
242 }
243
244 checksum = 0;
245 xmitcsum = -1;
246
247 count = 0;
248
249 /* now, read until a # or end of buffer is found */
250 while (count < BUFMAX) {
251 ch = getDebugChar() & 0x7f;
252 if (ch == '#')
253 break;
254 checksum = checksum + ch;
255 buffer[count] = ch;
256 count = count + 1;
257 }
258
259 if (count >= BUFMAX)
260 continue;
261
262 buffer[count] = 0;
263
264 if (ch == '#') {
265 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
266 xmitcsum |= hex(getDebugChar() & 0x7f);
267 if (checksum != xmitcsum)
268 putDebugChar('-'); /* failed checksum */
269 else {
270 putDebugChar('+'); /* successful transfer */
271 /* if a sequence char is present, reply the ID */
272 if (buffer[2] == ':') {
273 putDebugChar(buffer[0]);
274 putDebugChar(buffer[1]);
275 /* remove sequence chars from buffer */
276 count = strlen(buffer);
277 for (i=3; i <= count; i++)
278 buffer[i-3] = buffer[i];
279 }
280 }
281 }
282 } while (checksum != xmitcsum);
283 }
284
285 /* send the packet in buffer. */
286 static void
287 putpacket(unsigned char *buffer)
288 {
289 unsigned char checksum;
290 int count;
291 unsigned char ch, recv;
292
293 /* $<packet info>#<checksum>. */
294 do {
295 putDebugChar('$');
296 checksum = 0;
297 count = 0;
298
299 while ((ch = buffer[count])) {
300 putDebugChar(ch);
301 checksum += ch;
302 count += 1;
303 }
304
305 putDebugChar('#');
306 putDebugChar(hexchars[checksum >> 4]);
307 putDebugChar(hexchars[checksum & 0xf]);
308 recv = getDebugChar();
309 } while ((recv & 0x7f) != '+');
310 }
311
312 /*
313 * This function does all command processing for interfacing to gdb.
314 */
315 static int
316 handle_exception (struct pt_regs *regs)
317 {
318 int addr;
319 int length;
320 char *ptr;
321 kgdb_data kd;
322 int i;
323
324 if (!initialized) {
325 printf("kgdb: exception before kgdb is initialized! huh?\n");
326 return (0);
327 }
328
329 /* probably should check which exception occured as well */
330 if (longjmp_on_fault) {
331 longjmp_on_fault = 0;
332 kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
333 panic("kgdb longjump failed!\n");
334 }
335
336 if (kgdb_active) {
337 printf("kgdb: unexpected exception from within kgdb\n");
338 return (0);
339 }
340 kgdb_active = 1;
341
342 kgdb_interruptible(0);
343
344 printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
345
346 if (kgdb_setjmp(error_jmp_buf) != 0)
347 panic("kgdb: error or fault in entry init!\n");
348
349 kgdb_enter(regs, &kd);
350
351 if (first_entry) {
352 /*
353 * the first time we enter kgdb, we save the processor
354 * state so that we can return to the monitor if the
355 * remote end quits gdb (or at least, tells us to quit
356 * with the 'k' packet)
357 */
358 entry_regs = *regs;
359 first_entry = 0;
360 }
361
362 ptr = remcomOutBuffer;
363
364 *ptr++ = 'T';
365
366 *ptr++ = hexchars[kd.sigval >> 4];
367 *ptr++ = hexchars[kd.sigval & 0xf];
368
369 for (i = 0; i < kd.nregs; i++) {
370 kgdb_reg *rp = &kd.regs[i];
371
372 *ptr++ = hexchars[rp->num >> 4];
373 *ptr++ = hexchars[rp->num & 0xf];
374 *ptr++ = ':';
375 ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
376 *ptr++ = ';';
377 }
378
379 *ptr = 0;
380
381 #ifdef KGDB_DEBUG
382 if (kdebug)
383 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
384 #endif
385
386 putpacket((unsigned char *)&remcomOutBuffer);
387
388 while (1) {
389 volatile int errnum;
390
391 remcomOutBuffer[0] = 0;
392
393 getpacket(remcomInBuffer);
394 ptr = &remcomInBuffer[1];
395
396 #ifdef KGDB_DEBUG
397 if (kdebug)
398 printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
399 #endif
400
401 errnum = kgdb_setjmp(error_jmp_buf);
402
403 if (errnum == 0) switch (remcomInBuffer[0]) {
404
405 case '?': /* report most recent signal */
406 remcomOutBuffer[0] = 'S';
407 remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
408 remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
409 remcomOutBuffer[3] = 0;
410 break;
411
412 #ifdef KGDB_DEBUG
413 case 'd':
414 /* toggle debug flag */
415 kdebug ^= 1;
416 break;
417 #endif
418
419 case 'g': /* return the value of the CPU registers. */
420 length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
421 mem2hex(remcomRegBuffer, remcomOutBuffer, length);
422 break;
423
424 case 'G': /* set the value of the CPU registers */
425 length = strlen(ptr);
426 if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
427 hex2mem(ptr, remcomRegBuffer, length/2);
428 kgdb_putregs(regs, remcomRegBuffer, length/2);
429 strcpy(remcomOutBuffer,"OK");
430 break;
431
432 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
433 /* Try to read %x,%x. */
434
435 if (hexToInt(&ptr, &addr)
436 && *ptr++ == ','
437 && hexToInt(&ptr, &length)) {
438 mem2hex((char *)addr, remcomOutBuffer, length);
439 } else {
440 kgdb_error(KGDBERR_BADPARAMS);
441 }
442 break;
443
444 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
445 /* Try to read '%x,%x:'. */
446
447 if (hexToInt(&ptr, &addr)
448 && *ptr++ == ','
449 && hexToInt(&ptr, &length)
450 && *ptr++ == ':') {
451 hex2mem(ptr, (char *)addr, length);
452 strcpy(remcomOutBuffer, "OK");
453 } else {
454 kgdb_error(KGDBERR_BADPARAMS);
455 }
456 break;
457
458
459 case 'k': /* kill the program, actually return to monitor */
460 kd.extype = KGDBEXIT_KILL;
461 *regs = entry_regs;
462 first_entry = 1;
463 goto doexit;
464
465 case 'C': /* CSS continue with signal SS */
466 *ptr = '\0'; /* ignore the signal number for now */
467 /* fall through */
468
469 case 'c': /* cAA..AA Continue; address AA..AA optional */
470 /* try to read optional parameter, pc unchanged if no parm */
471 kd.extype = KGDBEXIT_CONTINUE;
472
473 if (hexToInt(&ptr, &addr)) {
474 kd.exaddr = addr;
475 kd.extype |= KGDBEXIT_WITHADDR;
476 }
477
478 goto doexit;
479
480 case 'S': /* SSS single step with signal SS */
481 *ptr = '\0'; /* ignore the signal number for now */
482 /* fall through */
483
484 case 's':
485 kd.extype = KGDBEXIT_SINGLE;
486
487 if (hexToInt(&ptr, &addr)) {
488 kd.exaddr = addr;
489 kd.extype |= KGDBEXIT_WITHADDR;
490 }
491
492 doexit:
493 /* Need to flush the instruction cache here, as we may have deposited a
494 * breakpoint, and the icache probably has no way of knowing that a data ref to
495 * some location may have changed something that is in the instruction cache.
496 */
497 kgdb_flush_cache_all();
498 kgdb_exit(regs, &kd);
499 kgdb_active = 0;
500 kgdb_interruptible(1);
501 return (1);
502
503 case 'r': /* Reset (if user process..exit ???)*/
504 panic("kgdb reset.");
505 break;
506
507 case 'P': /* Pr=v set reg r to value v (r and v are hex) */
508 if (hexToInt(&ptr, &addr)
509 && *ptr++ == '='
510 && ((length = strlen(ptr)) & 1) == 0) {
511 hex2mem(ptr, remcomRegBuffer, length/2);
512 kgdb_putreg(regs, addr,
513 remcomRegBuffer, length/2);
514 strcpy(remcomOutBuffer,"OK");
515 } else {
516 kgdb_error(KGDBERR_BADPARAMS);
517 }
518 break;
519 } /* switch */
520
521 if (errnum != 0)
522 sprintf(remcomOutBuffer, "E%02d", errnum);
523
524 #ifdef KGDB_DEBUG
525 if (kdebug)
526 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
527 #endif
528
529 /* reply to the request */
530 putpacket((unsigned char *)&remcomOutBuffer);
531
532 } /* while(1) */
533 }
534
535 /*
536 * kgdb_init must be called *after* the
537 * monitor is relocated into ram
538 */
539 void
540 kgdb_init(void)
541 {
542 kgdb_serial_init();
543 debugger_exception_handler = handle_exception;
544 initialized = 1;
545
546 putDebugStr("kgdb ready\n");
547 puts("ready\n");
548 }
549
550 void
551 kgdb_error(int errnum)
552 {
553 longjmp_on_fault = 0;
554 kgdb_longjmp(error_jmp_buf, errnum);
555 panic("kgdb_error: longjmp failed!\n");
556 }
557
558 /* Output string in GDB O-packet format if GDB has connected. If nothing
559 output, returns 0 (caller must then handle output). */
560 int
561 kgdb_output_string (const char* s, unsigned int count)
562 {
563 char buffer[512];
564
565 count = (count <= (sizeof(buffer) / 2 - 2))
566 ? count : (sizeof(buffer) / 2 - 2);
567
568 buffer[0] = 'O';
569 mem2hex ((char *)s, &buffer[1], count);
570 putpacket((unsigned char *)&buffer);
571
572 return 1;
573 }
574
575 void
576 breakpoint(void)
577 {
578 if (!initialized) {
579 printf("breakpoint() called b4 kgdb init\n");
580 return;
581 }
582
583 kgdb_breakpoint(0, 0);
584 }
585
586 int
587 do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
588 {
589 printf("Entering KGDB mode via exception handler...\n\n");
590 kgdb_breakpoint(argc - 1, argv + 1);
591 printf("\nReturned from KGDB mode\n");
592 return 0;
593 }
594
595 U_BOOT_CMD(
596 kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
597 "enter gdb remote debug mode",
598 "[arg0 arg1 .. argN]\n"
599 " - executes a breakpoint so that kgdb mode is\n"
600 " entered via the exception handler. To return\n"
601 " to the monitor, the remote gdb debugger must\n"
602 " execute a \"continue\" or \"quit\" command.\n"
603 "\n"
604 " if a program is loaded by the remote gdb, any args\n"
605 " passed to the kgdb command are given to the loaded\n"
606 " program if it is executed (see the \"hello_world\"\n"
607 " example program in the U-Boot examples directory)."
608 );