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 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
68 * All commands and responses are sent with a packet which includes a
69 * checksum. A packet consists of
71 * $<packet info>#<checksum>.
74 * <packet info> :: <characters representing the command or response>
75 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
77 * When a packet is received, it is first acknowledged with either '+' or '-'.
78 * '+' indicates a successful transfer. '-' indicates a failed transfer.
83 * $m0,10#2a +$00010203040506070809101112131415#42
85 ****************************************************************************/
90 /************************************************************************
92 * external low-level support routines
95 extern putDebugChar(); /* write a single character */
96 extern getDebugChar(); /* 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 static void set_mem_fault_trap();
107 static const char hexchars
[]="0123456789abcdef";
111 /* Number of bytes of registers. */
112 #define NUMREGBYTES (NUMREGS * 4)
113 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
114 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
115 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
116 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
118 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
119 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
120 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
121 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
122 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
};
124 /*************************** ASSEMBLY CODE MACROS *************************/
127 extern void trap_low();
130 .reserve trapstack, 1000 * 4, \"bss\", 8
141 ! This function is called when any SPARC trap (except window overflow or
142 ! underflow) occurs. It makes sure that the invalid register window is still
143 ! available before jumping into C code. It will also restore the world if you
144 ! return from handle_exception.
151 srl %l3, %l0, %l4 ! wim >> cwp
153 bne window_fine ! Branch if not in the invalid window
156 ! Handle window overflow
158 mov %g1, %l4 ! Save g1, we use it to hold the wim
159 srl %l3, 1, %g1 ! Rotate wim right
163 save %g0, %g0, %g0 ! Slip into next window
164 mov %g1, %wim ! Install the new wim
166 std %l0, [%sp + 0 * 4] ! save L & I registers
167 std %l2, [%sp + 2 * 4]
168 std %l4, [%sp + 4 * 4]
169 std %l6, [%sp + 6 * 4]
171 std %i0, [%sp + 8 * 4]
172 std %i2, [%sp + 10 * 4]
173 std %i4, [%sp + 12 * 4]
174 std %i6, [%sp + 14 * 4]
176 restore ! Go back to trap window.
177 mov %l4, %g1 ! Restore %g1
180 sethi %hi(in_trap_handler), %l4
181 ld [%lo(in_trap_handler) + %l4], %l5
186 set trapstack+1000*4, %sp ! Switch to trap stack
189 st %l5, [%lo(in_trap_handler) + %l4]
190 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
191 ! + hidden arg + arg spill
192 ! + doubleword alignment
193 ! + registers[72] local var
195 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
196 std %g2, [%sp + (24 + 2) * 4]
197 std %g4, [%sp + (24 + 4) * 4]
198 std %g6, [%sp + (24 + 6) * 4]
200 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
201 std %i2, [%sp + (24 + 10) * 4]
202 std %i4, [%sp + (24 + 12) * 4]
203 std %i6, [%sp + (24 + 14) * 4]
204 ! F0->F31 not implemented
207 st %l4, [%sp + (24 + 64) * 4] ! Y
208 st %l0, [%sp + (24 + 65) * 4] ! PSR
209 st %l3, [%sp + (24 + 66) * 4] ! WIM
210 st %l5, [%sp + (24 + 67) * 4] ! TBR
211 st %l1, [%sp + (24 + 68) * 4] ! PC
212 st %l2, [%sp + (24 + 69) * 4] ! NPC
214 ! CPSR and FPSR not impl
217 mov %l4, %psr ! Turn on traps, disable interrupts
219 call _handle_exception
220 add %sp, 24 * 4, %o0 ! Pass address of registers
222 ! Reload all of the registers that aren't on the stack
224 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
225 ldd [%sp + (24 + 2) * 4], %g2
226 ldd [%sp + (24 + 4) * 4], %g4
227 ldd [%sp + (24 + 6) * 4], %g6
229 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
230 ldd [%sp + (24 + 10) * 4], %i2
231 ldd [%sp + (24 + 12) * 4], %i4
232 ldd [%sp + (24 + 14) * 4], %i6
234 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
235 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
237 restore ! Ensure that previous window is valid
238 save %g0, %g0, %g0 ! by causing a window_underflow trap
241 mov %l1, %psr ! Make sure that traps are disabled
244 sethi %hi(in_trap_handler), %l4
245 ld [%lo(in_trap_handler) + %l4], %l5
247 st %l5, [%lo(in_trap_handler) + %l4]
249 jmpl %l2, %g0 ! Restore old PC
250 rett %l3 ! Restore old nPC
253 /* Convert ch from a hex digit to an int */
259 if (ch
>= 'a' && ch
<= 'f')
261 if (ch
>= '0' && ch
<= '9')
263 if (ch
>= 'A' && ch
<= 'F')
268 /* scan for the sequence $<data>#<checksum> */
274 unsigned char checksum
;
275 unsigned char xmitcsum
;
282 /* wait around for the start character, ignore all other characters */
283 while ((ch
= getDebugChar()) != '$') ;
290 /* now, read until a # or end of buffer is found */
291 while (count
< BUFMAX
)
296 checksum
= checksum
+ ch
;
308 xmitcsum
= hex(getDebugChar()) << 4;
309 xmitcsum
|= hex(getDebugChar());
311 /* Humans shouldn't have to figure out checksums to type to it. */
315 if (checksum
!= xmitcsum
)
316 putDebugChar('-'); /* failed checksum */
319 putDebugChar('+'); /* successful transfer */
320 /* if a sequence char is present, reply the sequence ID */
321 if (buffer
[2] == ':')
323 putDebugChar(buffer
[0]);
324 putDebugChar(buffer
[1]);
325 /* remove sequence chars from buffer */
326 count
= strlen(buffer
);
327 for (i
=3; i
<= count
; i
++)
328 buffer
[i
-3] = buffer
[i
];
333 while (checksum
!= xmitcsum
);
336 /* send the packet in buffer. */
340 unsigned char *buffer
;
342 unsigned char checksum
;
346 /* $<packet info>#<checksum>. */
353 while (ch
= buffer
[count
])
355 if (! putDebugChar(ch
))
362 putDebugChar(hexchars
[checksum
>> 4]);
363 putDebugChar(hexchars
[checksum
& 0xf]);
366 while (getDebugChar() != '+');
369 static char remcomInBuffer
[BUFMAX
];
370 static char remcomOutBuffer
[BUFMAX
];
372 /* Indicate to caller of mem2hex or hex2mem that there has been an
374 static volatile int mem_err
= 0;
376 /* Convert the memory pointed to by mem into hex, placing result in buf.
377 * Return a pointer to the last char put in buf (null), in case of mem fault,
379 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
380 * a 0, else treat a fault like any other fault in the stub.
383 static unsigned char *
384 mem2hex(mem
, buf
, count
, may_fault
)
392 set_mem_fault_trap(may_fault
);
399 *buf
++ = hexchars
[ch
>> 4];
400 *buf
++ = hexchars
[ch
& 0xf];
405 set_mem_fault_trap(0);
410 /* convert the hex array pointed to by buf into binary to be placed in mem
411 * return a pointer to the character AFTER the last byte written */
414 hex2mem(buf
, mem
, count
, may_fault
)
423 set_mem_fault_trap(may_fault
);
425 for (i
=0; i
<count
; i
++)
427 ch
= hex(*buf
++) << 4;
434 set_mem_fault_trap(0);
439 /* This table contains the mapping between SPARC hardware trap types, and
440 signals, which are primarily what GDB understands. It also indicates
441 which hardware traps we need to commandeer when initializing the stub. */
443 static struct hard_trap_info
445 unsigned char tt
; /* Trap type code for SPARClite */
446 unsigned char signo
; /* Signal that we map this trap into */
447 } hard_trap_info
[] = {
448 {1, SIGSEGV
}, /* instruction access error */
449 {2, SIGILL
}, /* privileged instruction */
450 {3, SIGILL
}, /* illegal instruction */
451 {4, SIGEMT
}, /* fp disabled */
452 {36, SIGEMT
}, /* cp disabled */
453 {7, SIGBUS
}, /* mem address not aligned */
454 {9, SIGSEGV
}, /* data access exception */
455 {10, SIGEMT
}, /* tag overflow */
456 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
457 {0, 0} /* Must be last */
460 /* Set up exception handlers for tracing and breakpoints */
465 struct hard_trap_info
*ht
;
467 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
468 exceptionHandler(ht
->tt
, trap_low
);
470 /* In case GDB is started before us, ack any packets (presumably
471 "$?#xx") sitting there. */
479 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
480 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
481 ! 0 would ever contain code that could mem fault. This routine will skip
482 ! past the faulting instruction after setting mem_err.
488 sethi %hi(_mem_err), %l0
489 st %l1, [%l0 + %lo(_mem_err)]
495 set_mem_fault_trap(enable
)
498 extern void fltr_set_mem_err();
502 exceptionHandler(9, fltr_set_mem_err
);
504 exceptionHandler(9, trap_low
);
507 /* Convert the SPARC hardware trap type code to a unix signal number. */
513 struct hard_trap_info
*ht
;
515 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
519 return SIGHUP
; /* default for things we don't know about */
523 * While we find nice hex chars, build an int.
524 * Return number of chars processed.
528 hexToInt(char **ptr
, int *intValue
)
537 hexValue
= hex(**ptr
);
541 *intValue
= (*intValue
<< 4) | hexValue
;
551 * This function does all command procesing for interfacing to gdb. It
552 * returns 1 if you should skip the instruction at the trap address, 0
556 extern void breakinst();
559 handle_exception (registers
)
560 unsigned long *registers
;
562 int tt
; /* Trap type */
569 /* First, we must force all of the windows to be spilled out */
571 asm(" save %sp, -64, %sp
589 if (registers
[PC
] == (unsigned long)breakinst
)
591 registers
[PC
] = registers
[NPC
];
595 sp
= (unsigned long *)registers
[SP
];
597 tt
= (registers
[TBR
] >> 4) & 0xff;
599 /* reply to host that an exception has occurred */
600 sigval
= computeSignal(tt
);
601 ptr
= remcomOutBuffer
;
604 *ptr
++ = hexchars
[sigval
>> 4];
605 *ptr
++ = hexchars
[sigval
& 0xf];
607 *ptr
++ = hexchars
[PC
>> 4];
608 *ptr
++ = hexchars
[PC
& 0xf];
610 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
613 *ptr
++ = hexchars
[FP
>> 4];
614 *ptr
++ = hexchars
[FP
& 0xf];
616 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
619 *ptr
++ = hexchars
[SP
>> 4];
620 *ptr
++ = hexchars
[SP
& 0xf];
622 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
625 *ptr
++ = hexchars
[NPC
>> 4];
626 *ptr
++ = hexchars
[NPC
& 0xf];
628 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
631 *ptr
++ = hexchars
[O7
>> 4];
632 *ptr
++ = hexchars
[O7
& 0xf];
634 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
639 putpacket(remcomOutBuffer
);
643 remcomOutBuffer
[0] = 0;
645 getpacket(remcomInBuffer
);
646 switch (remcomInBuffer
[0])
649 remcomOutBuffer
[0] = 'S';
650 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
651 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
652 remcomOutBuffer
[3] = 0;
656 /* toggle debug flag */
659 case 'g': /* return the value of the CPU registers */
661 ptr
= remcomOutBuffer
;
662 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
663 ptr
= mem2hex(sp
+ 0, ptr
, 16 * 4, 0); /* L & I regs */
664 memset(ptr
, '0', 32 * 8); /* Floating point */
665 mem2hex((char *)®isters
[Y
],
668 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
672 case 'G': /* set the value of the CPU registers - return OK */
674 unsigned long *newsp
, psr
;
676 psr
= registers
[PSR
];
678 ptr
= &remcomInBuffer
[1];
679 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
680 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 16 * 4, 0); /* L & I regs */
681 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
682 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
684 /* See if the stack pointer has moved. If so, then copy the saved
685 locals and ins to the new location. This keeps the window
686 overflow and underflow routines happy. */
688 newsp
= (unsigned long *)registers
[SP
];
690 sp
= memcpy(newsp
, sp
, 16 * 4);
692 /* Don't allow CWP to be modified. */
694 if (psr
!= registers
[PSR
])
695 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
697 strcpy(remcomOutBuffer
,"OK");
701 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
702 /* Try to read %x,%x. */
704 ptr
= &remcomInBuffer
[1];
706 if (hexToInt(&ptr
, &addr
)
708 && hexToInt(&ptr
, &length
))
710 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
713 strcpy (remcomOutBuffer
, "E03");
716 strcpy(remcomOutBuffer
,"E01");
719 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
720 /* Try to read '%x,%x:'. */
722 ptr
= &remcomInBuffer
[1];
724 if (hexToInt(&ptr
, &addr
)
726 && hexToInt(&ptr
, &length
)
729 if (hex2mem(ptr
, (char *)addr
, length
, 1))
730 strcpy(remcomOutBuffer
, "OK");
732 strcpy(remcomOutBuffer
, "E03");
735 strcpy(remcomOutBuffer
, "E02");
738 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
739 /* try to read optional parameter, pc unchanged if no parm */
741 ptr
= &remcomInBuffer
[1];
742 if (hexToInt(&ptr
, &addr
))
744 registers
[PC
] = addr
;
745 registers
[NPC
] = addr
+ 4;
748 /* Need to flush the instruction cache here, as we may have deposited a
749 breakpoint, and the icache probably has no way of knowing that a data ref to
750 some location may have changed something that is in the instruction cache.
756 /* kill the program */
757 case 'k' : /* do nothing */
760 case 't': /* Test feature */
761 asm (" std %f31,[%sp]");
764 case 'r': /* Reset */
770 Disabled until we can unscrew
this properly
772 case 'b': /* bBB... Set baud rate to BB... */
775 extern void set_timer_3();
777 ptr
= &remcomInBuffer
[1];
778 if (!hexToInt(&ptr
, &baudrate
))
780 strcpy(remcomOutBuffer
,"B01");
784 /* Convert baud rate to uart clock divider */
797 strcpy(remcomOutBuffer
,"B02");
801 putpacket("OK"); /* Ack before changing speed */
802 set_timer_3(baudrate
); /* Set it */
808 /* reply to the request */
809 putpacket(remcomOutBuffer
);
813 /* This function will generate a breakpoint exception. It is used at the
814 beginning of a program to sync up with a debugger and can be used
815 otherwise as a quick means to stop program execution and "break" into
824 asm(" .globl _breakinst