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 *)®isters[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 *)®isters[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 *)®isters[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 *)®isters[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 *)®isters[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