blob: b14898be9214929dbe44b3bb7e100e4f98564f34 [file] [log] [blame]
wdenk4a9cbbe2002-08-27 09:48:53 +00001/* taken from arch/ppc/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
Jon Loeliger052fc842007-07-08 18:10:08 -050095#if defined(CONFIG_CMD_KGDB)
wdenk4a9cbbe2002-08-27 09:48:53 +000096
97#undef KGDB_DEBUG
98
99/*
100 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
101 */
102#define BUFMAX 1024
103static char remcomInBuffer[BUFMAX];
104static char remcomOutBuffer[BUFMAX];
105static char remcomRegBuffer[BUFMAX];
106
107static int initialized = 0;
108static int kgdb_active = 0, first_entry = 1;
109static struct pt_regs entry_regs;
Wolfgang Denk7c76eb32008-03-09 10:33:31 +0100110static long error_jmp_buf[BUFMAX/2];
wdenk4a9cbbe2002-08-27 09:48:53 +0000111static int longjmp_on_fault = 0;
112#ifdef KGDB_DEBUG
113static int kdebug = 1;
114#endif
115
116static const char hexchars[]="0123456789abcdef";
117
118/* Convert ch from a hex digit to an int */
119static int
120hex(unsigned char ch)
121{
122 if (ch >= 'a' && ch <= 'f')
123 return ch-'a'+10;
124 if (ch >= '0' && ch <= '9')
125 return ch-'0';
126 if (ch >= 'A' && ch <= 'F')
127 return ch-'A'+10;
128 return -1;
129}
130
131/* Convert the memory pointed to by mem into hex, placing result in buf.
132 * Return a pointer to the last char put in buf (null).
133 */
134static unsigned char *
135mem2hex(char *mem, char *buf, int count)
136{
137 unsigned char ch;
138
139 longjmp_on_fault = 1;
140 while (count-- > 0) {
141 ch = *mem++;
142 *buf++ = hexchars[ch >> 4];
143 *buf++ = hexchars[ch & 0xf];
144 }
145 *buf = 0;
146 longjmp_on_fault = 0;
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200147 return (unsigned char *)buf;
wdenk4a9cbbe2002-08-27 09:48:53 +0000148}
149
150/* convert the hex array pointed to by buf into binary to be placed in mem
151 * return a pointer to the character AFTER the last byte fetched from buf.
152*/
153static char *
154hex2mem(char *buf, char *mem, int count)
155{
156 int i, hexValue;
157 unsigned char ch;
158 char *mem_start = mem;
159
160 longjmp_on_fault = 1;
161 for (i=0; i<count; i++) {
162 if ((hexValue = hex(*buf++)) < 0)
163 kgdb_error(KGDBERR_NOTHEXDIG);
164 ch = hexValue << 4;
165 if ((hexValue = hex(*buf++)) < 0)
166 kgdb_error(KGDBERR_NOTHEXDIG);
167 ch |= hexValue;
168 *mem++ = ch;
169 }
170 kgdb_flush_cache_range((void *)mem_start, (void *)(mem - 1));
171 longjmp_on_fault = 0;
172
173 return buf;
174}
175
176/*
177 * While we find nice hex chars, build an int.
178 * Return number of chars processed.
179 */
180static int
181hexToInt(char **ptr, int *intValue)
182{
183 int numChars = 0;
184 int hexValue;
185
186 *intValue = 0;
187
188 longjmp_on_fault = 1;
189 while (**ptr) {
190 hexValue = hex(**ptr);
191 if (hexValue < 0)
192 break;
193
194 *intValue = (*intValue << 4) | hexValue;
195 numChars ++;
196
197 (*ptr)++;
198 }
199 longjmp_on_fault = 0;
200
201 return (numChars);
202}
203
204/* scan for the sequence $<data>#<checksum> */
205static void
206getpacket(char *buffer)
207{
208 unsigned char checksum;
209 unsigned char xmitcsum;
210 int i;
211 int count;
212 unsigned char ch;
213
214 do {
215 /* wait around for the start character, ignore all other
216 * characters */
217 while ((ch = (getDebugChar() & 0x7f)) != '$') {
218#ifdef KGDB_DEBUG
219 if (kdebug)
220 putc(ch);
221#endif
222 ;
223 }
224
225 checksum = 0;
226 xmitcsum = -1;
227
228 count = 0;
229
230 /* now, read until a # or end of buffer is found */
231 while (count < BUFMAX) {
232 ch = getDebugChar() & 0x7f;
233 if (ch == '#')
234 break;
235 checksum = checksum + ch;
236 buffer[count] = ch;
237 count = count + 1;
238 }
239
240 if (count >= BUFMAX)
241 continue;
242
243 buffer[count] = 0;
244
245 if (ch == '#') {
246 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
247 xmitcsum |= hex(getDebugChar() & 0x7f);
248 if (checksum != xmitcsum)
249 putDebugChar('-'); /* failed checksum */
250 else {
251 putDebugChar('+'); /* successful transfer */
252 /* if a sequence char is present, reply the ID */
253 if (buffer[2] == ':') {
254 putDebugChar(buffer[0]);
255 putDebugChar(buffer[1]);
256 /* remove sequence chars from buffer */
257 count = strlen(buffer);
258 for (i=3; i <= count; i++)
259 buffer[i-3] = buffer[i];
260 }
261 }
262 }
263 } while (checksum != xmitcsum);
264}
265
266/* send the packet in buffer. */
267static void
268putpacket(unsigned char *buffer)
269{
270 unsigned char checksum;
271 int count;
272 unsigned char ch, recv;
273
274 /* $<packet info>#<checksum>. */
275 do {
276 putDebugChar('$');
277 checksum = 0;
278 count = 0;
279
280 while ((ch = buffer[count])) {
281 putDebugChar(ch);
282 checksum += ch;
283 count += 1;
284 }
285
286 putDebugChar('#');
287 putDebugChar(hexchars[checksum >> 4]);
288 putDebugChar(hexchars[checksum & 0xf]);
289 recv = getDebugChar();
290 } while ((recv & 0x7f) != '+');
291}
292
293/*
294 * This function does all command processing for interfacing to gdb.
295 */
296static int
297handle_exception (struct pt_regs *regs)
298{
299 int addr;
300 int length;
301 char *ptr;
302 kgdb_data kd;
303 int i;
304
305 if (!initialized) {
306 printf("kgdb: exception before kgdb is initialized! huh?\n");
307 return (0);
308 }
309
310 /* probably should check which exception occured as well */
311 if (longjmp_on_fault) {
312 longjmp_on_fault = 0;
Wolfgang Denk7c76eb32008-03-09 10:33:31 +0100313 kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
wdenk4a9cbbe2002-08-27 09:48:53 +0000314 panic("kgdb longjump failed!\n");
315 }
316
317 if (kgdb_active) {
318 printf("kgdb: unexpected exception from within kgdb\n");
319 return (0);
320 }
321 kgdb_active = 1;
322
323 kgdb_interruptible(0);
324
325 printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
326
Wolfgang Denk7c76eb32008-03-09 10:33:31 +0100327 if (kgdb_setjmp(error_jmp_buf) != 0)
wdenk4a9cbbe2002-08-27 09:48:53 +0000328 panic("kgdb: error or fault in entry init!\n");
329
330 kgdb_enter(regs, &kd);
331
332 if (first_entry) {
333 /*
334 * the first time we enter kgdb, we save the processor
335 * state so that we can return to the monitor if the
336 * remote end quits gdb (or at least, tells us to quit
337 * with the 'k' packet)
338 */
339 entry_regs = *regs;
340 first_entry = 0;
341 }
342
343 ptr = remcomOutBuffer;
344
345 *ptr++ = 'T';
346
347 *ptr++ = hexchars[kd.sigval >> 4];
348 *ptr++ = hexchars[kd.sigval & 0xf];
349
350 for (i = 0; i < kd.nregs; i++) {
351 kgdb_reg *rp = &kd.regs[i];
352
353 *ptr++ = hexchars[rp->num >> 4];
354 *ptr++ = hexchars[rp->num & 0xf];
355 *ptr++ = ':';
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200356 ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
wdenk4a9cbbe2002-08-27 09:48:53 +0000357 *ptr++ = ';';
358 }
359
360 *ptr = 0;
361
362#ifdef KGDB_DEBUG
363 if (kdebug)
364 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
365#endif
366
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200367 putpacket((unsigned char *)&remcomOutBuffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000368
369 while (1) {
370 volatile int errnum;
371
372 remcomOutBuffer[0] = 0;
373
374 getpacket(remcomInBuffer);
375 ptr = &remcomInBuffer[1];
376
377#ifdef KGDB_DEBUG
378 if (kdebug)
379 printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
380#endif
381
Wolfgang Denk7c76eb32008-03-09 10:33:31 +0100382 errnum = kgdb_setjmp(error_jmp_buf);
wdenk4a9cbbe2002-08-27 09:48:53 +0000383
384 if (errnum == 0) switch (remcomInBuffer[0]) {
385
386 case '?': /* report most recent signal */
387 remcomOutBuffer[0] = 'S';
388 remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
389 remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
390 remcomOutBuffer[3] = 0;
391 break;
392
393#ifdef KGDB_DEBUG
394 case 'd':
395 /* toggle debug flag */
396 kdebug ^= 1;
397 break;
398#endif
399
400 case 'g': /* return the value of the CPU registers. */
401 length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
402 mem2hex(remcomRegBuffer, remcomOutBuffer, length);
403 break;
404
405 case 'G': /* set the value of the CPU registers */
406 length = strlen(ptr);
407 if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
408 hex2mem(ptr, remcomRegBuffer, length/2);
409 kgdb_putregs(regs, remcomRegBuffer, length/2);
410 strcpy(remcomOutBuffer,"OK");
411 break;
412
413 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
414 /* Try to read %x,%x. */
415
416 if (hexToInt(&ptr, &addr)
417 && *ptr++ == ','
418 && hexToInt(&ptr, &length)) {
419 mem2hex((char *)addr, remcomOutBuffer, length);
420 } else {
421 kgdb_error(KGDBERR_BADPARAMS);
422 }
423 break;
424
425 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
426 /* Try to read '%x,%x:'. */
427
428 if (hexToInt(&ptr, &addr)
429 && *ptr++ == ','
430 && hexToInt(&ptr, &length)
431 && *ptr++ == ':') {
432 hex2mem(ptr, (char *)addr, length);
433 strcpy(remcomOutBuffer, "OK");
434 } else {
435 kgdb_error(KGDBERR_BADPARAMS);
436 }
437 break;
438
439
440 case 'k': /* kill the program, actually return to monitor */
441 kd.extype = KGDBEXIT_KILL;
442 *regs = entry_regs;
443 first_entry = 1;
444 goto doexit;
445
446 case 'C': /* CSS continue with signal SS */
447 *ptr = '\0'; /* ignore the signal number for now */
448 /* fall through */
449
450 case 'c': /* cAA..AA Continue; address AA..AA optional */
451 /* try to read optional parameter, pc unchanged if no parm */
452 kd.extype = KGDBEXIT_CONTINUE;
453
454 if (hexToInt(&ptr, &addr)) {
455 kd.exaddr = addr;
456 kd.extype |= KGDBEXIT_WITHADDR;
457 }
458
459 goto doexit;
460
461 case 'S': /* SSS single step with signal SS */
462 *ptr = '\0'; /* ignore the signal number for now */
463 /* fall through */
464
465 case 's':
466 kd.extype = KGDBEXIT_SINGLE;
467
468 if (hexToInt(&ptr, &addr)) {
469 kd.exaddr = addr;
470 kd.extype |= KGDBEXIT_WITHADDR;
471 }
472
473 doexit:
474/* Need to flush the instruction cache here, as we may have deposited a
475 * breakpoint, and the icache probably has no way of knowing that a data ref to
476 * some location may have changed something that is in the instruction cache.
477 */
478 kgdb_flush_cache_all();
479 kgdb_exit(regs, &kd);
480 kgdb_active = 0;
481 kgdb_interruptible(1);
482 return (1);
483
484 case 'r': /* Reset (if user process..exit ???)*/
485 panic("kgdb reset.");
486 break;
487
488 case 'P': /* Pr=v set reg r to value v (r and v are hex) */
489 if (hexToInt(&ptr, &addr)
490 && *ptr++ == '='
491 && ((length = strlen(ptr)) & 1) == 0) {
492 hex2mem(ptr, remcomRegBuffer, length/2);
493 kgdb_putreg(regs, addr,
494 remcomRegBuffer, length/2);
495 strcpy(remcomOutBuffer,"OK");
496 } else {
497 kgdb_error(KGDBERR_BADPARAMS);
498 }
499 break;
500 } /* switch */
501
502 if (errnum != 0)
503 sprintf(remcomOutBuffer, "E%02d", errnum);
504
505#ifdef KGDB_DEBUG
506 if (kdebug)
507 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
508#endif
509
510 /* reply to the request */
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200511 putpacket((unsigned char *)&remcomOutBuffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000512
513 } /* while(1) */
514}
515
516/*
517 * kgdb_init must be called *after* the
518 * monitor is relocated into ram
519 */
520void
521kgdb_init(void)
522{
523 kgdb_serial_init();
524 debugger_exception_handler = handle_exception;
525 initialized = 1;
526
527 putDebugStr("kgdb ready\n");
528 puts("ready\n");
529}
530
531void
532kgdb_error(int errnum)
533{
534 longjmp_on_fault = 0;
Wolfgang Denk7c76eb32008-03-09 10:33:31 +0100535 kgdb_longjmp(error_jmp_buf, errnum);
wdenk4a9cbbe2002-08-27 09:48:53 +0000536 panic("kgdb_error: longjmp failed!\n");
537}
538
539/* Output string in GDB O-packet format if GDB has connected. If nothing
540 output, returns 0 (caller must then handle output). */
541int
542kgdb_output_string (const char* s, unsigned int count)
543{
544 char buffer[512];
545
546 count = (count <= (sizeof(buffer) / 2 - 2))
547 ? count : (sizeof(buffer) / 2 - 2);
548
549 buffer[0] = 'O';
550 mem2hex ((char *)s, &buffer[1], count);
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200551 putpacket((unsigned char *)&buffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000552
553 return 1;
554}
555
556void
557breakpoint(void)
558{
559 if (!initialized) {
560 printf("breakpoint() called b4 kgdb init\n");
561 return;
562 }
563
564 kgdb_breakpoint(0, 0);
565}
566
567int
568do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
569{
570 printf("Entering KGDB mode via exception handler...\n\n");
571 kgdb_breakpoint(argc - 1, argv + 1);
572 printf("\nReturned from KGDB mode\n");
573 return 0;
574}
575
wdenkf287a242003-07-01 21:06:45 +0000576U_BOOT_CMD(
577 kgdb, CFG_MAXARGS, 1, do_kgdb,
wdenk57b2d802003-06-27 21:31:46 +0000578 "kgdb - enter gdb remote debug mode\n",
579 "[arg0 arg1 .. argN]\n"
580 " - executes a breakpoint so that kgdb mode is\n"
581 " entered via the exception handler. To return\n"
582 " to the monitor, the remote gdb debugger must\n"
583 " execute a \"continue\" or \"quit\" command.\n"
584 "\n"
585 " if a program is loaded by the remote gdb, any args\n"
586 " passed to the kgdb command are given to the loaded\n"
587 " program if it is executed (see the \"hello_world\"\n"
588 " example program in the U-Boot examples directory)."
589);
wdenk4a9cbbe2002-08-27 09:48:53 +0000590#else
591
592int kgdb_not_configured = 1;
593
Jon Loeligerd704d912007-07-10 11:02:44 -0500594#endif