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