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 * All commands and responses are sent with a packet which includes a
68 * checksum. A packet consists of
70 * $<packet info>#<checksum>.
73 * <packet info> :: <characters representing the command or response>
74 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
76 * When a packet is received, it is first acknowledged with either '+' or '-'.
77 * '+' indicates a successful transfer. '-' indicates a failed transfer.
82 * $m0,10#2a +$00010203040506070809101112131415#42
84 ****************************************************************************/
88 #include <sparclite.h>
90 /************************************************************************
92 * external low-level support routines
95 extern void putDebugChar (int c
); /* write a single character */
96 extern int getDebugChar (void); /* read and return a single char */
98 /************************************************************************/
99 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
100 /* at least NUMREGBYTES*2 are needed for register packets */
103 static int initialized
= 0; /* !0 means we've been initialized */
105 extern void breakinst ();
106 static void set_mem_fault_trap (int enable
);
107 static void get_in_break_mode (void);
109 static const char hexchars
[]="0123456789abcdef";
113 /* Number of bytes of registers. */
114 #define NUMREGBYTES (NUMREGS * 4)
115 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
116 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
117 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
118 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
120 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
121 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
122 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
123 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
124 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
,
125 DIA1
, DIA2
, DDA1
, DDA2
, DDV1
, DDV2
, DCR
, DSR
};
127 /*************************** ASSEMBLY CODE MACROS *************************/
130 extern void trap_low();
132 /* Create private copies of common functions used by the stub. This prevents
133 nasty interactions between app code and the stub (for instance if user steps
134 into strlen, etc..) */
137 strcpy (char *dst
, const char *src
)
141 while ((*dst
++ = *src
++) != '\000');
147 memcpy (void *vdst
, const void *vsrc
, int n
)
150 const char *src
= vsrc
;
160 .reserve trapstack, 1000 * 4, \"bss\", 8
171 ! This function is called when any SPARC trap (except window overflow or
172 ! underflow) occurs. It makes sure that the invalid register window is still
173 ! available before jumping into C code. It will also restore the world if you
174 ! return from handle_exception.
176 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
177 ! Register usage throughout the routine is as follows:
183 ! l4 - scratch and y reg
184 ! l5 - scratch and tbr
193 srl %l3, %l0, %l4 ! wim >> cwp
195 bne window_fine ! Branch if not in the invalid window
198 ! Handle window overflow
200 mov %g1, %l4 ! Save g1, we use it to hold the wim
201 srl %l3, 1, %g1 ! Rotate wim right
203 bg good_wim ! Branch if new wim is non-zero
206 ! At this point, we need to bring a 1 into the high order bit of the wim.
207 ! Since we don't want to make any assumptions about the number of register
208 ! windows, we figure it out dynamically so as to setup the wim correctly.
210 not %g1 ! Fill g1 with ones
211 mov %g1, %wim ! Fill the wim with ones
215 mov %wim, %g1 ! Read back the wim
216 inc %g1 ! Now g1 has 1 just to left of wim
217 srl %g1, 1, %g1 ! Now put 1 at top of wim
218 mov %g0, %wim ! Clear wim so that subsequent save
224 save %g0, %g0, %g0 ! Slip into next window
225 mov %g1, %wim ! Install the new wim
227 std %l0, [%sp + 0 * 4] ! save L & I registers
228 std %l2, [%sp + 2 * 4]
229 std %l4, [%sp + 4 * 4]
230 std %l6, [%sp + 6 * 4]
232 std %i0, [%sp + 8 * 4]
233 std %i2, [%sp + 10 * 4]
234 std %i4, [%sp + 12 * 4]
235 std %i6, [%sp + 14 * 4]
237 restore ! Go back to trap window.
238 mov %l4, %g1 ! Restore %g1
241 sethi %hi(in_trap_handler), %l4
242 ld [%lo(in_trap_handler) + %l4], %l5
247 set trapstack+1000*4, %sp ! Switch to trap stack
250 st %l5, [%lo(in_trap_handler) + %l4]
251 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
252 ! + hidden arg + arg spill
253 ! + doubleword alignment
254 ! + registers[72] local var
256 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
257 std %g2, [%sp + (24 + 2) * 4]
258 std %g4, [%sp + (24 + 4) * 4]
259 std %g6, [%sp + (24 + 6) * 4]
261 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
262 std %i2, [%sp + (24 + 10) * 4]
263 std %i4, [%sp + (24 + 12) * 4]
264 std %i6, [%sp + (24 + 14) * 4]
268 st %l4, [%sp + (24 + 64) * 4] ! Y
269 st %l0, [%sp + (24 + 65) * 4] ! PSR
270 st %l3, [%sp + (24 + 66) * 4] ! WIM
271 st %l5, [%sp + (24 + 67) * 4] ! TBR
272 st %l1, [%sp + (24 + 68) * 4] ! PC
273 st %l2, [%sp + (24 + 69) * 4] ! NPC
276 mov %l4, %psr ! Turn on traps, disable interrupts
279 btst %l1, %l0 ! FP enabled?
283 ! Must save fsr first, to flush the FQ. This may cause a deferred fp trap, so
284 ! traps must be enabled to allow the trap handler to clean things up.
286 st %fsr, [%sp + (24 + 70) * 4]
288 std %f0, [%sp + (24 + 32) * 4]
289 std %f2, [%sp + (24 + 34) * 4]
290 std %f4, [%sp + (24 + 36) * 4]
291 std %f6, [%sp + (24 + 38) * 4]
292 std %f8, [%sp + (24 + 40) * 4]
293 std %f10, [%sp + (24 + 42) * 4]
294 std %f12, [%sp + (24 + 44) * 4]
295 std %f14, [%sp + (24 + 46) * 4]
296 std %f16, [%sp + (24 + 48) * 4]
297 std %f18, [%sp + (24 + 50) * 4]
298 std %f20, [%sp + (24 + 52) * 4]
299 std %f22, [%sp + (24 + 54) * 4]
300 std %f24, [%sp + (24 + 56) * 4]
301 std %f26, [%sp + (24 + 58) * 4]
302 std %f28, [%sp + (24 + 60) * 4]
303 std %f30, [%sp + (24 + 62) * 4]
306 call _handle_exception
307 add %sp, 24 * 4, %o0 ! Pass address of registers
309 ! Reload all of the registers that aren't on the stack
311 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
312 ldd [%sp + (24 + 2) * 4], %g2
313 ldd [%sp + (24 + 4) * 4], %g4
314 ldd [%sp + (24 + 6) * 4], %g6
316 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
317 ldd [%sp + (24 + 10) * 4], %i2
318 ldd [%sp + (24 + 12) * 4], %i4
319 ldd [%sp + (24 + 14) * 4], %i6
322 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
323 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
326 btst %l5, %l1 ! FP enabled?
330 ldd [%sp + (24 + 32) * 4], %f0
331 ldd [%sp + (24 + 34) * 4], %f2
332 ldd [%sp + (24 + 36) * 4], %f4
333 ldd [%sp + (24 + 38) * 4], %f6
334 ldd [%sp + (24 + 40) * 4], %f8
335 ldd [%sp + (24 + 42) * 4], %f10
336 ldd [%sp + (24 + 44) * 4], %f12
337 ldd [%sp + (24 + 46) * 4], %f14
338 ldd [%sp + (24 + 48) * 4], %f16
339 ldd [%sp + (24 + 50) * 4], %f18
340 ldd [%sp + (24 + 52) * 4], %f20
341 ldd [%sp + (24 + 54) * 4], %f22
342 ldd [%sp + (24 + 56) * 4], %f24
343 ldd [%sp + (24 + 58) * 4], %f26
344 ldd [%sp + (24 + 60) * 4], %f28
345 ldd [%sp + (24 + 62) * 4], %f30
347 ld [%sp + (24 + 70) * 4], %fsr
350 restore ! Ensure that previous window is valid
351 save %g0, %g0, %g0 ! by causing a window_underflow trap
354 mov %l1, %psr ! Make sure that traps are disabled
356 sethi %hi(in_trap_handler), %l4
357 ld [%lo(in_trap_handler) + %l4], %l5
359 st %l5, [%lo(in_trap_handler) + %l4]
361 jmpl %l2, %g0 ! Restore old PC
362 rett %l3 ! Restore old nPC
365 /* Convert ch from a hex digit to an int */
371 if (ch
>= 'a' && ch
<= 'f')
373 if (ch
>= '0' && ch
<= '9')
375 if (ch
>= 'A' && ch
<= 'F')
380 static char remcomInBuffer
[BUFMAX
];
381 static char remcomOutBuffer
[BUFMAX
];
383 /* scan for the sequence $<data>#<checksum> */
388 unsigned char *buffer
= &remcomInBuffer
[0];
389 unsigned char checksum
;
390 unsigned char xmitcsum
;
396 /* wait around for the start character, ignore all other characters */
397 while ((ch
= getDebugChar ()) != '$')
405 /* now, read until a # or end of buffer is found */
406 while (count
< BUFMAX
)
408 ch
= getDebugChar ();
413 checksum
= checksum
+ ch
;
421 ch
= getDebugChar ();
422 xmitcsum
= hex (ch
) << 4;
423 ch
= getDebugChar ();
424 xmitcsum
+= hex (ch
);
426 if (checksum
!= xmitcsum
)
428 putDebugChar ('-'); /* failed checksum */
432 putDebugChar ('+'); /* successful transfer */
434 /* if a sequence char is present, reply the sequence ID */
435 if (buffer
[2] == ':')
437 putDebugChar (buffer
[0]);
438 putDebugChar (buffer
[1]);
449 /* send the packet in buffer. */
453 unsigned char *buffer
;
455 unsigned char checksum
;
459 /* $<packet info>#<checksum>. */
466 while (ch
= buffer
[count
])
474 putDebugChar(hexchars
[checksum
>> 4]);
475 putDebugChar(hexchars
[checksum
& 0xf]);
478 while (getDebugChar() != '+');
481 /* Indicate to caller of mem2hex or hex2mem that there has been an
483 static volatile int mem_err
= 0;
485 /* Convert the memory pointed to by mem into hex, placing result in buf.
486 * Return a pointer to the last char put in buf (null), in case of mem fault,
488 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
489 * a 0, else treat a fault like any other fault in the stub.
492 static unsigned char *
493 mem2hex(mem
, buf
, count
, may_fault
)
501 set_mem_fault_trap(may_fault
);
508 *buf
++ = hexchars
[ch
>> 4];
509 *buf
++ = hexchars
[ch
& 0xf];
514 set_mem_fault_trap(0);
519 /* convert the hex array pointed to by buf into binary to be placed in mem
520 * return a pointer to the character AFTER the last byte written */
523 hex2mem(buf
, mem
, count
, may_fault
)
532 set_mem_fault_trap(may_fault
);
534 for (i
=0; i
<count
; i
++)
536 ch
= hex(*buf
++) << 4;
543 set_mem_fault_trap(0);
548 /* This table contains the mapping between SPARC hardware trap types, and
549 signals, which are primarily what GDB understands. It also indicates
550 which hardware traps we need to commandeer when initializing the stub. */
552 static struct hard_trap_info
554 unsigned char tt
; /* Trap type code for SPARClite */
555 unsigned char signo
; /* Signal that we map this trap into */
556 } hard_trap_info
[] = {
557 {0x01, SIGSEGV
}, /* instruction access error */
558 {0x02, SIGILL
}, /* privileged instruction */
559 {0x03, SIGILL
}, /* illegal instruction */
560 {0x04, SIGEMT
}, /* fp disabled */
561 {0x07, SIGBUS
}, /* mem address not aligned */
562 {0x09, SIGSEGV
}, /* data access exception */
563 {0x0a, SIGEMT
}, /* tag overflow */
564 {0x20, SIGBUS
}, /* r register access error */
565 {0x21, SIGBUS
}, /* instruction access error */
566 {0x24, SIGEMT
}, /* cp disabled */
567 {0x29, SIGBUS
}, /* data access error */
568 {0x2a, SIGFPE
}, /* divide by zero */
569 {0x2b, SIGBUS
}, /* data store error */
570 {0x80+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
571 {0xff, SIGTRAP
}, /* hardware breakpoint */
572 {0, 0} /* Must be last */
575 /* Set up exception handlers for tracing and breakpoints */
580 struct hard_trap_info
*ht
;
582 /* Only setup fp traps if the FP is disabled. */
584 for (ht
= hard_trap_info
;
585 ht
->tt
!= 0 && ht
->signo
!= 0;
587 if (ht
->tt
!= 4 || ! (read_psr () & 0x1000))
588 exceptionHandler(ht
->tt
, trap_low
);
594 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
595 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
596 ! 0 would ever contain code that could mem fault. This routine will skip
597 ! past the faulting instruction after setting mem_err.
603 sethi %hi(_mem_err), %l0
604 st %l1, [%l0 + %lo(_mem_err)]
610 set_mem_fault_trap(enable
)
613 extern void fltr_set_mem_err();
617 exceptionHandler(9, fltr_set_mem_err
);
619 exceptionHandler(9, trap_low
);
626 _dummy_hw_breakpoint:
636 extern void dummy_hw_breakpoint();
638 exceptionHandler (255, dummy_hw_breakpoint
);
642 exceptionHandler (255, trap_low
);
645 /* Convert the SPARC hardware trap type code to a unix signal number. */
651 struct hard_trap_info
*ht
;
653 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
657 return SIGHUP
; /* default for things we don't know about */
661 * While we find nice hex chars, build an int.
662 * Return number of chars processed.
666 hexToInt(char **ptr
, int *intValue
)
675 hexValue
= hex(**ptr
);
679 *intValue
= (*intValue
<< 4) | hexValue
;
689 * This function does all command procesing for interfacing to gdb. It
690 * returns 1 if you should skip the instruction at the trap address, 0
695 handle_exception (registers
)
696 unsigned long *registers
;
698 int tt
; /* Trap type */
706 /* First, we must force all of the windows to be spilled out */
708 asm(" save %sp, -64, %sp
726 get_in_break_mode (); /* Enable DSU register writes */
728 registers
[DIA1
] = read_asi (1, 0xff00);
729 registers
[DIA2
] = read_asi (1, 0xff04);
730 registers
[DDA1
] = read_asi (1, 0xff08);
731 registers
[DDA2
] = read_asi (1, 0xff0c);
732 registers
[DDV1
] = read_asi (1, 0xff10);
733 registers
[DDV2
] = read_asi (1, 0xff14);
734 registers
[DCR
] = read_asi (1, 0xff18);
735 registers
[DSR
] = read_asi (1, 0xff1c);
737 if (registers
[PC
] == (unsigned long)breakinst
)
739 registers
[PC
] = registers
[NPC
];
742 sp
= (unsigned long *)registers
[SP
];
744 dsr
= (unsigned long)registers
[DSR
];
748 tt
= (registers
[TBR
] >> 4) & 0xff;
750 /* reply to host that an exception has occurred */
751 sigval
= computeSignal(tt
);
752 ptr
= remcomOutBuffer
;
755 *ptr
++ = hexchars
[sigval
>> 4];
756 *ptr
++ = hexchars
[sigval
& 0xf];
758 *ptr
++ = hexchars
[PC
>> 4];
759 *ptr
++ = hexchars
[PC
& 0xf];
761 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
764 *ptr
++ = hexchars
[FP
>> 4];
765 *ptr
++ = hexchars
[FP
& 0xf];
767 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
770 *ptr
++ = hexchars
[SP
>> 4];
771 *ptr
++ = hexchars
[SP
& 0xf];
773 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
776 *ptr
++ = hexchars
[NPC
>> 4];
777 *ptr
++ = hexchars
[NPC
& 0xf];
779 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
782 *ptr
++ = hexchars
[O7
>> 4];
783 *ptr
++ = hexchars
[O7
& 0xf];
785 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
790 putpacket(remcomOutBuffer
);
794 remcomOutBuffer
[0] = 0;
800 remcomOutBuffer
[0] = 'S';
801 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
802 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
803 remcomOutBuffer
[3] = 0;
807 /* toggle debug flag */
810 case 'g': /* return the value of the CPU registers */
811 memcpy (®isters
[L0
], sp
, 16 * 4); /* Copy L & I regs from stack */
812 mem2hex ((char *)registers
, remcomOutBuffer
, NUMREGBYTES
, 0);
815 case 'G': /* Set the value of all registers */
816 case 'P': /* Set the value of one register */
818 unsigned long *newsp
, psr
;
820 psr
= registers
[PSR
];
826 if (hexToInt (&ptr
, ®no
)
828 if (regno
>= L0
&& regno
<= I7
)
829 hex2mem (ptr
, sp
+ regno
- L0
, 4, 0);
831 hex2mem (ptr
, (char *)®isters
[regno
], 4, 0);
834 strcpy (remcomOutBuffer
, "P01");
840 hex2mem (ptr
, (char *)registers
, NUMREGBYTES
, 0);
841 memcpy (sp
, ®isters
[L0
], 16 * 4); /* Copy L & I regs to stack */
844 /* See if the stack pointer has moved. If so, then copy the saved
845 locals and ins to the new location. This keeps the window
846 overflow and underflow routines happy. */
848 newsp
= (unsigned long *)registers
[SP
];
850 sp
= memcpy(newsp
, sp
, 16 * 4);
852 /* Don't allow CWP to be modified. */
854 if (psr
!= registers
[PSR
])
855 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
857 strcpy(remcomOutBuffer
,"OK");
861 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
862 /* Try to read %x,%x. */
864 if (hexToInt(&ptr
, &addr
)
866 && hexToInt(&ptr
, &length
))
868 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
871 strcpy (remcomOutBuffer
, "E03");
874 strcpy(remcomOutBuffer
,"E01");
877 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
878 /* Try to read '%x,%x:'. */
880 if (hexToInt(&ptr
, &addr
)
882 && hexToInt(&ptr
, &length
)
885 if (hex2mem(ptr
, (char *)addr
, length
, 1))
886 strcpy(remcomOutBuffer
, "OK");
888 strcpy(remcomOutBuffer
, "E03");
891 strcpy(remcomOutBuffer
, "E02");
894 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
895 /* try to read optional parameter, pc unchanged if no parm */
896 if (hexToInt(&ptr
, &addr
))
898 registers
[PC
] = addr
;
899 registers
[NPC
] = addr
+ 4;
902 /* Need to flush the instruction cache here, as we may have deposited a
903 breakpoint, and the icache probably has no way of knowing that a data ref to
904 some location may have changed something that is in the instruction cache.
909 if (!(registers
[DSR
] & 0x1) /* DSU enabled? */
910 && !(registers
[DCR
] & 0x200)) /* Are we in break state? */
911 { /* Yes, set the DSU regs */
912 write_asi (1, 0xff00, registers
[DIA1
]);
913 write_asi (1, 0xff04, registers
[DIA2
]);
914 write_asi (1, 0xff08, registers
[DDA1
]);
915 write_asi (1, 0xff0c, registers
[DDA2
]);
916 write_asi (1, 0xff10, registers
[DDV1
]);
917 write_asi (1, 0xff14, registers
[DDV2
]);
918 write_asi (1, 0xff1c, registers
[DSR
]);
919 write_asi (1, 0xff18, registers
[DCR
] | 0x200); /* Clear break */
924 /* kill the program */
925 case 'k' : /* do nothing */
928 case 't': /* Test feature */
929 asm (" std %f30,[%sp]");
932 case 'r': /* Reset */
938 /* reply to the request */
939 putpacket(remcomOutBuffer
);
943 /* This function will generate a breakpoint exception. It is used at the
944 beginning of a program to sync up with a debugger and can be used
945 otherwise as a quick means to stop program execution and "break" into
954 asm(" .globl _breakinst
This page took 0.062909 seconds and 4 git commands to generate.