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 *)®isters[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 *)®isters[NPC], ptr, 4, 0);
624e93f7393Sniklas *ptr++ = ';';
625e93f7393Sniklas
626e93f7393Sniklas *ptr++ = hexchars[O7 >> 4];
627e93f7393Sniklas *ptr++ = hexchars[O7 & 0xf];
628e93f7393Sniklas *ptr++ = ':';
629e93f7393Sniklas ptr = mem2hex((char *)®isters[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 *)®isters[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 *)®isters[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