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