1*6ca2c52aSchristos /****************************************************************************
2*6ca2c52aSchristos 
3*6ca2c52aSchristos 		THIS SOFTWARE IS NOT COPYRIGHTED
4*6ca2c52aSchristos 
5*6ca2c52aSchristos    HP offers the following for use in the public domain.  HP makes no
6*6ca2c52aSchristos    warranty with regard to the software or it's performance and the
7*6ca2c52aSchristos    user accepts the software "AS IS" with all faults.
8*6ca2c52aSchristos 
9*6ca2c52aSchristos    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10*6ca2c52aSchristos    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11*6ca2c52aSchristos    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12*6ca2c52aSchristos 
13*6ca2c52aSchristos ****************************************************************************/
14*6ca2c52aSchristos 
15*6ca2c52aSchristos /****************************************************************************
16*6ca2c52aSchristos  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17*6ca2c52aSchristos  *
18*6ca2c52aSchristos  *  Module name: remcom.c $
19*6ca2c52aSchristos  *  Revision: 1.34 $
20*6ca2c52aSchristos  *  Date: 91/03/09 12:29:49 $
21*6ca2c52aSchristos  *  Contributor:     Lake Stevens Instrument Division$
22*6ca2c52aSchristos  *
23*6ca2c52aSchristos  *  Description:     low level support for gdb debugger. $
24*6ca2c52aSchristos  *
25*6ca2c52aSchristos  *  Considerations:  only works on target hardware $
26*6ca2c52aSchristos  *
27*6ca2c52aSchristos  *  Written by:      Glenn Engel $
28*6ca2c52aSchristos  *  ModuleState:     Experimental $
29*6ca2c52aSchristos  *
30*6ca2c52aSchristos  *  NOTES:           See Below $
31*6ca2c52aSchristos  *
32*6ca2c52aSchristos  *  Modified for SPARC by Stu Grossman, Cygnus Support.
33*6ca2c52aSchristos  *
34*6ca2c52aSchristos  *  This code has been extensively tested on the Fujitsu SPARClite demo board.
35*6ca2c52aSchristos  *
36*6ca2c52aSchristos  *  To enable debugger support, two things need to happen.  One, a
37*6ca2c52aSchristos  *  call to set_debug_traps() is necessary in order to allow any breakpoints
38*6ca2c52aSchristos  *  or error conditions to be properly intercepted and reported to gdb.
39*6ca2c52aSchristos  *  Two, a breakpoint needs to be generated to begin communication.  This
40*6ca2c52aSchristos  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
41*6ca2c52aSchristos  *  simulates a breakpoint by executing a trap #1.
42*6ca2c52aSchristos  *
43*6ca2c52aSchristos  *************
44*6ca2c52aSchristos  *
45*6ca2c52aSchristos  *    The following gdb commands are supported:
46*6ca2c52aSchristos  *
47*6ca2c52aSchristos  * command          function                               Return value
48*6ca2c52aSchristos  *
49*6ca2c52aSchristos  *    g             return the value of the CPU registers  hex data or ENN
50*6ca2c52aSchristos  *    G             set the value of the CPU registers     OK or ENN
51*6ca2c52aSchristos  *
52*6ca2c52aSchristos  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
53*6ca2c52aSchristos  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
54*6ca2c52aSchristos  *
55*6ca2c52aSchristos  *    c             Resume at current address              SNN   ( signal NN)
56*6ca2c52aSchristos  *    cAA..AA       Continue at address AA..AA             SNN
57*6ca2c52aSchristos  *
58*6ca2c52aSchristos  *    s             Step one instruction                   SNN
59*6ca2c52aSchristos  *    sAA..AA       Step one instruction from AA..AA       SNN
60*6ca2c52aSchristos  *
61*6ca2c52aSchristos  *    k             kill
62*6ca2c52aSchristos  *
63*6ca2c52aSchristos  *    ?             What was the last sigval ?             SNN   (signal NN)
64*6ca2c52aSchristos  *
65*6ca2c52aSchristos  * All commands and responses are sent with a packet which includes a
66*6ca2c52aSchristos  * checksum.  A packet consists of
67*6ca2c52aSchristos  *
68*6ca2c52aSchristos  * $<packet info>#<checksum>.
69*6ca2c52aSchristos  *
70*6ca2c52aSchristos  * where
71*6ca2c52aSchristos  * <packet info> :: <characters representing the command or response>
72*6ca2c52aSchristos  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
73*6ca2c52aSchristos  *
74*6ca2c52aSchristos  * When a packet is received, it is first acknowledged with either '+' or '-'.
75*6ca2c52aSchristos  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
76*6ca2c52aSchristos  *
77*6ca2c52aSchristos  * Example:
78*6ca2c52aSchristos  *
79*6ca2c52aSchristos  * Host:                  Reply:
80*6ca2c52aSchristos  * $m0,10#2a               +$00010203040506070809101112131415#42
81*6ca2c52aSchristos  *
82*6ca2c52aSchristos  ****************************************************************************/
83*6ca2c52aSchristos 
84*6ca2c52aSchristos #include <string.h>
85*6ca2c52aSchristos #include <signal.h>
86*6ca2c52aSchristos 
87*6ca2c52aSchristos /************************************************************************
88*6ca2c52aSchristos  *
89*6ca2c52aSchristos  * external low-level support routines
90*6ca2c52aSchristos  */
91*6ca2c52aSchristos 
92*6ca2c52aSchristos extern void putDebugChar();	/* write a single character      */
93*6ca2c52aSchristos extern int getDebugChar();	/* read and return a single char */
94*6ca2c52aSchristos 
95*6ca2c52aSchristos /************************************************************************/
96*6ca2c52aSchristos /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
97*6ca2c52aSchristos /* at least NUMREGBYTES*2 are needed for register packets */
98*6ca2c52aSchristos #define BUFMAX 2048
99*6ca2c52aSchristos 
100*6ca2c52aSchristos static int initialized = 0;	/* !0 means we've been initialized */
101*6ca2c52aSchristos 
102*6ca2c52aSchristos static void set_mem_fault_trap();
103*6ca2c52aSchristos 
104*6ca2c52aSchristos static const char hexchars[]="0123456789abcdef";
105*6ca2c52aSchristos 
106*6ca2c52aSchristos #define NUMREGS 72
107*6ca2c52aSchristos 
108*6ca2c52aSchristos /* Number of bytes of registers.  */
109*6ca2c52aSchristos #define NUMREGBYTES (NUMREGS * 4)
110*6ca2c52aSchristos enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
111*6ca2c52aSchristos 		 O0, O1, O2, O3, O4, O5, SP, O7,
112*6ca2c52aSchristos 		 L0, L1, L2, L3, L4, L5, L6, L7,
113*6ca2c52aSchristos 		 I0, I1, I2, I3, I4, I5, FP, I7,
114*6ca2c52aSchristos 
115*6ca2c52aSchristos 		 F0, F1, F2, F3, F4, F5, F6, F7,
116*6ca2c52aSchristos 		 F8, F9, F10, F11, F12, F13, F14, F15,
117*6ca2c52aSchristos 		 F16, F17, F18, F19, F20, F21, F22, F23,
118*6ca2c52aSchristos 		 F24, F25, F26, F27, F28, F29, F30, F31,
119*6ca2c52aSchristos 		 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
120*6ca2c52aSchristos 
121*6ca2c52aSchristos /***************************  ASSEMBLY CODE MACROS *************************/
122*6ca2c52aSchristos /* 									   */
123*6ca2c52aSchristos 
124*6ca2c52aSchristos extern void trap_low();
125*6ca2c52aSchristos 
126*6ca2c52aSchristos asm("
127*6ca2c52aSchristos 	.reserve trapstack, 1000 * 4, \"bss\", 8
128*6ca2c52aSchristos 
129*6ca2c52aSchristos 	.data
130*6ca2c52aSchristos 	.align	4
131*6ca2c52aSchristos 
132*6ca2c52aSchristos in_trap_handler:
133*6ca2c52aSchristos 	.word	0
134*6ca2c52aSchristos 
135*6ca2c52aSchristos 	.text
136*6ca2c52aSchristos 	.align 4
137*6ca2c52aSchristos 
138*6ca2c52aSchristos ! This function is called when any SPARC trap (except window overflow or
139*6ca2c52aSchristos ! underflow) occurs.  It makes sure that the invalid register window is still
140*6ca2c52aSchristos ! available before jumping into C code.  It will also restore the world if you
141*6ca2c52aSchristos ! return from handle_exception.
142*6ca2c52aSchristos 
143*6ca2c52aSchristos 	.globl _trap_low
144*6ca2c52aSchristos _trap_low:
145*6ca2c52aSchristos 	mov	%psr, %l0
146*6ca2c52aSchristos 	mov	%wim, %l3
147*6ca2c52aSchristos 
148*6ca2c52aSchristos 	srl	%l3, %l0, %l4		! wim >> cwp
149*6ca2c52aSchristos 	cmp	%l4, 1
150*6ca2c52aSchristos 	bne	window_fine		! Branch if not in the invalid window
151*6ca2c52aSchristos 	nop
152*6ca2c52aSchristos 
153*6ca2c52aSchristos ! Handle window overflow
154*6ca2c52aSchristos 
155*6ca2c52aSchristos 	mov	%g1, %l4		! Save g1, we use it to hold the wim
156*6ca2c52aSchristos 	srl	%l3, 1, %g1		! Rotate wim right
157*6ca2c52aSchristos 	tst	%g1
158*6ca2c52aSchristos 	bg	good_wim		! Branch if new wim is non-zero
159*6ca2c52aSchristos 	nop
160*6ca2c52aSchristos 
161*6ca2c52aSchristos ! At this point, we need to bring a 1 into the high order bit of the wim.
162*6ca2c52aSchristos ! Since we don't want to make any assumptions about the number of register
163*6ca2c52aSchristos ! windows, we figure it out dynamically so as to setup the wim correctly.
164*6ca2c52aSchristos 
165*6ca2c52aSchristos 	not	%g1			! Fill g1 with ones
166*6ca2c52aSchristos 	mov	%g1, %wim		! Fill the wim with ones
167*6ca2c52aSchristos 	nop
168*6ca2c52aSchristos 	nop
169*6ca2c52aSchristos 	nop
170*6ca2c52aSchristos 	mov	%wim, %g1		! Read back the wim
171*6ca2c52aSchristos 	inc	%g1			! Now g1 has 1 just to left of wim
172*6ca2c52aSchristos 	srl	%g1, 1, %g1		! Now put 1 at top of wim
173*6ca2c52aSchristos 	mov	%g0, %wim		! Clear wim so that subsequent save
174*6ca2c52aSchristos 	nop				!  won't trap
175*6ca2c52aSchristos 	nop
176*6ca2c52aSchristos 	nop
177*6ca2c52aSchristos 
178*6ca2c52aSchristos good_wim:
179*6ca2c52aSchristos 	save	%g0, %g0, %g0		! Slip into next window
180*6ca2c52aSchristos 	mov	%g1, %wim		! Install the new wim
181*6ca2c52aSchristos 
182*6ca2c52aSchristos 	std	%l0, [%sp + 0 * 4]	! save L & I registers
183*6ca2c52aSchristos 	std	%l2, [%sp + 2 * 4]
184*6ca2c52aSchristos 	std	%l4, [%sp + 4 * 4]
185*6ca2c52aSchristos 	std	%l6, [%sp + 6 * 4]
186*6ca2c52aSchristos 
187*6ca2c52aSchristos 	std	%i0, [%sp + 8 * 4]
188*6ca2c52aSchristos 	std	%i2, [%sp + 10 * 4]
189*6ca2c52aSchristos 	std	%i4, [%sp + 12 * 4]
190*6ca2c52aSchristos 	std	%i6, [%sp + 14 * 4]
191*6ca2c52aSchristos 
192*6ca2c52aSchristos 	restore				! Go back to trap window.
193*6ca2c52aSchristos 	mov	%l4, %g1		! Restore %g1
194*6ca2c52aSchristos 
195*6ca2c52aSchristos window_fine:
196*6ca2c52aSchristos 	sethi	%hi(in_trap_handler), %l4
197*6ca2c52aSchristos 	ld	[%lo(in_trap_handler) + %l4], %l5
198*6ca2c52aSchristos 	tst	%l5
199*6ca2c52aSchristos 	bg	recursive_trap
200*6ca2c52aSchristos 	inc	%l5
201*6ca2c52aSchristos 
202*6ca2c52aSchristos 	set	trapstack+1000*4, %sp	! Switch to trap stack
203*6ca2c52aSchristos 
204*6ca2c52aSchristos recursive_trap:
205*6ca2c52aSchristos 	st	%l5, [%lo(in_trap_handler) + %l4]
206*6ca2c52aSchristos 	sub	%sp,(16+1+6+1+72)*4,%sp	! Make room for input & locals
207*6ca2c52aSchristos  					! + hidden arg + arg spill
208*6ca2c52aSchristos 					! + doubleword alignment
209*6ca2c52aSchristos 					! + registers[72] local var
210*6ca2c52aSchristos 
211*6ca2c52aSchristos 	std	%g0, [%sp + (24 + 0) * 4] ! registers[Gx]
212*6ca2c52aSchristos 	std	%g2, [%sp + (24 + 2) * 4]
213*6ca2c52aSchristos 	std	%g4, [%sp + (24 + 4) * 4]
214*6ca2c52aSchristos 	std	%g6, [%sp + (24 + 6) * 4]
215*6ca2c52aSchristos 
216*6ca2c52aSchristos 	std	%i0, [%sp + (24 + 8) * 4] ! registers[Ox]
217*6ca2c52aSchristos 	std	%i2, [%sp + (24 + 10) * 4]
218*6ca2c52aSchristos 	std	%i4, [%sp + (24 + 12) * 4]
219*6ca2c52aSchristos 	std	%i6, [%sp + (24 + 14) * 4]
220*6ca2c52aSchristos 					! F0->F31 not implemented
221*6ca2c52aSchristos 	mov	%y, %l4
222*6ca2c52aSchristos 	mov	%tbr, %l5
223*6ca2c52aSchristos 	st	%l4, [%sp + (24 + 64) * 4] ! Y
224*6ca2c52aSchristos 	st	%l0, [%sp + (24 + 65) * 4] ! PSR
225*6ca2c52aSchristos 	st	%l3, [%sp + (24 + 66) * 4] ! WIM
226*6ca2c52aSchristos 	st	%l5, [%sp + (24 + 67) * 4] ! TBR
227*6ca2c52aSchristos 	st	%l1, [%sp + (24 + 68) * 4] ! PC
228*6ca2c52aSchristos 	st	%l2, [%sp + (24 + 69) * 4] ! NPC
229*6ca2c52aSchristos 
230*6ca2c52aSchristos 					! CPSR and FPSR not impl
231*6ca2c52aSchristos 
232*6ca2c52aSchristos 	or	%l0, 0xf20, %l4
233*6ca2c52aSchristos 	mov	%l4, %psr		! Turn on traps, disable interrupts
234*6ca2c52aSchristos 
235*6ca2c52aSchristos 	call	_handle_exception
236*6ca2c52aSchristos 	add	%sp, 24 * 4, %o0	! Pass address of registers
237*6ca2c52aSchristos 
238*6ca2c52aSchristos ! Reload all of the registers that aren't on the stack
239*6ca2c52aSchristos 
240*6ca2c52aSchristos 	ld	[%sp + (24 + 1) * 4], %g1 ! registers[Gx]
241*6ca2c52aSchristos 	ldd	[%sp + (24 + 2) * 4], %g2
242*6ca2c52aSchristos 	ldd	[%sp + (24 + 4) * 4], %g4
243*6ca2c52aSchristos 	ldd	[%sp + (24 + 6) * 4], %g6
244*6ca2c52aSchristos 
245*6ca2c52aSchristos 	ldd	[%sp + (24 + 8) * 4], %i0 ! registers[Ox]
246*6ca2c52aSchristos 	ldd	[%sp + (24 + 10) * 4], %i2
247*6ca2c52aSchristos 	ldd	[%sp + (24 + 12) * 4], %i4
248*6ca2c52aSchristos 	ldd	[%sp + (24 + 14) * 4], %i6
249*6ca2c52aSchristos 
250*6ca2c52aSchristos 	ldd	[%sp + (24 + 64) * 4], %l0 ! Y & PSR
251*6ca2c52aSchristos 	ldd	[%sp + (24 + 68) * 4], %l2 ! PC & NPC
252*6ca2c52aSchristos 
253*6ca2c52aSchristos 	restore				! Ensure that previous window is valid
254*6ca2c52aSchristos 	save	%g0, %g0, %g0		!  by causing a window_underflow trap
255*6ca2c52aSchristos 
256*6ca2c52aSchristos 	mov	%l0, %y
257*6ca2c52aSchristos 	mov	%l1, %psr		! Make sure that traps are disabled
258*6ca2c52aSchristos 					! for rett
259*6ca2c52aSchristos 
260*6ca2c52aSchristos 	sethi	%hi(in_trap_handler), %l4
261*6ca2c52aSchristos 	ld	[%lo(in_trap_handler) + %l4], %l5
262*6ca2c52aSchristos 	dec	%l5
263*6ca2c52aSchristos 	st	%l5, [%lo(in_trap_handler) + %l4]
264*6ca2c52aSchristos 
265*6ca2c52aSchristos 	jmpl	%l2, %g0		! Restore old PC
266*6ca2c52aSchristos 	rett	%l3			! Restore old nPC
267*6ca2c52aSchristos ");
268*6ca2c52aSchristos 
269*6ca2c52aSchristos /* Convert ch from a hex digit to an int */
270*6ca2c52aSchristos 
271*6ca2c52aSchristos static int
hex(unsigned char ch)272*6ca2c52aSchristos hex (unsigned char ch)
273*6ca2c52aSchristos {
274*6ca2c52aSchristos   if (ch >= 'a' && ch <= 'f')
275*6ca2c52aSchristos     return ch-'a'+10;
276*6ca2c52aSchristos   if (ch >= '0' && ch <= '9')
277*6ca2c52aSchristos     return ch-'0';
278*6ca2c52aSchristos   if (ch >= 'A' && ch <= 'F')
279*6ca2c52aSchristos     return ch-'A'+10;
280*6ca2c52aSchristos   return -1;
281*6ca2c52aSchristos }
282*6ca2c52aSchristos 
283*6ca2c52aSchristos static char remcomInBuffer[BUFMAX];
284*6ca2c52aSchristos static char remcomOutBuffer[BUFMAX];
285*6ca2c52aSchristos 
286*6ca2c52aSchristos /* scan for the sequence $<data>#<checksum>     */
287*6ca2c52aSchristos 
288*6ca2c52aSchristos unsigned char *
getpacket(void)289*6ca2c52aSchristos getpacket (void)
290*6ca2c52aSchristos {
291*6ca2c52aSchristos   unsigned char *buffer = &remcomInBuffer[0];
292*6ca2c52aSchristos   unsigned char checksum;
293*6ca2c52aSchristos   unsigned char xmitcsum;
294*6ca2c52aSchristos   int count;
295*6ca2c52aSchristos   char ch;
296*6ca2c52aSchristos 
297*6ca2c52aSchristos   while (1)
298*6ca2c52aSchristos     {
299*6ca2c52aSchristos       /* wait around for the start character, ignore all other characters */
300*6ca2c52aSchristos       while ((ch = getDebugChar ()) != '$')
301*6ca2c52aSchristos 	;
302*6ca2c52aSchristos 
303*6ca2c52aSchristos retry:
304*6ca2c52aSchristos       checksum = 0;
305*6ca2c52aSchristos       xmitcsum = -1;
306*6ca2c52aSchristos       count = 0;
307*6ca2c52aSchristos 
308*6ca2c52aSchristos       /* now, read until a # or end of buffer is found */
309*6ca2c52aSchristos       while (count < BUFMAX - 1)
310*6ca2c52aSchristos 	{
311*6ca2c52aSchristos 	  ch = getDebugChar ();
312*6ca2c52aSchristos           if (ch == '$')
313*6ca2c52aSchristos             goto retry;
314*6ca2c52aSchristos 	  if (ch == '#')
315*6ca2c52aSchristos 	    break;
316*6ca2c52aSchristos 	  checksum = checksum + ch;
317*6ca2c52aSchristos 	  buffer[count] = ch;
318*6ca2c52aSchristos 	  count = count + 1;
319*6ca2c52aSchristos 	}
320*6ca2c52aSchristos       buffer[count] = 0;
321*6ca2c52aSchristos 
322*6ca2c52aSchristos       if (ch == '#')
323*6ca2c52aSchristos 	{
324*6ca2c52aSchristos 	  ch = getDebugChar ();
325*6ca2c52aSchristos 	  xmitcsum = hex (ch) << 4;
326*6ca2c52aSchristos 	  ch = getDebugChar ();
327*6ca2c52aSchristos 	  xmitcsum += hex (ch);
328*6ca2c52aSchristos 
329*6ca2c52aSchristos 	  if (checksum != xmitcsum)
330*6ca2c52aSchristos 	    {
331*6ca2c52aSchristos 	      putDebugChar ('-');	/* failed checksum */
332*6ca2c52aSchristos 	    }
333*6ca2c52aSchristos 	  else
334*6ca2c52aSchristos 	    {
335*6ca2c52aSchristos 	      putDebugChar ('+');	/* successful transfer */
336*6ca2c52aSchristos 
337*6ca2c52aSchristos 	      /* if a sequence char is present, reply the sequence ID */
338*6ca2c52aSchristos 	      if (buffer[2] == ':')
339*6ca2c52aSchristos 		{
340*6ca2c52aSchristos 		  putDebugChar (buffer[0]);
341*6ca2c52aSchristos 		  putDebugChar (buffer[1]);
342*6ca2c52aSchristos 
343*6ca2c52aSchristos 		  return &buffer[3];
344*6ca2c52aSchristos 		}
345*6ca2c52aSchristos 
346*6ca2c52aSchristos 	      return &buffer[0];
347*6ca2c52aSchristos 	    }
348*6ca2c52aSchristos 	}
349*6ca2c52aSchristos     }
350*6ca2c52aSchristos }
351*6ca2c52aSchristos 
352*6ca2c52aSchristos /* send the packet in buffer.  */
353*6ca2c52aSchristos 
354*6ca2c52aSchristos static void
putpacket(unsigned char * buffer)355*6ca2c52aSchristos putpacket (unsigned char *buffer)
356*6ca2c52aSchristos {
357*6ca2c52aSchristos   unsigned char checksum;
358*6ca2c52aSchristos   int count;
359*6ca2c52aSchristos   unsigned char ch;
360*6ca2c52aSchristos 
361*6ca2c52aSchristos   /*  $<packet info>#<checksum>. */
362*6ca2c52aSchristos   do
363*6ca2c52aSchristos     {
364*6ca2c52aSchristos       putDebugChar('$');
365*6ca2c52aSchristos       checksum = 0;
366*6ca2c52aSchristos       count = 0;
367*6ca2c52aSchristos 
368*6ca2c52aSchristos       while (ch = buffer[count])
369*6ca2c52aSchristos 	{
370*6ca2c52aSchristos 	  putDebugChar(ch);
371*6ca2c52aSchristos 	  checksum += ch;
372*6ca2c52aSchristos 	  count += 1;
373*6ca2c52aSchristos 	}
374*6ca2c52aSchristos 
375*6ca2c52aSchristos       putDebugChar('#');
376*6ca2c52aSchristos       putDebugChar(hexchars[checksum >> 4]);
377*6ca2c52aSchristos       putDebugChar(hexchars[checksum & 0xf]);
378*6ca2c52aSchristos 
379*6ca2c52aSchristos     }
380*6ca2c52aSchristos   while (getDebugChar() != '+');
381*6ca2c52aSchristos }
382*6ca2c52aSchristos 
383*6ca2c52aSchristos /* Indicate to caller of mem2hex or hex2mem that there has been an
384*6ca2c52aSchristos    error.  */
385*6ca2c52aSchristos static volatile int mem_err = 0;
386*6ca2c52aSchristos 
387*6ca2c52aSchristos /* Convert the memory pointed to by mem into hex, placing result in buf.
388*6ca2c52aSchristos  * Return a pointer to the last char put in buf (null), in case of mem fault,
389*6ca2c52aSchristos  * return 0.
390*6ca2c52aSchristos  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
391*6ca2c52aSchristos  * a 0, else treat a fault like any other fault in the stub.
392*6ca2c52aSchristos  */
393*6ca2c52aSchristos 
394*6ca2c52aSchristos static unsigned char *
mem2hex(unsigned char * mem,unsigned char * buf,int count,int may_fault)395*6ca2c52aSchristos mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
396*6ca2c52aSchristos {
397*6ca2c52aSchristos   unsigned char ch;
398*6ca2c52aSchristos 
399*6ca2c52aSchristos   set_mem_fault_trap(may_fault);
400*6ca2c52aSchristos 
401*6ca2c52aSchristos   while (count-- > 0)
402*6ca2c52aSchristos     {
403*6ca2c52aSchristos       ch = *mem++;
404*6ca2c52aSchristos       if (mem_err)
405*6ca2c52aSchristos 	return 0;
406*6ca2c52aSchristos       *buf++ = hexchars[ch >> 4];
407*6ca2c52aSchristos       *buf++ = hexchars[ch & 0xf];
408*6ca2c52aSchristos     }
409*6ca2c52aSchristos 
410*6ca2c52aSchristos   *buf = 0;
411*6ca2c52aSchristos 
412*6ca2c52aSchristos   set_mem_fault_trap(0);
413*6ca2c52aSchristos 
414*6ca2c52aSchristos   return buf;
415*6ca2c52aSchristos }
416*6ca2c52aSchristos 
417*6ca2c52aSchristos /* convert the hex array pointed to by buf into binary to be placed in mem
418*6ca2c52aSchristos  * return a pointer to the character AFTER the last byte written */
419*6ca2c52aSchristos 
420*6ca2c52aSchristos static char *
hex2mem(unsigned char * buf,unsigned char * mem,int count,int may_fault)421*6ca2c52aSchristos hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
422*6ca2c52aSchristos {
423*6ca2c52aSchristos   int i;
424*6ca2c52aSchristos   unsigned char ch;
425*6ca2c52aSchristos 
426*6ca2c52aSchristos   set_mem_fault_trap(may_fault);
427*6ca2c52aSchristos 
428*6ca2c52aSchristos   for (i=0; i<count; i++)
429*6ca2c52aSchristos     {
430*6ca2c52aSchristos       ch = hex(*buf++) << 4;
431*6ca2c52aSchristos       ch |= hex(*buf++);
432*6ca2c52aSchristos       *mem++ = ch;
433*6ca2c52aSchristos       if (mem_err)
434*6ca2c52aSchristos 	return 0;
435*6ca2c52aSchristos     }
436*6ca2c52aSchristos 
437*6ca2c52aSchristos   set_mem_fault_trap(0);
438*6ca2c52aSchristos 
439*6ca2c52aSchristos   return mem;
440*6ca2c52aSchristos }
441*6ca2c52aSchristos 
442*6ca2c52aSchristos /* This table contains the mapping between SPARC hardware trap types, and
443*6ca2c52aSchristos    signals, which are primarily what GDB understands.  It also indicates
444*6ca2c52aSchristos    which hardware traps we need to commandeer when initializing the stub. */
445*6ca2c52aSchristos 
446*6ca2c52aSchristos static struct hard_trap_info
447*6ca2c52aSchristos {
448*6ca2c52aSchristos   unsigned char tt;		/* Trap type code for SPARClite */
449*6ca2c52aSchristos   unsigned char signo;		/* Signal that we map this trap into */
450*6ca2c52aSchristos } hard_trap_info[] = {
451*6ca2c52aSchristos   {1, SIGSEGV},			/* instruction access error */
452*6ca2c52aSchristos   {2, SIGILL},			/* privileged instruction */
453*6ca2c52aSchristos   {3, SIGILL},			/* illegal instruction */
454*6ca2c52aSchristos   {4, SIGEMT},			/* fp disabled */
455*6ca2c52aSchristos   {36, SIGEMT},			/* cp disabled */
456*6ca2c52aSchristos   {7, SIGBUS},			/* mem address not aligned */
457*6ca2c52aSchristos   {9, SIGSEGV},			/* data access exception */
458*6ca2c52aSchristos   {10, SIGEMT},			/* tag overflow */
459*6ca2c52aSchristos   {128+1, SIGTRAP},		/* ta 1 - normal breakpoint instruction */
460*6ca2c52aSchristos   {0, 0}			/* Must be last */
461*6ca2c52aSchristos };
462*6ca2c52aSchristos 
463*6ca2c52aSchristos /* Set up exception handlers for tracing and breakpoints */
464*6ca2c52aSchristos 
465*6ca2c52aSchristos void
set_debug_traps(void)466*6ca2c52aSchristos set_debug_traps (void)
467*6ca2c52aSchristos {
468*6ca2c52aSchristos   struct hard_trap_info *ht;
469*6ca2c52aSchristos 
470*6ca2c52aSchristos   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
471*6ca2c52aSchristos     exceptionHandler(ht->tt, trap_low);
472*6ca2c52aSchristos 
473*6ca2c52aSchristos   initialized = 1;
474*6ca2c52aSchristos }
475*6ca2c52aSchristos 
476*6ca2c52aSchristos asm ("
477*6ca2c52aSchristos ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
478*6ca2c52aSchristos ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
479*6ca2c52aSchristos ! 0 would ever contain code that could mem fault.  This routine will skip
480*6ca2c52aSchristos ! past the faulting instruction after setting mem_err.
481*6ca2c52aSchristos 
482*6ca2c52aSchristos 	.text
483*6ca2c52aSchristos 	.align 4
484*6ca2c52aSchristos 
485*6ca2c52aSchristos _fltr_set_mem_err:
486*6ca2c52aSchristos 	sethi %hi(_mem_err), %l0
487*6ca2c52aSchristos 	st %l1, [%l0 + %lo(_mem_err)]
488*6ca2c52aSchristos 	jmpl %l2, %g0
489*6ca2c52aSchristos 	rett %l2+4
490*6ca2c52aSchristos ");
491*6ca2c52aSchristos 
492*6ca2c52aSchristos static void
set_mem_fault_trap(int enable)493*6ca2c52aSchristos set_mem_fault_trap (int enable)
494*6ca2c52aSchristos {
495*6ca2c52aSchristos   extern void fltr_set_mem_err();
496*6ca2c52aSchristos   mem_err = 0;
497*6ca2c52aSchristos 
498*6ca2c52aSchristos   if (enable)
499*6ca2c52aSchristos     exceptionHandler(9, fltr_set_mem_err);
500*6ca2c52aSchristos   else
501*6ca2c52aSchristos     exceptionHandler(9, trap_low);
502*6ca2c52aSchristos }
503*6ca2c52aSchristos 
504*6ca2c52aSchristos /* Convert the SPARC hardware trap type code to a unix signal number. */
505*6ca2c52aSchristos 
506*6ca2c52aSchristos static int
computeSignal(int tt)507*6ca2c52aSchristos computeSignal (int tt)
508*6ca2c52aSchristos {
509*6ca2c52aSchristos   struct hard_trap_info *ht;
510*6ca2c52aSchristos 
511*6ca2c52aSchristos   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
512*6ca2c52aSchristos     if (ht->tt == tt)
513*6ca2c52aSchristos       return ht->signo;
514*6ca2c52aSchristos 
515*6ca2c52aSchristos   return SIGHUP;		/* default for things we don't know about */
516*6ca2c52aSchristos }
517*6ca2c52aSchristos 
518*6ca2c52aSchristos /*
519*6ca2c52aSchristos  * While we find nice hex chars, build an int.
520*6ca2c52aSchristos  * Return number of chars processed.
521*6ca2c52aSchristos  */
522*6ca2c52aSchristos 
523*6ca2c52aSchristos static int
hexToInt(char ** ptr,int * intValue)524*6ca2c52aSchristos hexToInt(char **ptr, int *intValue)
525*6ca2c52aSchristos {
526*6ca2c52aSchristos   int numChars = 0;
527*6ca2c52aSchristos   int hexValue;
528*6ca2c52aSchristos 
529*6ca2c52aSchristos   *intValue = 0;
530*6ca2c52aSchristos 
531*6ca2c52aSchristos   while (**ptr)
532*6ca2c52aSchristos     {
533*6ca2c52aSchristos       hexValue = hex(**ptr);
534*6ca2c52aSchristos       if (hexValue < 0)
535*6ca2c52aSchristos 	break;
536*6ca2c52aSchristos 
537*6ca2c52aSchristos       *intValue = (*intValue << 4) | hexValue;
538*6ca2c52aSchristos       numChars ++;
539*6ca2c52aSchristos 
540*6ca2c52aSchristos       (*ptr)++;
541*6ca2c52aSchristos     }
542*6ca2c52aSchristos 
543*6ca2c52aSchristos   return (numChars);
544*6ca2c52aSchristos }
545*6ca2c52aSchristos 
546*6ca2c52aSchristos /*
547*6ca2c52aSchristos  * This function does all command procesing for interfacing to gdb.  It
548*6ca2c52aSchristos  * returns 1 if you should skip the instruction at the trap address, 0
549*6ca2c52aSchristos  * otherwise.
550*6ca2c52aSchristos  */
551*6ca2c52aSchristos 
552*6ca2c52aSchristos extern void breakinst();
553*6ca2c52aSchristos 
554*6ca2c52aSchristos static void
handle_exception(unsigned long * registers)555*6ca2c52aSchristos handle_exception (unsigned long *registers)
556*6ca2c52aSchristos {
557*6ca2c52aSchristos   int tt;			/* Trap type */
558*6ca2c52aSchristos   int sigval;
559*6ca2c52aSchristos   int addr;
560*6ca2c52aSchristos   int length;
561*6ca2c52aSchristos   char *ptr;
562*6ca2c52aSchristos   unsigned long *sp;
563*6ca2c52aSchristos 
564*6ca2c52aSchristos /* First, we must force all of the windows to be spilled out */
565*6ca2c52aSchristos 
566*6ca2c52aSchristos   asm("	save %sp, -64, %sp
567*6ca2c52aSchristos 	save %sp, -64, %sp
568*6ca2c52aSchristos 	save %sp, -64, %sp
569*6ca2c52aSchristos 	save %sp, -64, %sp
570*6ca2c52aSchristos 	save %sp, -64, %sp
571*6ca2c52aSchristos 	save %sp, -64, %sp
572*6ca2c52aSchristos 	save %sp, -64, %sp
573*6ca2c52aSchristos 	save %sp, -64, %sp
574*6ca2c52aSchristos 	restore
575*6ca2c52aSchristos 	restore
576*6ca2c52aSchristos 	restore
577*6ca2c52aSchristos 	restore
578*6ca2c52aSchristos 	restore
579*6ca2c52aSchristos 	restore
580*6ca2c52aSchristos 	restore
581*6ca2c52aSchristos 	restore
582*6ca2c52aSchristos ");
583*6ca2c52aSchristos 
584*6ca2c52aSchristos   if (registers[PC] == (unsigned long)breakinst)
585*6ca2c52aSchristos     {
586*6ca2c52aSchristos       registers[PC] = registers[NPC];
587*6ca2c52aSchristos       registers[NPC] += 4;
588*6ca2c52aSchristos     }
589*6ca2c52aSchristos 
590*6ca2c52aSchristos   sp = (unsigned long *)registers[SP];
591*6ca2c52aSchristos 
592*6ca2c52aSchristos   tt = (registers[TBR] >> 4) & 0xff;
593*6ca2c52aSchristos 
594*6ca2c52aSchristos   /* reply to host that an exception has occurred */
595*6ca2c52aSchristos   sigval = computeSignal(tt);
596*6ca2c52aSchristos   ptr = remcomOutBuffer;
597*6ca2c52aSchristos 
598*6ca2c52aSchristos   *ptr++ = 'T';
599*6ca2c52aSchristos   *ptr++ = hexchars[sigval >> 4];
600*6ca2c52aSchristos   *ptr++ = hexchars[sigval & 0xf];
601*6ca2c52aSchristos 
602*6ca2c52aSchristos   *ptr++ = hexchars[PC >> 4];
603*6ca2c52aSchristos   *ptr++ = hexchars[PC & 0xf];
604*6ca2c52aSchristos   *ptr++ = ':';
605*6ca2c52aSchristos   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
606*6ca2c52aSchristos   *ptr++ = ';';
607*6ca2c52aSchristos 
608*6ca2c52aSchristos   *ptr++ = hexchars[FP >> 4];
609*6ca2c52aSchristos   *ptr++ = hexchars[FP & 0xf];
610*6ca2c52aSchristos   *ptr++ = ':';
611*6ca2c52aSchristos   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
612*6ca2c52aSchristos   *ptr++ = ';';
613*6ca2c52aSchristos 
614*6ca2c52aSchristos   *ptr++ = hexchars[SP >> 4];
615*6ca2c52aSchristos   *ptr++ = hexchars[SP & 0xf];
616*6ca2c52aSchristos   *ptr++ = ':';
617*6ca2c52aSchristos   ptr = mem2hex((char *)&sp, ptr, 4, 0);
618*6ca2c52aSchristos   *ptr++ = ';';
619*6ca2c52aSchristos 
620*6ca2c52aSchristos   *ptr++ = hexchars[NPC >> 4];
621*6ca2c52aSchristos   *ptr++ = hexchars[NPC & 0xf];
622*6ca2c52aSchristos   *ptr++ = ':';
623*6ca2c52aSchristos   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
624*6ca2c52aSchristos   *ptr++ = ';';
625*6ca2c52aSchristos 
626*6ca2c52aSchristos   *ptr++ = hexchars[O7 >> 4];
627*6ca2c52aSchristos   *ptr++ = hexchars[O7 & 0xf];
628*6ca2c52aSchristos   *ptr++ = ':';
629*6ca2c52aSchristos   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
630*6ca2c52aSchristos   *ptr++ = ';';
631*6ca2c52aSchristos 
632*6ca2c52aSchristos   *ptr++ = 0;
633*6ca2c52aSchristos 
634*6ca2c52aSchristos   putpacket(remcomOutBuffer);
635*6ca2c52aSchristos 
636*6ca2c52aSchristos   while (1)
637*6ca2c52aSchristos     {
638*6ca2c52aSchristos       remcomOutBuffer[0] = 0;
639*6ca2c52aSchristos 
640*6ca2c52aSchristos       ptr = getpacket();
641*6ca2c52aSchristos       switch (*ptr++)
642*6ca2c52aSchristos 	{
643*6ca2c52aSchristos 	case '?':
644*6ca2c52aSchristos 	  remcomOutBuffer[0] = 'S';
645*6ca2c52aSchristos 	  remcomOutBuffer[1] = hexchars[sigval >> 4];
646*6ca2c52aSchristos 	  remcomOutBuffer[2] = hexchars[sigval & 0xf];
647*6ca2c52aSchristos 	  remcomOutBuffer[3] = 0;
648*6ca2c52aSchristos 	  break;
649*6ca2c52aSchristos 
650*6ca2c52aSchristos 	case 'd':		/* toggle debug flag */
651*6ca2c52aSchristos 	  break;
652*6ca2c52aSchristos 
653*6ca2c52aSchristos 	case 'g':		/* return the value of the CPU registers */
654*6ca2c52aSchristos 	  {
655*6ca2c52aSchristos 	    ptr = remcomOutBuffer;
656*6ca2c52aSchristos 	    ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
657*6ca2c52aSchristos 	    ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
658*6ca2c52aSchristos 	    memset(ptr, '0', 32 * 8); /* Floating point */
659*6ca2c52aSchristos 	    mem2hex((char *)&registers[Y],
660*6ca2c52aSchristos 		    ptr + 32 * 4 * 2,
661*6ca2c52aSchristos 		    8 * 4,
662*6ca2c52aSchristos 		    0);		/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
663*6ca2c52aSchristos 	  }
664*6ca2c52aSchristos 	  break;
665*6ca2c52aSchristos 
666*6ca2c52aSchristos 	case 'G':	   /* set the value of the CPU registers - return OK */
667*6ca2c52aSchristos 	  {
668*6ca2c52aSchristos 	    unsigned long *newsp, psr;
669*6ca2c52aSchristos 
670*6ca2c52aSchristos 	    psr = registers[PSR];
671*6ca2c52aSchristos 
672*6ca2c52aSchristos 	    hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
673*6ca2c52aSchristos 	    hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
674*6ca2c52aSchristos 	    hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
675*6ca2c52aSchristos 		    8 * 4, 0);	/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
676*6ca2c52aSchristos 
677*6ca2c52aSchristos 	    /* See if the stack pointer has moved.  If so, then copy the saved
678*6ca2c52aSchristos 	       locals and ins to the new location.  This keeps the window
679*6ca2c52aSchristos 	       overflow and underflow routines happy.  */
680*6ca2c52aSchristos 
681*6ca2c52aSchristos 	    newsp = (unsigned long *)registers[SP];
682*6ca2c52aSchristos 	    if (sp != newsp)
683*6ca2c52aSchristos 	      sp = memcpy(newsp, sp, 16 * 4);
684*6ca2c52aSchristos 
685*6ca2c52aSchristos 	    /* Don't allow CWP to be modified. */
686*6ca2c52aSchristos 
687*6ca2c52aSchristos 	    if (psr != registers[PSR])
688*6ca2c52aSchristos 	      registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
689*6ca2c52aSchristos 
690*6ca2c52aSchristos 	    strcpy(remcomOutBuffer,"OK");
691*6ca2c52aSchristos 	  }
692*6ca2c52aSchristos 	  break;
693*6ca2c52aSchristos 
694*6ca2c52aSchristos 	case 'm':	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
695*6ca2c52aSchristos 	  /* Try to read %x,%x.  */
696*6ca2c52aSchristos 
697*6ca2c52aSchristos 	  if (hexToInt(&ptr, &addr)
698*6ca2c52aSchristos 	      && *ptr++ == ','
699*6ca2c52aSchristos 	      && hexToInt(&ptr, &length))
700*6ca2c52aSchristos 	    {
701*6ca2c52aSchristos 	      if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
702*6ca2c52aSchristos 		break;
703*6ca2c52aSchristos 
704*6ca2c52aSchristos 	      strcpy (remcomOutBuffer, "E03");
705*6ca2c52aSchristos 	    }
706*6ca2c52aSchristos 	  else
707*6ca2c52aSchristos 	    strcpy(remcomOutBuffer,"E01");
708*6ca2c52aSchristos 	  break;
709*6ca2c52aSchristos 
710*6ca2c52aSchristos 	case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
711*6ca2c52aSchristos 	  /* Try to read '%x,%x:'.  */
712*6ca2c52aSchristos 
713*6ca2c52aSchristos 	  if (hexToInt(&ptr, &addr)
714*6ca2c52aSchristos 	      && *ptr++ == ','
715*6ca2c52aSchristos 	      && hexToInt(&ptr, &length)
716*6ca2c52aSchristos 	      && *ptr++ == ':')
717*6ca2c52aSchristos 	    {
718*6ca2c52aSchristos 	      if (hex2mem(ptr, (char *)addr, length, 1))
719*6ca2c52aSchristos 		strcpy(remcomOutBuffer, "OK");
720*6ca2c52aSchristos 	      else
721*6ca2c52aSchristos 		strcpy(remcomOutBuffer, "E03");
722*6ca2c52aSchristos 	    }
723*6ca2c52aSchristos 	  else
724*6ca2c52aSchristos 	    strcpy(remcomOutBuffer, "E02");
725*6ca2c52aSchristos 	  break;
726*6ca2c52aSchristos 
727*6ca2c52aSchristos 	case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
728*6ca2c52aSchristos 	  /* try to read optional parameter, pc unchanged if no parm */
729*6ca2c52aSchristos 
730*6ca2c52aSchristos 	  if (hexToInt(&ptr, &addr))
731*6ca2c52aSchristos 	    {
732*6ca2c52aSchristos 	      registers[PC] = addr;
733*6ca2c52aSchristos 	      registers[NPC] = addr + 4;
734*6ca2c52aSchristos 	    }
735*6ca2c52aSchristos 
736*6ca2c52aSchristos /* Need to flush the instruction cache here, as we may have deposited a
737*6ca2c52aSchristos    breakpoint, and the icache probably has no way of knowing that a data ref to
738*6ca2c52aSchristos    some location may have changed something that is in the instruction cache.
739*6ca2c52aSchristos  */
740*6ca2c52aSchristos 
741*6ca2c52aSchristos 	  flush_i_cache();
742*6ca2c52aSchristos 	  return;
743*6ca2c52aSchristos 
744*6ca2c52aSchristos 	  /* kill the program */
745*6ca2c52aSchristos 	case 'k' :		/* do nothing */
746*6ca2c52aSchristos 	  break;
747*6ca2c52aSchristos #if 0
748*6ca2c52aSchristos 	case 't':		/* Test feature */
749*6ca2c52aSchristos 	  asm (" std %f30,[%sp]");
750*6ca2c52aSchristos 	  break;
751*6ca2c52aSchristos #endif
752*6ca2c52aSchristos 	case 'r':		/* Reset */
753*6ca2c52aSchristos 	  asm ("call 0
754*6ca2c52aSchristos 		nop ");
755*6ca2c52aSchristos 	  break;
756*6ca2c52aSchristos 	}			/* switch */
757*6ca2c52aSchristos 
758*6ca2c52aSchristos       /* reply to the request */
759*6ca2c52aSchristos       putpacket(remcomOutBuffer);
760*6ca2c52aSchristos     }
761*6ca2c52aSchristos }
762*6ca2c52aSchristos 
763*6ca2c52aSchristos /* This function will generate a breakpoint exception.  It is used at the
764*6ca2c52aSchristos    beginning of a program to sync up with a debugger and can be used
765*6ca2c52aSchristos    otherwise as a quick means to stop program execution and "break" into
766*6ca2c52aSchristos    the debugger. */
767*6ca2c52aSchristos 
768*6ca2c52aSchristos void
breakpoint(void)769*6ca2c52aSchristos breakpoint (void)
770*6ca2c52aSchristos {
771*6ca2c52aSchristos   if (!initialized)
772*6ca2c52aSchristos     return;
773*6ca2c52aSchristos 
774*6ca2c52aSchristos   asm("	.globl _breakinst
775*6ca2c52aSchristos 
776*6ca2c52aSchristos 	_breakinst: ta 1
777*6ca2c52aSchristos       ");
778*6ca2c52aSchristos }
779