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 its 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 ****************************************************************************/
93 /************************************************************************
95 * external low-level support routines
97 extern putDebugChar(); /* write a single character */
98 extern getDebugChar(); /* read and return a single char */
100 /* Pointer to hook for outbyte, set by stub's exception handler. */
101 extern void (*__outbyte_hook
)();
103 /************************************************************************/
104 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
105 /* at least NUMREGBYTES*2 are needed for register packets */
108 static int initialized
= 0; /* !0 means we've been initialized */
110 extern void breakinst();
111 static void hw_breakpoint();
112 static void set_mem_fault_trap();
113 static void get_in_break_mode();
115 static const char hexchars
[]="0123456789abcdef";
119 /* Number of bytes of registers. */
120 #define NUMREGBYTES (NUMREGS * 4)
121 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
122 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
123 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
124 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
126 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
127 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
128 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
129 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
130 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
,
131 DIA1
, DIA2
, DDA1
, DDA2
, DDV1
, DDV2
, DCR
, DSR
};
133 /*************************** ASSEMBLY CODE MACROS *************************/
136 extern void trap_low();
139 .reserve trapstack, 1000 * 4, \"bss\", 8
150 ! This function is called when any SPARC trap (except window overflow or
151 ! underflow) occurs. It makes sure that the invalid register window is still
152 ! available before jumping into C code. It will also restore the world if you
153 ! return from handle_exception.
155 .globl " STRINGSYM(trap_low
) "
156 " STRINGSYM(trap_low
) ":
160 srl %l3, %l0, %l4 ! wim >> cwp
162 bne window_fine ! Branch if not in the invalid window
165 ! Handle window overflow
167 mov %g1, %l4 ! Save g1, we use it to hold the wim
168 srl %l3, 1, %g1 ! Rotate wim right
170 bg good_wim ! Branch if new wim is non-zero
173 ! At this point, we need to bring a 1 into the high order bit of the wim.
174 ! Since we don't want to make any assumptions about the number of register
175 ! windows, we figure it out dynamically so as to setup the wim correctly.
177 not %g1 ! Fill g1 with ones
178 mov %g1, %wim ! Fill the wim with ones
182 mov %wim, %g1 ! Read back the wim
183 inc %g1 ! Now g1 has 1 just to left of wim
184 srl %g1, 1, %g1 ! Now put 1 at top of wim
185 mov %g0, %wim ! Clear wim so that subsequent save
191 save %g0, %g0, %g0 ! Slip into next window
192 mov %g1, %wim ! Install the new wim
194 std %l0, [%sp + 0 * 4] ! save L & I registers
195 std %l2, [%sp + 2 * 4]
196 std %l4, [%sp + 4 * 4]
197 std %l6, [%sp + 6 * 4]
199 std %i0, [%sp + 8 * 4]
200 std %i2, [%sp + 10 * 4]
201 std %i4, [%sp + 12 * 4]
202 std %i6, [%sp + 14 * 4]
204 restore ! Go back to trap window.
205 mov %l4, %g1 ! Restore %g1
208 sethi %hi(in_trap_handler), %l4
209 ld [%lo(in_trap_handler) + %l4], %l5
214 set trapstack+1000*4, %sp ! Switch to trap stack
217 st %l5, [%lo(in_trap_handler) + %l4]
218 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
219 ! + hidden arg + arg spill
220 ! + doubleword alignment
221 ! + registers[72] local var
223 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
224 std %g2, [%sp + (24 + 2) * 4]
225 std %g4, [%sp + (24 + 4) * 4]
226 std %g6, [%sp + (24 + 6) * 4]
228 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
229 std %i2, [%sp + (24 + 10) * 4]
230 std %i4, [%sp + (24 + 12) * 4]
231 std %i6, [%sp + (24 + 14) * 4]
232 ! F0->F31 not implemented
235 st %l4, [%sp + (24 + 64) * 4] ! Y
236 st %l0, [%sp + (24 + 65) * 4] ! PSR
237 st %l3, [%sp + (24 + 66) * 4] ! WIM
238 st %l5, [%sp + (24 + 67) * 4] ! TBR
239 st %l1, [%sp + (24 + 68) * 4] ! PC
240 st %l2, [%sp + (24 + 69) * 4] ! NPC
241 ! CPSR and FPSR not impl
243 mov %l4, %psr ! Turn on traps, disable interrupts
247 call " STRINGSYM(get_in_break_mode
) "
252 sethi %hi(0xff00), %l5
253 or %l5, %lo(0xff00), %l5
256 st %l4, [%sp + (24 + 72) * 4] ! DIA1, debug instr addr 1
259 st %l4, [%sp + (24 + 73) * 4] ! DIA2, debug instr addr 2
262 st %l4, [%sp + (24 + 74) * 4] ! DDA1, debug data addr 1
265 st %l4, [%sp + (24 + 75) * 4] ! DDA2, debug data addr 2
268 st %l4, [%sp + (24 + 76) * 4] ! DDV1, debug data val 1
271 st %l4, [%sp + (24 + 77) * 4] ! DDV2, debug data val 2
274 st %l4, [%sp + (24 + 78) * 4] ! DCR, debug control reg
277 st %l4, [%sp + (24 + 79) * 4] ! DSR, debug status reg
281 mov %l4, %psr ! Turn on traps, disable interrupts
285 call " STRINGSYM(handle_exception
) "
286 add %sp, 24 * 4, %o0 ! Pass address of registers
288 ! Reload all of the registers that aren't on the stack
290 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
291 ldd [%sp + (24 + 2) * 4], %g2
292 ldd [%sp + (24 + 4) * 4], %g4
293 ldd [%sp + (24 + 6) * 4], %g6
295 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
296 ldd [%sp + (24 + 10) * 4], %i2
297 ldd [%sp + (24 + 12) * 4], %i4
298 ldd [%sp + (24 + 14) * 4], %i6
300 sethi %hi(0xff00), %l2
301 or %l2, %lo(0xff00), %l2
302 ldd [%sp + (24 + 72) * 4], %l4 ! DIA1, debug instr addr 1
308 ldd [%sp + (24 + 74) * 4], %l4 ! DDA1, debug data addr 1
315 ldd [%sp + (24 + 76) * 4], %l4 ! DDV1, debug data value 1
322 ld [%sp + (24 + 78) * 4], %l4 ! DCR, debug control reg
323 ld [%sp + (24 + 79) * 4], %l5 ! DSR, debug control reg
334 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
335 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
337 restore ! Ensure that previous window is valid
338 save %g0, %g0, %g0 ! by causing a window_underflow trap
341 mov %l1, %psr ! Make sure that traps are disabled
343 sethi %hi(in_trap_handler), %l4
344 ld [%lo(in_trap_handler) + %l4], %l5
346 st %l5, [%lo(in_trap_handler) + %l4]
348 jmpl %l2, %g0 ! Restore old PC
349 rett %l3 ! Restore old nPC
352 /* Convert ch from a hex digit to an int */
358 if (ch
>= 'a' && ch
<= 'f')
360 if (ch
>= '0' && ch
<= '9')
362 if (ch
>= 'A' && ch
<= 'F')
367 /* scan for the sequence $<data>#<checksum> */
373 unsigned char checksum
;
374 unsigned char xmitcsum
;
381 /* wait around for the start character, ignore all other characters */
382 while ((ch
= (getDebugChar() & 0x7f)) != '$') ;
389 /* now, read until a # or end of buffer is found */
390 while (count
< BUFMAX
)
392 ch
= getDebugChar() & 0x7f;
395 checksum
= checksum
+ ch
;
407 xmitcsum
= hex(getDebugChar() & 0x7f) << 4;
408 xmitcsum
|= hex(getDebugChar() & 0x7f);
410 /* Humans shouldn't have to figure out checksums to type to it. */
414 if (checksum
!= xmitcsum
)
415 putDebugChar('-'); /* failed checksum */
418 putDebugChar('+'); /* successful transfer */
419 /* if a sequence char is present, reply the sequence ID */
420 if (buffer
[2] == ':')
422 putDebugChar(buffer
[0]);
423 putDebugChar(buffer
[1]);
424 /* remove sequence chars from buffer */
425 count
= strlen(buffer
);
426 for (i
=3; i
<= count
; i
++)
427 buffer
[i
-3] = buffer
[i
];
432 while (checksum
!= xmitcsum
);
435 /* send the packet in buffer. */
439 unsigned char *buffer
;
441 unsigned char checksum
;
445 /* $<packet info>#<checksum>. */
452 while (ch
= buffer
[count
])
454 if (! putDebugChar(ch
))
461 putDebugChar(hexchars
[checksum
>> 4]);
462 putDebugChar(hexchars
[checksum
& 0xf]);
465 while ((getDebugChar() & 0x7f) != '+');
468 static char remcomInBuffer
[BUFMAX
];
469 static char remcomOutBuffer
[BUFMAX
];
471 /* Indicate to caller of mem2hex or hex2mem that there has been an
473 static volatile int mem_err
= 0;
475 /* Convert the memory pointed to by mem into hex, placing result in buf.
476 * Return a pointer to the last char put in buf (null), in case of mem fault,
478 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
479 * a 0, else treat a fault like any other fault in the stub.
482 static unsigned char *
483 mem2hex(mem
, buf
, count
, may_fault
)
491 set_mem_fault_trap(may_fault
);
498 *buf
++ = hexchars
[ch
>> 4];
499 *buf
++ = hexchars
[ch
& 0xf];
504 set_mem_fault_trap(0);
509 /* convert the hex array pointed to by buf into binary to be placed in mem
510 * return a pointer to the character AFTER the last byte written */
513 hex2mem(buf
, mem
, count
, may_fault
)
522 set_mem_fault_trap(may_fault
);
524 for (i
=0; i
<count
; i
++)
526 ch
= hex(*buf
++) << 4;
533 set_mem_fault_trap(0);
538 /* This table contains the mapping between SPARC hardware trap types, and
539 signals, which are primarily what GDB understands. It also indicates
540 which hardware traps we need to commandeer when initializing the stub. */
542 static struct hard_trap_info
544 unsigned char tt
; /* Trap type code for SPARClite */
545 unsigned char signo
; /* Signal that we map this trap into */
546 } hard_trap_info
[] = {
547 {1, SIGSEGV
}, /* instruction access error */
548 {2, SIGILL
}, /* privileged instruction */
549 {3, SIGILL
}, /* illegal instruction */
550 {4, SIGEMT
}, /* fp disabled */
551 {36, SIGEMT
}, /* cp disabled */
552 {7, SIGBUS
}, /* mem address not aligned */
553 {9, SIGSEGV
}, /* data access exception */
554 {10, SIGEMT
}, /* tag overflow */
555 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
556 {255, SIGTRAP
}, /* hardware breakpoint */
557 {0, 0} /* Must be last */
560 /* Set up exception handlers for tracing and breakpoints */
565 struct hard_trap_info
*ht
;
567 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
568 exceptionHandler(ht
->tt
, trap_low
);
570 /* In case GDB is started before us, ack any packets (presumably
571 "$?#xx") sitting there. */
579 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
580 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
581 ! 0 would ever contain code that could mem fault. This routine will skip
582 ! past the faulting instruction after setting mem_err.
587 " STRINGSYM(fltr_set_mem_err
) ":
588 sethi %hi(" STRINGSYM(mem_err
) "), %l0
589 st %l1, [%l0 + %lo(" STRINGSYM(mem_err
) ")]
595 set_mem_fault_trap(enable
)
598 extern void fltr_set_mem_err();
602 exceptionHandler(9, fltr_set_mem_err
);
604 exceptionHandler(9, trap_low
);
611 " STRINGSYM(dummy_hw_breakpoint
) ":
619 set_hw_breakpoint_trap(enable
)
622 extern void dummy_hw_breakpoint();
625 exceptionHandler(255, dummy_hw_breakpoint
);
627 exceptionHandler(255, trap_low
);
633 set_hw_breakpoint_trap(1);
636 sethi %hi(0xff10), %l4
637 or %l4, %lo(0xff10), %l4
644 set_hw_breakpoint_trap(0);
647 /* Convert the SPARC hardware trap type code to a unix signal number. */
653 struct hard_trap_info
*ht
;
655 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
659 return SIGHUP
; /* default for things we don't know about */
663 * While we find nice hex chars, build an int.
664 * Return number of chars processed.
668 hexToInt(char **ptr
, int *intValue
)
677 hexValue
= hex(**ptr
);
681 *intValue
= (*intValue
<< 4) | hexValue
;
690 /* Replacement for outbyte that sends a packet to GDB containing
691 the character to be output. */
699 buf
[1] = hexchars
[(c
>> 4) & 0xf];
700 buf
[2] = hexchars
[c
% 16];
707 * This function does all command procesing for interfacing to gdb. It
708 * returns 1 if you should skip the instruction at the trap address, 0
714 handle_exception (registers
)
715 unsigned long *registers
;
717 int tt
; /* Trap type */
725 /* First, we must force all of the windows to be spilled out */
727 asm(" save %sp, -64, %sp
745 if (registers
[PC
] == (unsigned long)breakinst
)
747 registers
[PC
] = registers
[NPC
];
750 sp
= (unsigned long *)registers
[SP
];
752 dsr
= (unsigned long)registers
[DSR
];
759 tt
= (registers
[TBR
] >> 4) & 0xff;
762 /* reply to host that an exception has occurred */
763 sigval
= computeSignal(tt
);
764 ptr
= remcomOutBuffer
;
767 *ptr
++ = hexchars
[sigval
>> 4];
768 *ptr
++ = hexchars
[sigval
& 0xf];
770 *ptr
++ = hexchars
[PC
>> 4];
771 *ptr
++ = hexchars
[PC
& 0xf];
773 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
776 *ptr
++ = hexchars
[FP
>> 4];
777 *ptr
++ = hexchars
[FP
& 0xf];
779 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
782 *ptr
++ = hexchars
[SP
>> 4];
783 *ptr
++ = hexchars
[SP
& 0xf];
785 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
788 *ptr
++ = hexchars
[NPC
>> 4];
789 *ptr
++ = hexchars
[NPC
& 0xf];
791 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
794 *ptr
++ = hexchars
[O7
>> 4];
795 *ptr
++ = hexchars
[O7
& 0xf];
797 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
802 putpacket(remcomOutBuffer
);
804 __outbyte_hook
= outbyte_stub
;
808 remcomOutBuffer
[0] = 0;
810 getpacket(remcomInBuffer
);
811 switch (remcomInBuffer
[0])
814 remcomOutBuffer
[0] = 'S';
815 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
816 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
817 remcomOutBuffer
[3] = 0;
821 /* toggle debug flag */
824 case 'g': /* return the value of the CPU registers */
826 ptr
= remcomOutBuffer
;
827 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
828 ptr
= mem2hex(sp
+ 0, ptr
, 16 * 4, 0); /* L & I regs */
829 memset(ptr
, '0', 32 * 8); /* Floating point */
830 ptr
= mem2hex((char *)®isters
[Y
],
833 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
834 mem2hex((char *)®isters
[DIA1
], ptr
,
835 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
839 case 'G': /* set the value of the CPU registers - return OK */
841 unsigned long *newsp
, psr
;
843 psr
= registers
[PSR
];
845 ptr
= &remcomInBuffer
[1];
846 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
847 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 16 * 4, 0); /* L & I regs */
848 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
849 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
850 hex2mem(ptr
+ 72 * 4 * 2, (char *)®isters
[DIA1
],
851 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
853 /* See if the stack pointer has moved. If so, then copy the saved
854 locals and ins to the new location. This keeps the window
855 overflow and underflow routines happy. */
857 newsp
= (unsigned long *)registers
[SP
];
859 sp
= memcpy(newsp
, sp
, 16 * 4);
861 /* Don't allow CWP to be modified. */
863 if (psr
!= registers
[PSR
])
864 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
866 strcpy(remcomOutBuffer
,"OK");
870 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
871 /* Try to read %x,%x. */
873 ptr
= &remcomInBuffer
[1];
875 if (hexToInt(&ptr
, &addr
)
877 && hexToInt(&ptr
, &length
))
879 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
882 strcpy (remcomOutBuffer
, "E03");
885 strcpy(remcomOutBuffer
,"E01");
888 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
889 /* Try to read '%x,%x:'. */
891 ptr
= &remcomInBuffer
[1];
893 if (hexToInt(&ptr
, &addr
)
895 && hexToInt(&ptr
, &length
)
898 if (hex2mem(ptr
, (char *)addr
, length
, 1))
899 strcpy(remcomOutBuffer
, "OK");
901 strcpy(remcomOutBuffer
, "E03");
904 strcpy(remcomOutBuffer
, "E02");
907 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
908 /* try to read optional parameter, pc unchanged if no parm */
910 ptr
= &remcomInBuffer
[1];
911 if (hexToInt(&ptr
, &addr
))
913 registers
[PC
] = addr
;
914 registers
[NPC
] = addr
+ 4;
917 /* Need to flush the instruction cache here, as we may have deposited a
918 breakpoint, and the icache probably has no way of knowing that a data ref to
919 some location may have changed something that is in the instruction cache.
925 /* kill the program */
926 case 'k' : /* do nothing */
929 case 't': /* Test feature */
930 asm (" std %f30,[%sp]");
933 case 'r': /* Reset */
939 Disabled until we can unscrew
this properly
941 case 'b': /* bBB... Set baud rate to BB... */
944 extern void set_timer_3();
946 ptr
= &remcomInBuffer
[1];
947 if (!hexToInt(&ptr
, &baudrate
))
949 strcpy(remcomOutBuffer
,"B01");
953 /* Convert baud rate to uart clock divider */
966 strcpy(remcomOutBuffer
,"B02");
970 putpacket("OK"); /* Ack before changing speed */
971 set_timer_3(baudrate
); /* Set it */
977 /* reply to the request */
978 putpacket(remcomOutBuffer
);
982 /* This function will generate a breakpoint exception. It is used at the
983 beginning of a program to sync up with a debugger and can be used
984 otherwise as a quick means to stop program execution and "break" into
993 asm(" .globl " STRINGSYM(breakinst
) "
995 " STRINGSYM(breakinst
) ": ta 1