1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for SPARC by Stu Grossman, Cygnus Support.
34 * This code has been extensively tested on the Fujitsu SPARClite demo board.
36 * To enable debugger support, two things need to happen. One, a
37 * call to set_debug_traps() is necessary in order to allow any breakpoints
38 * or error conditions to be properly intercepted and reported to gdb.
39 * Two, a breakpoint needs to be generated to begin communication. This
40 * is most easily accomplished by a call to breakpoint(). Breakpoint()
41 * simulates a breakpoint by executing a trap #1.
45 * The following gdb commands are supported:
47 * command function Return value
49 * g return the value of the CPU registers hex data or ENN
50 * G set the value of the CPU registers OK or ENN
52 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
53 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
55 * c Resume at current address SNN ( signal NN)
56 * cAA..AA Continue at address AA..AA SNN
58 * s Step one instruction SNN
59 * sAA..AA Step one instruction from AA..AA SNN
63 * ? What was the last sigval ? SNN (signal NN)
65 * All commands and responses are sent with a packet which includes a
66 * checksum. A packet consists of
68 * $<packet info>#<checksum>.
71 * <packet info> :: <characters representing the command or response>
72 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
74 * When a packet is received, it is first acknowledged with either '+' or '-'.
75 * '+' indicates a successful transfer. '-' indicates a failed transfer.
80 * $m0,10#2a +$00010203040506070809101112131415#42
82 ****************************************************************************/
87 /************************************************************************
89 * external low-level support routines
92 extern void putDebugChar(); /* write a single character */
93 extern int getDebugChar(); /* read and return a single char */
95 /************************************************************************/
96 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
97 /* at least NUMREGBYTES*2 are needed for register packets */
100 static int initialized
= 0; /* !0 means we've been initialized */
102 static void set_mem_fault_trap();
104 static const char hexchars
[]="0123456789abcdef";
108 /* Number of bytes of registers. */
109 #define NUMREGBYTES (NUMREGS * 4)
110 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
111 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
112 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
113 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
115 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
116 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
117 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
118 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
119 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
};
121 /*************************** ASSEMBLY CODE MACROS *************************/
124 extern void trap_low();
127 .reserve trapstack, 1000 * 4, \"bss\", 8
138 ! This function is called when any SPARC trap (except window overflow or
139 ! underflow) occurs. It makes sure that the invalid register window is still
140 ! available before jumping into C code. It will also restore the world if you
141 ! return from handle_exception.
148 srl %l3, %l0, %l4 ! wim >> cwp
150 bne window_fine ! Branch if not in the invalid window
153 ! Handle window overflow
155 mov %g1, %l4 ! Save g1, we use it to hold the wim
156 srl %l3, 1, %g1 ! Rotate wim right
158 bg good_wim ! Branch if new wim is non-zero
161 ! At this point, we need to bring a 1 into the high order bit of the wim.
162 ! Since we don't want to make any assumptions about the number of register
163 ! windows, we figure it out dynamically so as to setup the wim correctly.
165 not %g1 ! Fill g1 with ones
166 mov %g1, %wim ! Fill the wim with ones
170 mov %wim, %g1 ! Read back the wim
171 inc %g1 ! Now g1 has 1 just to left of wim
172 srl %g1, 1, %g1 ! Now put 1 at top of wim
173 mov %g0, %wim ! Clear wim so that subsequent save
179 save %g0, %g0, %g0 ! Slip into next window
180 mov %g1, %wim ! Install the new wim
182 std %l0, [%sp + 0 * 4] ! save L & I registers
183 std %l2, [%sp + 2 * 4]
184 std %l4, [%sp + 4 * 4]
185 std %l6, [%sp + 6 * 4]
187 std %i0, [%sp + 8 * 4]
188 std %i2, [%sp + 10 * 4]
189 std %i4, [%sp + 12 * 4]
190 std %i6, [%sp + 14 * 4]
192 restore ! Go back to trap window.
193 mov %l4, %g1 ! Restore %g1
196 sethi %hi(in_trap_handler), %l4
197 ld [%lo(in_trap_handler) + %l4], %l5
202 set trapstack+1000*4, %sp ! Switch to trap stack
205 st %l5, [%lo(in_trap_handler) + %l4]
206 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
207 ! + hidden arg + arg spill
208 ! + doubleword alignment
209 ! + registers[72] local var
211 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
212 std %g2, [%sp + (24 + 2) * 4]
213 std %g4, [%sp + (24 + 4) * 4]
214 std %g6, [%sp + (24 + 6) * 4]
216 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
217 std %i2, [%sp + (24 + 10) * 4]
218 std %i4, [%sp + (24 + 12) * 4]
219 std %i6, [%sp + (24 + 14) * 4]
220 ! F0->F31 not implemented
223 st %l4, [%sp + (24 + 64) * 4] ! Y
224 st %l0, [%sp + (24 + 65) * 4] ! PSR
225 st %l3, [%sp + (24 + 66) * 4] ! WIM
226 st %l5, [%sp + (24 + 67) * 4] ! TBR
227 st %l1, [%sp + (24 + 68) * 4] ! PC
228 st %l2, [%sp + (24 + 69) * 4] ! NPC
230 ! CPSR and FPSR not impl
233 mov %l4, %psr ! Turn on traps, disable interrupts
235 call _handle_exception
236 add %sp, 24 * 4, %o0 ! Pass address of registers
238 ! Reload all of the registers that aren't on the stack
240 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
241 ldd [%sp + (24 + 2) * 4], %g2
242 ldd [%sp + (24 + 4) * 4], %g4
243 ldd [%sp + (24 + 6) * 4], %g6
245 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
246 ldd [%sp + (24 + 10) * 4], %i2
247 ldd [%sp + (24 + 12) * 4], %i4
248 ldd [%sp + (24 + 14) * 4], %i6
250 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
251 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
253 restore ! Ensure that previous window is valid
254 save %g0, %g0, %g0 ! by causing a window_underflow trap
257 mov %l1, %psr ! Make sure that traps are disabled
260 sethi %hi(in_trap_handler), %l4
261 ld [%lo(in_trap_handler) + %l4], %l5
263 st %l5, [%lo(in_trap_handler) + %l4]
265 jmpl %l2, %g0 ! Restore old PC
266 rett %l3 ! Restore old nPC
269 /* Convert ch from a hex digit to an int */
275 if (ch
>= 'a' && ch
<= 'f')
277 if (ch
>= '0' && ch
<= '9')
279 if (ch
>= 'A' && ch
<= 'F')
284 static char remcomInBuffer
[BUFMAX
];
285 static char remcomOutBuffer
[BUFMAX
];
287 /* scan for the sequence $<data>#<checksum> */
292 unsigned char *buffer
= &remcomInBuffer
[0];
293 unsigned char checksum
;
294 unsigned char xmitcsum
;
300 /* wait around for the start character, ignore all other characters */
301 while ((ch
= getDebugChar ()) != '$')
309 /* now, read until a # or end of buffer is found */
310 while (count
< BUFMAX
)
312 ch
= getDebugChar ();
317 checksum
= checksum
+ ch
;
325 ch
= getDebugChar ();
326 xmitcsum
= hex (ch
) << 4;
327 ch
= getDebugChar ();
328 xmitcsum
+= hex (ch
);
330 if (checksum
!= xmitcsum
)
332 putDebugChar ('-'); /* failed checksum */
336 putDebugChar ('+'); /* successful transfer */
338 /* if a sequence char is present, reply the sequence ID */
339 if (buffer
[2] == ':')
341 putDebugChar (buffer
[0]);
342 putDebugChar (buffer
[1]);
353 /* send the packet in buffer. */
357 unsigned char *buffer
;
359 unsigned char checksum
;
363 /* $<packet info>#<checksum>. */
370 while (ch
= buffer
[count
])
378 putDebugChar(hexchars
[checksum
>> 4]);
379 putDebugChar(hexchars
[checksum
& 0xf]);
382 while (getDebugChar() != '+');
385 /* Indicate to caller of mem2hex or hex2mem that there has been an
387 static volatile int mem_err
= 0;
389 /* Convert the memory pointed to by mem into hex, placing result in buf.
390 * Return a pointer to the last char put in buf (null), in case of mem fault,
392 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
393 * a 0, else treat a fault like any other fault in the stub.
396 static unsigned char *
397 mem2hex(mem
, buf
, count
, may_fault
)
405 set_mem_fault_trap(may_fault
);
412 *buf
++ = hexchars
[ch
>> 4];
413 *buf
++ = hexchars
[ch
& 0xf];
418 set_mem_fault_trap(0);
423 /* convert the hex array pointed to by buf into binary to be placed in mem
424 * return a pointer to the character AFTER the last byte written */
427 hex2mem(buf
, mem
, count
, may_fault
)
436 set_mem_fault_trap(may_fault
);
438 for (i
=0; i
<count
; i
++)
440 ch
= hex(*buf
++) << 4;
447 set_mem_fault_trap(0);
452 /* This table contains the mapping between SPARC hardware trap types, and
453 signals, which are primarily what GDB understands. It also indicates
454 which hardware traps we need to commandeer when initializing the stub. */
456 static struct hard_trap_info
458 unsigned char tt
; /* Trap type code for SPARClite */
459 unsigned char signo
; /* Signal that we map this trap into */
460 } hard_trap_info
[] = {
461 {1, SIGSEGV
}, /* instruction access error */
462 {2, SIGILL
}, /* privileged instruction */
463 {3, SIGILL
}, /* illegal instruction */
464 {4, SIGEMT
}, /* fp disabled */
465 {36, SIGEMT
}, /* cp disabled */
466 {7, SIGBUS
}, /* mem address not aligned */
467 {9, SIGSEGV
}, /* data access exception */
468 {10, SIGEMT
}, /* tag overflow */
469 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
470 {0, 0} /* Must be last */
473 /* Set up exception handlers for tracing and breakpoints */
478 struct hard_trap_info
*ht
;
480 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
481 exceptionHandler(ht
->tt
, trap_low
);
487 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
488 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
489 ! 0 would ever contain code that could mem fault. This routine will skip
490 ! past the faulting instruction after setting mem_err.
496 sethi %hi(_mem_err), %l0
497 st %l1, [%l0 + %lo(_mem_err)]
503 set_mem_fault_trap(enable
)
506 extern void fltr_set_mem_err();
510 exceptionHandler(9, fltr_set_mem_err
);
512 exceptionHandler(9, trap_low
);
515 /* Convert the SPARC hardware trap type code to a unix signal number. */
521 struct hard_trap_info
*ht
;
523 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
527 return SIGHUP
; /* default for things we don't know about */
531 * While we find nice hex chars, build an int.
532 * Return number of chars processed.
536 hexToInt(char **ptr
, int *intValue
)
545 hexValue
= hex(**ptr
);
549 *intValue
= (*intValue
<< 4) | hexValue
;
559 * This function does all command procesing for interfacing to gdb. It
560 * returns 1 if you should skip the instruction at the trap address, 0
564 extern void breakinst();
567 handle_exception (registers
)
568 unsigned long *registers
;
570 int tt
; /* Trap type */
577 /* First, we must force all of the windows to be spilled out */
579 asm(" save %sp, -64, %sp
597 if (registers
[PC
] == (unsigned long)breakinst
)
599 registers
[PC
] = registers
[NPC
];
603 sp
= (unsigned long *)registers
[SP
];
605 tt
= (registers
[TBR
] >> 4) & 0xff;
607 /* reply to host that an exception has occurred */
608 sigval
= computeSignal(tt
);
609 ptr
= remcomOutBuffer
;
612 *ptr
++ = hexchars
[sigval
>> 4];
613 *ptr
++ = hexchars
[sigval
& 0xf];
615 *ptr
++ = hexchars
[PC
>> 4];
616 *ptr
++ = hexchars
[PC
& 0xf];
618 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
621 *ptr
++ = hexchars
[FP
>> 4];
622 *ptr
++ = hexchars
[FP
& 0xf];
624 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
627 *ptr
++ = hexchars
[SP
>> 4];
628 *ptr
++ = hexchars
[SP
& 0xf];
630 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
633 *ptr
++ = hexchars
[NPC
>> 4];
634 *ptr
++ = hexchars
[NPC
& 0xf];
636 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
639 *ptr
++ = hexchars
[O7
>> 4];
640 *ptr
++ = hexchars
[O7
& 0xf];
642 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
647 putpacket(remcomOutBuffer
);
651 remcomOutBuffer
[0] = 0;
657 remcomOutBuffer
[0] = 'S';
658 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
659 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
660 remcomOutBuffer
[3] = 0;
663 case 'd': /* toggle debug flag */
666 case 'g': /* return the value of the CPU registers */
668 ptr
= remcomOutBuffer
;
669 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
670 ptr
= mem2hex(sp
+ 0, ptr
, 16 * 4, 0); /* L & I regs */
671 memset(ptr
, '0', 32 * 8); /* Floating point */
672 mem2hex((char *)®isters
[Y
],
675 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
679 case 'G': /* set the value of the CPU registers - return OK */
681 unsigned long *newsp
, psr
;
683 psr
= registers
[PSR
];
685 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
686 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 16 * 4, 0); /* L & I regs */
687 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
688 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
690 /* See if the stack pointer has moved. If so, then copy the saved
691 locals and ins to the new location. This keeps the window
692 overflow and underflow routines happy. */
694 newsp
= (unsigned long *)registers
[SP
];
696 sp
= memcpy(newsp
, sp
, 16 * 4);
698 /* Don't allow CWP to be modified. */
700 if (psr
!= registers
[PSR
])
701 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
703 strcpy(remcomOutBuffer
,"OK");
707 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
708 /* Try to read %x,%x. */
710 if (hexToInt(&ptr
, &addr
)
712 && hexToInt(&ptr
, &length
))
714 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
717 strcpy (remcomOutBuffer
, "E03");
720 strcpy(remcomOutBuffer
,"E01");
723 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
724 /* Try to read '%x,%x:'. */
726 if (hexToInt(&ptr
, &addr
)
728 && hexToInt(&ptr
, &length
)
731 if (hex2mem(ptr
, (char *)addr
, length
, 1))
732 strcpy(remcomOutBuffer
, "OK");
734 strcpy(remcomOutBuffer
, "E03");
737 strcpy(remcomOutBuffer
, "E02");
740 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
741 /* try to read optional parameter, pc unchanged if no parm */
743 if (hexToInt(&ptr
, &addr
))
745 registers
[PC
] = addr
;
746 registers
[NPC
] = addr
+ 4;
749 /* Need to flush the instruction cache here, as we may have deposited a
750 breakpoint, and the icache probably has no way of knowing that a data ref to
751 some location may have changed something that is in the instruction cache.
757 /* kill the program */
758 case 'k' : /* do nothing */
761 case 't': /* Test feature */
762 asm (" std %f30,[%sp]");
765 case 'r': /* Reset */
771 /* reply to the request */
772 putpacket(remcomOutBuffer
);
776 /* This function will generate a breakpoint exception. It is used at the
777 beginning of a program to sync up with a debugger and can be used
778 otherwise as a quick means to stop program execution and "break" into
787 asm(" .globl _breakinst
This page took 0.045018 seconds and 4 git commands to generate.