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