]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/kgdb.c
rockchip: rk3288: Fix wrong TPL_TEXT_BASE
[people/ms/u-boot.git] / common / kgdb.c
CommitLineData
a47a12be 1/* taken from arch/powerpc/kernel/ppc-stub.c */
4a9cbbe8
WD
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
4a9cbbe8
WD
95#undef KGDB_DEBUG
96
97/*
98 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
99 */
100#define BUFMAX 1024
101static char remcomInBuffer[BUFMAX];
102static char remcomOutBuffer[BUFMAX];
103static char remcomRegBuffer[BUFMAX];
104
105static int initialized = 0;
f9f040b2 106static int kgdb_active;
4a9cbbe8 107static struct pt_regs entry_regs;
cc3843e3 108static long error_jmp_buf[BUFMAX/2];
4a9cbbe8
WD
109static int longjmp_on_fault = 0;
110#ifdef KGDB_DEBUG
111static int kdebug = 1;
112#endif
113
114static const char hexchars[]="0123456789abcdef";
115
116/* Convert ch from a hex digit to an int */
117static int
118hex(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 */
132static unsigned char *
133mem2hex(char *mem, char *buf, int count)
134{
16035bcd 135 char *tmp;
4a9cbbe8
WD
136 unsigned char ch;
137
16035bcd
RG
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;
4a9cbbe8 143 longjmp_on_fault = 1;
16035bcd
RG
144
145 memcpy(tmp, mem, count);
146
4a9cbbe8 147 while (count-- > 0) {
16035bcd 148 ch = *tmp++;
4a9cbbe8
WD
149 *buf++ = hexchars[ch >> 4];
150 *buf++ = hexchars[ch & 0xf];
151 }
152 *buf = 0;
153 longjmp_on_fault = 0;
77ddac94 154 return (unsigned char *)buf;
4a9cbbe8
WD
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*/
160static char *
161hex2mem(char *buf, char *mem, int count)
162{
16035bcd
RG
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;
4a9cbbe8
WD
172
173 longjmp_on_fault = 1;
16035bcd
RG
174 while (tmp_hex >= buf) {
175 tmp_raw--;
176 hexValue = hex(*tmp_hex--);
177 if (hexValue < 0)
4a9cbbe8 178 kgdb_error(KGDBERR_NOTHEXDIG);
16035bcd
RG
179 *tmp_raw = hexValue;
180 hexValue = hex(*tmp_hex--);
181 if (hexValue < 0)
4a9cbbe8 182 kgdb_error(KGDBERR_NOTHEXDIG);
16035bcd
RG
183 *tmp_raw |= hexValue << 4;
184
4a9cbbe8 185 }
16035bcd
RG
186
187 memcpy(mem, tmp_raw, count);
188
189 kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
4a9cbbe8
WD
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 */
199static int
200hexToInt(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> */
224static void
225getpacket(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. */
286static void
287putpacket(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 */
315static int
316handle_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
eae4b2b6 329 /* probably should check which exception occurred as well */
4a9cbbe8
WD
330 if (longjmp_on_fault) {
331 longjmp_on_fault = 0;
cc3843e3 332 kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
4a9cbbe8
WD
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
cc3843e3 346 if (kgdb_setjmp(error_jmp_buf) != 0)
4a9cbbe8
WD
347 panic("kgdb: error or fault in entry init!\n");
348
349 kgdb_enter(regs, &kd);
350
f9f040b2 351 entry_regs = *regs;
4a9cbbe8
WD
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++ = ':';
77ddac94 366 ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
4a9cbbe8
WD
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
77ddac94 377 putpacket((unsigned char *)&remcomOutBuffer);
4a9cbbe8
WD
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
cc3843e3 392 errnum = kgdb_setjmp(error_jmp_buf);
4a9cbbe8
WD
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;
4a9cbbe8
WD
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 */
77ddac94 520 putpacket((unsigned char *)&remcomOutBuffer);
4a9cbbe8
WD
521
522 } /* while(1) */
523}
524
525/*
526 * kgdb_init must be called *after* the
527 * monitor is relocated into ram
528 */
529void
530kgdb_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
540void
541kgdb_error(int errnum)
542{
543 longjmp_on_fault = 0;
cc3843e3 544 kgdb_longjmp(error_jmp_buf, errnum);
4a9cbbe8
WD
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). */
550int
551kgdb_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);
77ddac94 560 putpacket((unsigned char *)&buffer);
4a9cbbe8
WD
561
562 return 1;
563}
564
565void
566breakpoint(void)
567{
568 if (!initialized) {
569 printf("breakpoint() called b4 kgdb init\n");
570 return;
571 }
572
573 kgdb_breakpoint(0, 0);
574}
575
576int
54841ab5 577do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
4a9cbbe8
WD
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
0d498393 585U_BOOT_CMD(
6d0f6bcf 586 kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
2fb2604d 587 "enter gdb remote debug mode",
8bde7f77
WD
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);