xref: /openbmc/u-boot/common/kgdb.c (revision 76b00aca)
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;
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 occurred 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 	entry_regs = *regs;
352 
353 	ptr = remcomOutBuffer;
354 
355 	*ptr++ = 'T';
356 
357 	*ptr++ = hexchars[kd.sigval >> 4];
358 	*ptr++ = hexchars[kd.sigval & 0xf];
359 
360 	for (i = 0; i < kd.nregs; i++) {
361 		kgdb_reg *rp = &kd.regs[i];
362 
363 		*ptr++ = hexchars[rp->num >> 4];
364 		*ptr++ = hexchars[rp->num & 0xf];
365 		*ptr++ = ':';
366 		ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
367 		*ptr++ = ';';
368 	}
369 
370 	*ptr = 0;
371 
372 #ifdef KGDB_DEBUG
373 	if (kdebug)
374 		printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
375 #endif
376 
377 	putpacket((unsigned char *)&remcomOutBuffer);
378 
379 	while (1) {
380 		volatile int errnum;
381 
382 		remcomOutBuffer[0] = 0;
383 
384 		getpacket(remcomInBuffer);
385 		ptr = &remcomInBuffer[1];
386 
387 #ifdef KGDB_DEBUG
388 		if (kdebug)
389 			printf("kgdb:  remcomInBuffer: %s\n", remcomInBuffer);
390 #endif
391 
392 		errnum = kgdb_setjmp(error_jmp_buf);
393 
394 		if (errnum == 0) switch (remcomInBuffer[0]) {
395 
396 		case '?':               /* report most recent signal */
397 			remcomOutBuffer[0] = 'S';
398 			remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
399 			remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
400 			remcomOutBuffer[3] = 0;
401 			break;
402 
403 #ifdef KGDB_DEBUG
404 		case 'd':
405 			/* toggle debug flag */
406 			kdebug ^= 1;
407 			break;
408 #endif
409 
410 		case 'g':	/* return the value of the CPU registers. */
411 			length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
412 			mem2hex(remcomRegBuffer, remcomOutBuffer, length);
413 			break;
414 
415 		case 'G':   /* set the value of the CPU registers */
416 			length = strlen(ptr);
417 			if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
418 			hex2mem(ptr, remcomRegBuffer, length/2);
419 			kgdb_putregs(regs, remcomRegBuffer, length/2);
420 			strcpy(remcomOutBuffer,"OK");
421 			break;
422 
423 		case 'm':	/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
424 				/* Try to read %x,%x.  */
425 
426 			if (hexToInt(&ptr, &addr)
427 			    && *ptr++ == ','
428 			    && hexToInt(&ptr, &length))	{
429 				mem2hex((char *)addr, remcomOutBuffer, length);
430 			} else {
431 				kgdb_error(KGDBERR_BADPARAMS);
432 			}
433 			break;
434 
435 		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
436 			/* Try to read '%x,%x:'.  */
437 
438 			if (hexToInt(&ptr, &addr)
439 			    && *ptr++ == ','
440 			    && hexToInt(&ptr, &length)
441 			    && *ptr++ == ':') {
442 				hex2mem(ptr, (char *)addr, length);
443 				strcpy(remcomOutBuffer, "OK");
444 			} else {
445 				kgdb_error(KGDBERR_BADPARAMS);
446 			}
447 			break;
448 
449 
450 		case 'k':    /* kill the program, actually return to monitor */
451 			kd.extype = KGDBEXIT_KILL;
452 			*regs = entry_regs;
453 			goto doexit;
454 
455 		case 'C':    /* CSS  continue with signal SS */
456 			*ptr = '\0';	/* ignore the signal number for now */
457 			/* fall through */
458 
459 		case 'c':    /* cAA..AA  Continue; address AA..AA optional */
460 			/* try to read optional parameter, pc unchanged if no parm */
461 			kd.extype = KGDBEXIT_CONTINUE;
462 
463 			if (hexToInt(&ptr, &addr)) {
464 				kd.exaddr = addr;
465 				kd.extype |= KGDBEXIT_WITHADDR;
466 			}
467 
468 			goto doexit;
469 
470 		case 'S':    /* SSS  single step with signal SS */
471 			*ptr = '\0';	/* ignore the signal number for now */
472 			/* fall through */
473 
474 		case 's':
475 			kd.extype = KGDBEXIT_SINGLE;
476 
477 			if (hexToInt(&ptr, &addr)) {
478 				kd.exaddr = addr;
479 				kd.extype |= KGDBEXIT_WITHADDR;
480 			}
481 
482 		doexit:
483 /* Need to flush the instruction cache here, as we may have deposited a
484  * breakpoint, and the icache probably has no way of knowing that a data ref to
485  * some location may have changed something that is in the instruction cache.
486  */
487 			kgdb_flush_cache_all();
488 			kgdb_exit(regs, &kd);
489 			kgdb_active = 0;
490 			kgdb_interruptible(1);
491 			return (1);
492 
493 		case 'r':		/* Reset (if user process..exit ???)*/
494 			panic("kgdb reset.");
495 			break;
496 
497 		case 'P':    /* Pr=v  set reg r to value v (r and v are hex) */
498 			if (hexToInt(&ptr, &addr)
499 			    && *ptr++ == '='
500 			    && ((length = strlen(ptr)) & 1) == 0) {
501 				hex2mem(ptr, remcomRegBuffer, length/2);
502 				kgdb_putreg(regs, addr,
503 					remcomRegBuffer, length/2);
504 				strcpy(remcomOutBuffer,"OK");
505 			} else {
506 				kgdb_error(KGDBERR_BADPARAMS);
507 			}
508 			break;
509 		}			/* switch */
510 
511 		if (errnum != 0)
512 			sprintf(remcomOutBuffer, "E%02d", errnum);
513 
514 #ifdef KGDB_DEBUG
515 		if (kdebug)
516 			printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
517 #endif
518 
519 		/* reply to the request */
520 		putpacket((unsigned char *)&remcomOutBuffer);
521 
522 	} /* while(1) */
523 }
524 
525 /*
526  * kgdb_init must be called *after* the
527  * monitor is relocated into ram
528  */
529 void
530 kgdb_init(void)
531 {
532 	kgdb_serial_init();
533 	debugger_exception_handler = handle_exception;
534 	initialized = 1;
535 
536 	putDebugStr("kgdb ready\n");
537 	puts("ready\n");
538 }
539 
540 void
541 kgdb_error(int errnum)
542 {
543 	longjmp_on_fault = 0;
544 	kgdb_longjmp(error_jmp_buf, errnum);
545 	panic("kgdb_error: longjmp failed!\n");
546 }
547 
548 /* Output string in GDB O-packet format if GDB has connected. If nothing
549    output, returns 0 (caller must then handle output). */
550 int
551 kgdb_output_string (const char* s, unsigned int count)
552 {
553 	char buffer[512];
554 
555 	count = (count <= (sizeof(buffer) / 2 - 2))
556 		? count : (sizeof(buffer) / 2 - 2);
557 
558 	buffer[0] = 'O';
559 	mem2hex ((char *)s, &buffer[1], count);
560 	putpacket((unsigned char *)&buffer);
561 
562 	return 1;
563 }
564 
565 void
566 breakpoint(void)
567 {
568 	if (!initialized) {
569 		printf("breakpoint() called b4 kgdb init\n");
570 		return;
571 	}
572 
573 	kgdb_breakpoint(0, 0);
574 }
575 
576 int
577 do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
578 {
579     printf("Entering KGDB mode via exception handler...\n\n");
580     kgdb_breakpoint(argc - 1, argv + 1);
581     printf("\nReturned from KGDB mode\n");
582     return 0;
583 }
584 
585 U_BOOT_CMD(
586 	kgdb, CONFIG_SYS_MAXARGS, 1,	do_kgdb,
587 	"enter gdb remote debug mode",
588 	"[arg0 arg1 .. argN]\n"
589 	"    - executes a breakpoint so that kgdb mode is\n"
590 	"      entered via the exception handler. To return\n"
591 	"      to the monitor, the remote gdb debugger must\n"
592 	"      execute a \"continue\" or \"quit\" command.\n"
593 	"\n"
594 	"      if a program is loaded by the remote gdb, any args\n"
595 	"      passed to the kgdb command are given to the loaded\n"
596 	"      program if it is executed (see the \"hello_world\"\n"
597 	"      example program in the U-Boot examples directory)."
598 );
599