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.
33 * Based on sparc-stub.c, it's modified for SPARClite Debug Unit hardware
34 * breakpoint support to create sparclite-stub.c, by Kung Hsu, Cygnus Support.
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
38 * To enable debugger support, two things need to happen. One, a
39 * call to set_debug_traps() is necessary in order to allow any breakpoints
40 * or error conditions to be properly intercepted and reported to gdb.
41 * Two, a breakpoint needs to be generated to begin communication. This
42 * is most easily accomplished by a call to breakpoint(). Breakpoint()
43 * simulates a breakpoint by executing a trap #1.
47 * The following gdb commands are supported:
49 * command function Return value
51 * g return the value of the CPU registers hex data or ENN
52 * G set the value of the CPU registers OK or ENN
54 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
55 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 * c Resume at current address SNN ( signal NN)
58 * cAA..AA Continue at address AA..AA SNN
60 * s Step one instruction SNN
61 * sAA..AA Step one instruction from AA..AA SNN
65 * ? What was the last sigval ? SNN (signal NN)
67 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
70 * All commands and responses are sent with a packet which includes a
71 * checksum. A packet consists of
73 * $<packet info>#<checksum>.
76 * <packet info> :: <characters representing the command or response>
77 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
79 * When a packet is received, it is first acknowledged with either '+' or '-'.
80 * '+' indicates a successful transfer. '-' indicates a failed transfer.
85 * $m0,10#2a +$00010203040506070809101112131415#42
87 ****************************************************************************/
92 /************************************************************************
94 * external low-level support routines
97 extern putDebugChar(); /* write a single character */
98 extern getDebugChar(); /* read and return a single char */
100 /************************************************************************/
101 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
102 /* at least NUMREGBYTES*2 are needed for register packets */
105 static int initialized
= 0; /* !0 means we've been initialized */
107 extern void breakinst();
108 static void hw_breakpoint();
109 static void set_mem_fault_trap();
110 static void get_in_break_mode();
112 static const char hexchars
[]="0123456789abcdef";
116 /* Number of bytes of registers. */
117 #define NUMREGBYTES (NUMREGS * 4)
118 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
119 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
120 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
121 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
123 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
124 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
125 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
126 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
127 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
,
128 DIA1
, DIA2
, DDA1
, DDA2
, DDV1
, DDV2
, DCR
, DSR
};
130 /*************************** ASSEMBLY CODE MACROS *************************/
133 extern void trap_low();
136 .reserve trapstack, 1000 * 4, \"bss\", 8
147 ! This function is called when any SPARC trap (except window overflow or
148 ! underflow) occurs. It makes sure that the invalid register window is still
149 ! available before jumping into C code. It will also restore the world if you
150 ! return from handle_exception.
157 srl %l3, %l0, %l4 ! wim >> cwp
159 bne window_fine ! Branch if not in the invalid window
162 ! Handle window overflow
164 mov %g1, %l4 ! Save g1, we use it to hold the wim
165 srl %l3, 1, %g1 ! Rotate wim right
167 bg good_wim ! Branch if new wim is non-zero
169 ! At this point, we need to bring a 1 into the high order bit of the wim.
170 ! Since we don't want to make any assumptions about the number of register
171 ! windows, we figure it out dynamically so as to setup the wim correctly.
173 not %g1 ! Fill g1 with ones
174 mov %g1, %wim ! Fill the wim with ones
178 mov %wim, %g1 ! Read back the wim
179 inc %g1 ! Now g1 has 1 just to left of wim
180 srl %g1, 1, %g1 ! Now put 1 at top of wim
181 mov %g0, %wim ! Clear wim so that subsequent save
187 save %g0, %g0, %g0 ! Slip into next window
188 mov %g1, %wim ! Install the new wim
190 std %l0, [%sp + 0 * 4] ! save L & I registers
191 std %l2, [%sp + 2 * 4]
192 std %l4, [%sp + 4 * 4]
193 std %l6, [%sp + 6 * 4]
195 std %i0, [%sp + 8 * 4]
196 std %i2, [%sp + 10 * 4]
197 std %i4, [%sp + 12 * 4]
198 std %i6, [%sp + 14 * 4]
200 restore ! Go back to trap window.
201 mov %l4, %g1 ! Restore %g1
204 sethi %hi(in_trap_handler), %l4
205 ld [%lo(in_trap_handler) + %l4], %l5
210 set trapstack+1000*4, %sp ! Switch to trap stack
213 st %l5, [%lo(in_trap_handler) + %l4]
214 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
215 ! + hidden arg + arg spill
216 ! + doubleword alignment
217 ! + registers[72] local var
219 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
220 std %g2, [%sp + (24 + 2) * 4]
221 std %g4, [%sp + (24 + 4) * 4]
222 std %g6, [%sp + (24 + 6) * 4]
224 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
225 std %i2, [%sp + (24 + 10) * 4]
226 std %i4, [%sp + (24 + 12) * 4]
227 std %i6, [%sp + (24 + 14) * 4]
228 ! F0->F31 not implemented
231 st %l4, [%sp + (24 + 64) * 4] ! Y
232 st %l0, [%sp + (24 + 65) * 4] ! PSR
233 st %l3, [%sp + (24 + 66) * 4] ! WIM
234 st %l5, [%sp + (24 + 67) * 4] ! TBR
235 st %l1, [%sp + (24 + 68) * 4] ! PC
236 st %l2, [%sp + (24 + 69) * 4] ! NPC
237 ! CPSR and FPSR not impl
239 mov %l4, %psr ! Turn on traps, disable interrupts
243 call _get_in_break_mode
248 sethi %hi(0xff00), %l5
249 or %l5, %lo(0xff00), %l5
252 st %l4, [%sp + (24 + 72) * 4] ! DIA1, debug instr addr 1
255 st %l4, [%sp + (24 + 73) * 4] ! DIA2, debug instr addr 2
258 st %l4, [%sp + (24 + 74) * 4] ! DDA1, debug data addr 1
261 st %l4, [%sp + (24 + 75) * 4] ! DDA2, debug data addr 2
264 st %l4, [%sp + (24 + 76) * 4] ! DDV1, debug data val 1
267 st %l4, [%sp + (24 + 77) * 4] ! DDV2, debug data val 2
270 st %l4, [%sp + (24 + 78) * 4] ! DCR, debug control reg
273 st %l4, [%sp + (24 + 79) * 4] ! DSR, debug status reg
277 mov %l4, %psr ! Turn on traps, disable interrupts
281 call _handle_exception
282 add %sp, 24 * 4, %o0 ! Pass address of registers
284 ! Reload all of the registers that aren't on the stack
286 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
287 ldd [%sp + (24 + 2) * 4], %g2
288 ldd [%sp + (24 + 4) * 4], %g4
289 ldd [%sp + (24 + 6) * 4], %g6
291 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
292 ldd [%sp + (24 + 10) * 4], %i2
293 ldd [%sp + (24 + 12) * 4], %i4
294 ldd [%sp + (24 + 14) * 4], %i6
296 sethi %hi(0xff00), %l2
297 or %l2, %lo(0xff00), %l2
298 ldd [%sp + (24 + 72) * 4], %l4 ! DIA1, debug instr addr 1
304 ldd [%sp + (24 + 74) * 4], %l4 ! DDA1, debug data addr 1
311 ldd [%sp + (24 + 76) * 4], %l4 ! DDV1, debug data value 1
318 ld [%sp + (24 + 78) * 4], %l4 ! DCR, debug control reg
319 ld [%sp + (24 + 79) * 4], %l5 ! DSR, debug control reg
330 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
331 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
333 restore ! Ensure that previous window is valid
334 save %g0, %g0, %g0 ! by causing a window_underflow trap
337 mov %l1, %psr ! Make sure that traps are disabled
339 sethi %hi(in_trap_handler), %l4
340 ld [%lo(in_trap_handler) + %l4], %l5
342 st %l5, [%lo(in_trap_handler) + %l4]
344 jmpl %l2, %g0 ! Restore old PC
345 rett %l3 ! Restore old nPC
348 /* Convert ch from a hex digit to an int */
354 if (ch
>= 'a' && ch
<= 'f')
356 if (ch
>= '0' && ch
<= '9')
358 if (ch
>= 'A' && ch
<= 'F')
363 /* scan for the sequence $<data>#<checksum> */
369 unsigned char checksum
;
370 unsigned char xmitcsum
;
377 /* wait around for the start character, ignore all other characters */
378 while ((ch
= (getDebugChar() & 0x7f)) != '$') ;
385 /* now, read until a # or end of buffer is found */
386 while (count
< BUFMAX
)
388 ch
= getDebugChar() & 0x7f;
391 checksum
= checksum
+ ch
;
403 xmitcsum
= hex(getDebugChar() & 0x7f) << 4;
404 xmitcsum
|= hex(getDebugChar() & 0x7f);
406 /* Humans shouldn't have to figure out checksums to type to it. */
410 if (checksum
!= xmitcsum
)
411 putDebugChar('-'); /* failed checksum */
414 putDebugChar('+'); /* successful transfer */
415 /* if a sequence char is present, reply the sequence ID */
416 if (buffer
[2] == ':')
418 putDebugChar(buffer
[0]);
419 putDebugChar(buffer
[1]);
420 /* remove sequence chars from buffer */
421 count
= strlen(buffer
);
422 for (i
=3; i
<= count
; i
++)
423 buffer
[i
-3] = buffer
[i
];
428 while (checksum
!= xmitcsum
);
431 /* send the packet in buffer. */
435 unsigned char *buffer
;
437 unsigned char checksum
;
441 /* $<packet info>#<checksum>. */
448 while (ch
= buffer
[count
])
450 if (! putDebugChar(ch
))
457 putDebugChar(hexchars
[checksum
>> 4]);
458 putDebugChar(hexchars
[checksum
& 0xf]);
461 while ((getDebugChar() & 0x7f) != '+');
464 static char remcomInBuffer
[BUFMAX
];
465 static char remcomOutBuffer
[BUFMAX
];
467 /* Indicate to caller of mem2hex or hex2mem that there has been an
469 static volatile int mem_err
= 0;
471 /* Convert the memory pointed to by mem into hex, placing result in buf.
472 * Return a pointer to the last char put in buf (null), in case of mem fault,
474 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
475 * a 0, else treat a fault like any other fault in the stub.
478 static unsigned char *
479 mem2hex(mem
, buf
, count
, may_fault
)
487 set_mem_fault_trap(may_fault
);
494 *buf
++ = hexchars
[ch
>> 4];
495 *buf
++ = hexchars
[ch
& 0xf];
500 set_mem_fault_trap(0);
505 /* convert the hex array pointed to by buf into binary to be placed in mem
506 * return a pointer to the character AFTER the last byte written */
509 hex2mem(buf
, mem
, count
, may_fault
)
518 set_mem_fault_trap(may_fault
);
520 for (i
=0; i
<count
; i
++)
522 ch
= hex(*buf
++) << 4;
529 set_mem_fault_trap(0);
534 /* This table contains the mapping between SPARC hardware trap types, and
535 signals, which are primarily what GDB understands. It also indicates
536 which hardware traps we need to commandeer when initializing the stub. */
538 static struct hard_trap_info
540 unsigned char tt
; /* Trap type code for SPARClite */
541 unsigned char signo
; /* Signal that we map this trap into */
542 } hard_trap_info
[] = {
543 {1, SIGSEGV
}, /* instruction access error */
544 {2, SIGILL
}, /* privileged instruction */
545 {3, SIGILL
}, /* illegal instruction */
546 {4, SIGEMT
}, /* fp disabled */
547 {36, SIGEMT
}, /* cp disabled */
548 {7, SIGBUS
}, /* mem address not aligned */
549 {9, SIGSEGV
}, /* data access exception */
550 {10, SIGEMT
}, /* tag overflow */
551 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
552 {255, SIGTRAP
}, /* hardware breakpoint */
553 {0, 0} /* Must be last */
556 /* Set up exception handlers for tracing and breakpoints */
561 struct hard_trap_info
*ht
;
563 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
564 exceptionHandler(ht
->tt
, trap_low
);
566 /* In case GDB is started before us, ack any packets (presumably
567 "$?#xx") sitting there. */
575 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
576 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
577 ! 0 would ever contain code that could mem fault. This routine will skip
578 ! past the faulting instruction after setting mem_err.
584 sethi %hi(_mem_err), %l0
585 st %l1, [%l0 + %lo(_mem_err)]
591 set_mem_fault_trap(enable
)
594 extern void fltr_set_mem_err();
598 exceptionHandler(9, fltr_set_mem_err
);
600 exceptionHandler(9, trap_low
);
607 _dummy_hw_breakpoint:
615 set_hw_breakpoint_trap(enable
)
618 extern void dummy_hw_breakpoint();
621 exceptionHandler(255, dummy_hw_breakpoint
);
623 exceptionHandler(255, trap_low
);
629 set_hw_breakpoint_trap(1);
632 sethi %hi(0xff10), %l4
633 or %l4, %lo(0xff10), %l4
640 set_hw_breakpoint_trap(0);
643 /* Convert the SPARC hardware trap type code to a unix signal number. */
649 struct hard_trap_info
*ht
;
651 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
655 return SIGHUP
; /* default for things we don't know about */
659 * While we find nice hex chars, build an int.
660 * Return number of chars processed.
664 hexToInt(char **ptr
, int *intValue
)
673 hexValue
= hex(**ptr
);
677 *intValue
= (*intValue
<< 4) | hexValue
;
687 * This function does all command procesing for interfacing to gdb. It
688 * returns 1 if you should skip the instruction at the trap address, 0
694 handle_exception (registers
)
695 unsigned long *registers
;
697 int tt
; /* Trap type */
705 /* First, we must force all of the windows to be spilled out */
707 asm(" save %sp, -64, %sp
725 if (registers
[PC
] == (unsigned long)breakinst
)
727 registers
[PC
] = registers
[NPC
];
730 sp
= (unsigned long *)registers
[SP
];
732 dsr
= (unsigned long)registers
[DSR
];
739 tt
= (registers
[TBR
] >> 4) & 0xff;
742 /* reply to host that an exception has occurred */
743 sigval
= computeSignal(tt
);
744 ptr
= remcomOutBuffer
;
747 *ptr
++ = hexchars
[sigval
>> 4];
748 *ptr
++ = hexchars
[sigval
& 0xf];
750 *ptr
++ = hexchars
[PC
>> 4];
751 *ptr
++ = hexchars
[PC
& 0xf];
753 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
756 *ptr
++ = hexchars
[FP
>> 4];
757 *ptr
++ = hexchars
[FP
& 0xf];
759 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
762 *ptr
++ = hexchars
[SP
>> 4];
763 *ptr
++ = hexchars
[SP
& 0xf];
765 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
768 *ptr
++ = hexchars
[NPC
>> 4];
769 *ptr
++ = hexchars
[NPC
& 0xf];
771 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
774 *ptr
++ = hexchars
[O7
>> 4];
775 *ptr
++ = hexchars
[O7
& 0xf];
777 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
782 putpacket(remcomOutBuffer
);
786 remcomOutBuffer
[0] = 0;
788 getpacket(remcomInBuffer
);
789 switch (remcomInBuffer
[0])
792 remcomOutBuffer
[0] = 'S';
793 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
794 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
795 remcomOutBuffer
[3] = 0;
799 /* toggle debug flag */
802 case 'g': /* return the value of the CPU registers */
804 ptr
= remcomOutBuffer
;
805 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
806 ptr
= mem2hex(sp
+ 0, ptr
, 16 * 4, 0); /* L & I regs */
807 memset(ptr
, '0', 32 * 8); /* Floating point */
808 ptr
= mem2hex((char *)®isters
[Y
],
811 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
812 mem2hex((char *)®isters
[DIA1
], ptr
,
813 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
817 case 'G': /* set the value of the CPU registers - return OK */
819 unsigned long *newsp
, psr
;
821 psr
= registers
[PSR
];
823 ptr
= &remcomInBuffer
[1];
824 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
825 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 16 * 4, 0); /* L & I regs */
826 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
827 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
828 hex2mem(ptr
+ 72 * 4 * 2, (char *)®isters
[DIA1
],
829 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
831 /* See if the stack pointer has moved. If so, then copy the saved
832 locals and ins to the new location. This keeps the window
833 overflow and underflow routines happy. */
835 newsp
= (unsigned long *)registers
[SP
];
837 sp
= memcpy(newsp
, sp
, 16 * 4);
839 /* Don't allow CWP to be modified. */
841 if (psr
!= registers
[PSR
])
842 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
844 strcpy(remcomOutBuffer
,"OK");
848 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
849 /* Try to read %x,%x. */
851 ptr
= &remcomInBuffer
[1];
853 if (hexToInt(&ptr
, &addr
)
855 && hexToInt(&ptr
, &length
))
857 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
860 strcpy (remcomOutBuffer
, "E03");
863 strcpy(remcomOutBuffer
,"E01");
866 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
867 /* Try to read '%x,%x:'. */
869 ptr
= &remcomInBuffer
[1];
871 if (hexToInt(&ptr
, &addr
)
873 && hexToInt(&ptr
, &length
)
876 if (hex2mem(ptr
, (char *)addr
, length
, 1))
877 strcpy(remcomOutBuffer
, "OK");
879 strcpy(remcomOutBuffer
, "E03");
882 strcpy(remcomOutBuffer
, "E02");
885 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
886 /* try to read optional parameter, pc unchanged if no parm */
888 ptr
= &remcomInBuffer
[1];
889 if (hexToInt(&ptr
, &addr
))
891 registers
[PC
] = addr
;
892 registers
[NPC
] = addr
+ 4;
895 /* Need to flush the instruction cache here, as we may have deposited a
896 breakpoint, and the icache probably has no way of knowing that a data ref to
897 some location may have changed something that is in the instruction cache.
903 /* kill the program */
904 case 'k' : /* do nothing */
907 case 't': /* Test feature */
908 asm (" std %f30,[%sp]");
911 case 'r': /* Reset */
917 Disabled until we can unscrew
this properly
919 case 'b': /* bBB... Set baud rate to BB... */
922 extern void set_timer_3();
924 ptr
= &remcomInBuffer
[1];
925 if (!hexToInt(&ptr
, &baudrate
))
927 strcpy(remcomOutBuffer
,"B01");
931 /* Convert baud rate to uart clock divider */
944 strcpy(remcomOutBuffer
,"B02");
948 putpacket("OK"); /* Ack before changing speed */
949 set_timer_3(baudrate
); /* Set it */
955 /* reply to the request */
956 putpacket(remcomOutBuffer
);
960 /* This function will generate a breakpoint exception. It is used at the
961 beginning of a program to sync up with a debugger and can be used
962 otherwise as a quick means to stop program execution and "break" into
971 asm(" .globl _breakinst