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 * To enable debugger support, two things need to happen. One, a
35 * call to set_debug_traps() is necessary in order to allow any breakpoints
36 * or error conditions to be properly intercepted and reported to gdb.
37 * Two, a breakpoint needs to be generated to begin communication. This
38 * is most easily accomplished by a call to breakpoint(). Breakpoint()
39 * simulates a breakpoint by executing a trap #1.
43 * The following gdb commands are supported:
45 * command function Return value
47 * g return the value of the CPU registers hex data or ENN
48 * G set the value of the CPU registers OK or ENN
50 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
51 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
53 * c Resume at current address SNN ( signal NN)
54 * cAA..AA Continue at address AA..AA SNN
56 * s Step one instruction SNN
57 * sAA..AA Step one instruction from AA..AA SNN
61 * ? What was the last sigval ? SNN (signal NN)
63 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
66 * All commands and responses are sent with a packet which includes a
67 * checksum. A packet consists of
69 * $<packet info>#<checksum>.
72 * <packet info> :: <characters representing the command or response>
73 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
75 * When a packet is received, it is first acknowledged with either '+' or '-'.
76 * '+' indicates a successful transfer. '-' indicates a failed transfer.
81 * $m0,10#2a +$00010203040506070809101112131415#42
83 ****************************************************************************/
89 /************************************************************************
91 * external low-level support routines
94 extern putDebugChar(); /* write a single character */
95 extern getDebugChar(); /* read and return a single char */
97 /************************************************************************/
98 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
99 /* at least NUMREGBYTES*2 are needed for register packets */
102 static int initialized
= 0; /* !0 means we've been initialized */
104 static void set_mem_fault_trap();
106 static const char hexchars
[]="0123456789abcdef";
110 /* Number of bytes of registers. */
111 #define NUMREGBYTES (NUMREGS * 4)
112 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
113 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
114 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
115 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
117 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
118 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
119 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
120 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
121 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
};
123 /*************************** ASSEMBLY CODE MACROS *************************/
126 extern void trap_low();
129 .reserve trapstack, 1000 * 4, \"bss\", 8
140 ! This function is called when any SPARC trap (except window overflow or
141 ! underflow) occurs. It makes sure that the invalid register window is still
142 ! available before jumping into C code. It will also restore the world if you
143 ! return from handle_exception.
150 srl %l3, %l0, %l4 ! wim >> cwp
152 bne window_fine ! Branch if not in the invalid window
155 ! Handle window overflow
157 mov %g1, %l4 ! Save g1, we use it to hold the wim
158 srl %l3, 1, %g1 ! Rotate wim right
162 save %g0, %g0, %g0 ! Slip into next window
163 mov %g1, %wim ! Install the new wim
165 std %l0, [%sp + 0 * 4] ! save L & I registers
166 std %l2, [%sp + 2 * 4]
167 std %l4, [%sp + 4 * 4]
168 std %l6, [%sp + 6 * 4]
170 std %i0, [%sp + 8 * 4]
171 std %i2, [%sp + 10 * 4]
172 std %i4, [%sp + 12 * 4]
173 std %i6, [%sp + 14 * 4]
175 restore ! Go back to trap window.
176 mov %l4, %g1 ! Restore %g1
179 sethi %hi(in_trap_handler), %l4
180 ld [%lo(in_trap_handler) + %l4], %l5
185 set trapstack+1000*4, %sp ! Switch to trap stack
188 st %l5, [%lo(in_trap_handler) + %l4]
189 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
190 ! + hidden arg + arg spill
191 ! + doubleword alignment
192 ! + registers[72] local var
194 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
195 std %g2, [%sp + (24 + 2) * 4]
196 std %g4, [%sp + (24 + 4) * 4]
197 std %g6, [%sp + (24 + 6) * 4]
199 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
200 std %i2, [%sp + (24 + 10) * 4]
201 std %i4, [%sp + (24 + 12) * 4]
202 std %i6, [%sp + (24 + 14) * 4]
203 ! F0->F31 not implemented
206 st %l4, [%sp + (24 + 64) * 4] ! Y
207 st %l0, [%sp + (24 + 65) * 4] ! PSR
208 st %l3, [%sp + (24 + 66) * 4] ! WIM
209 st %l5, [%sp + (24 + 67) * 4] ! TBR
210 st %l1, [%sp + (24 + 68) * 4] ! PC
211 st %l2, [%sp + (24 + 69) * 4] ! NPC
213 ! CPSR and FPSR not impl
216 mov %l4, %psr ! Turn on traps, disable interrupts
218 call _handle_exception
219 add %sp, 24 * 4, %o0 ! Pass address of registers
221 restore ! Ensure that previous window is valid
222 save %g0, %g0, %g0 ! by causing a window_underflow trap
224 ! Reload all of the registers that aren't on the stack
226 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
227 ldd [%sp + (24 + 2) * 4], %g2
228 ldd [%sp + (24 + 4) * 4], %g4
229 ldd [%sp + (24 + 6) * 4], %g6
231 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
232 ldd [%sp + (24 + 10) * 4], %i2
233 ldd [%sp + (24 + 12) * 4], %i4
234 ldd [%sp + (24 + 14) * 4], %i6
236 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
237 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
239 mov %l1, %psr ! Make sure that traps are disabled
242 sethi %hi(in_trap_handler), %l4
243 ld [%lo(in_trap_handler) + %l4], %l5
245 st %l5, [%lo(in_trap_handler) + %l4]
247 jmpl %l2, %g0 ! Restore old PC
248 rett %l3 ! Restore old nPC
251 /* Convert ch from a hex digit to an int */
257 if (ch
>= 'a' && ch
<= 'f')
259 if (ch
>= '0' && ch
<= '9')
261 if (ch
>= 'A' && ch
<= 'F')
266 /* scan for the sequence $<data>#<checksum> */
272 unsigned char checksum
;
273 unsigned char xmitcsum
;
280 /* wait around for the start character, ignore all other characters */
281 while ((ch
= getDebugChar()) != '$') ;
288 /* now, read until a # or end of buffer is found */
289 while (count
< BUFMAX
)
294 checksum
= checksum
+ ch
;
306 xmitcsum
= hex(getDebugChar()) << 4;
307 xmitcsum
|= hex(getDebugChar());
309 /* Humans shouldn't have to figure out checksums to type to it. */
313 if (checksum
!= xmitcsum
)
314 putDebugChar('-'); /* failed checksum */
317 putDebugChar('+'); /* successful transfer */
318 /* if a sequence char is present, reply the sequence ID */
319 if (buffer
[2] == ':')
321 putDebugChar(buffer
[0]);
322 putDebugChar(buffer
[1]);
323 /* remove sequence chars from buffer */
324 count
= strlen(buffer
);
325 for (i
=3; i
<= count
; i
++)
326 buffer
[i
-3] = buffer
[i
];
331 while (checksum
!= xmitcsum
);
334 /* send the packet in buffer. */
338 unsigned char *buffer
;
340 unsigned char checksum
;
344 /* $<packet info>#<checksum>. */
351 while (ch
= buffer
[count
])
353 if (! putDebugChar(ch
))
360 putDebugChar(hexchars
[checksum
>> 4]);
361 putDebugChar(hexchars
[checksum
& 0xf]);
364 while (getDebugChar() != '+');
367 static char remcomInBuffer
[BUFMAX
];
368 static char remcomOutBuffer
[BUFMAX
];
370 /* Indicate to caller of mem2hex or hex2mem that there has been an
372 static volatile int mem_err
= 0;
374 /* Convert the memory pointed to by mem into hex, placing result in buf.
375 * Return a pointer to the last char put in buf (null), in case of mem fault,
377 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
378 * a 0, else treat a fault like any other fault in the stub.
381 static unsigned char *
382 mem2hex(mem
, buf
, count
, may_fault
)
390 set_mem_fault_trap(may_fault
);
397 *buf
++ = hexchars
[ch
>> 4];
398 *buf
++ = hexchars
[ch
& 0xf];
403 set_mem_fault_trap(0);
408 /* convert the hex array pointed to by buf into binary to be placed in mem
409 * return a pointer to the character AFTER the last byte written */
412 hex2mem(buf
, mem
, count
, may_fault
)
421 set_mem_fault_trap(may_fault
);
423 for (i
=0; i
<count
; i
++)
425 ch
= hex(*buf
++) << 4;
432 set_mem_fault_trap(0);
437 /* This table contains the mapping between SPARC hardware trap types, and
438 signals, which are primarily what GDB understands. It also indicates
439 which hardware traps we need to commandeer when initializing the stub. */
441 static struct hard_trap_info
443 unsigned char tt
; /* Trap type code for SPARClite */
444 unsigned char signo
; /* Signal that we map this trap into */
445 } hard_trap_info
[] = {
446 {1, SIGSEGV
}, /* instruction access error */
447 {2, SIGILL
}, /* privileged instruction */
448 {3, SIGILL
}, /* illegal instruction */
449 {4, SIGEMT
}, /* fp disabled */
450 {36, SIGEMT
}, /* cp disabled */
451 {7, SIGBUS
}, /* mem address not aligned */
452 {9, SIGSEGV
}, /* data access exception */
453 {10, SIGEMT
}, /* tag overflow */
454 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
455 {0, 0} /* Must be last */
458 /* Set up exception handlers for tracing and breakpoints */
463 struct hard_trap_info
*ht
;
465 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
466 exceptionHandler(ht
->tt
, trap_low
);
468 /* In case GDB is started before us, ack any packets (presumably
469 "$?#xx") sitting there. */
477 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
478 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
479 ! 0 would ever contain code that could mem fault. This routine will skip
480 ! past the faulting instruction after setting mem_err.
486 sethi %hi(_mem_err), %l0
487 st %l1, [%l0 + %lo(_mem_err)]
493 set_mem_fault_trap(enable
)
496 extern void fltr_set_mem_err();
500 exceptionHandler(9, fltr_set_mem_err
);
502 exceptionHandler(9, trap_low
);
505 /* Convert the SPARC hardware trap type code to a unix signal number. */
511 struct hard_trap_info
*ht
;
513 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
517 return SIGHUP
; /* default for things we don't know about */
521 * While we find nice hex chars, build an int.
522 * Return number of chars processed.
526 hexToInt(char **ptr
, int *intValue
)
535 hexValue
= hex(**ptr
);
539 *intValue
= (*intValue
<< 4) | hexValue
;
549 * This function does all command procesing for interfacing to gdb. It
550 * returns 1 if you should skip the instruction at the trap address, 0
554 extern void breakinst();
557 handle_exception (registers
)
558 unsigned long *registers
;
560 int tt
; /* Trap type */
567 /* First, we must force all of the windows to be spilled out */
569 asm(" save %sp, -64, %sp
587 if (registers
[PC
] == (unsigned long)breakinst
)
589 registers
[PC
] = registers
[NPC
];
593 sp
= (unsigned long *)registers
[SP
];
595 tt
= (registers
[TBR
] >> 4) & 0xff;
597 /* reply to host that an exception has occurred */
598 sigval
= computeSignal(tt
);
599 ptr
= remcomOutBuffer
;
602 *ptr
++ = hexchars
[sigval
>> 4];
603 *ptr
++ = hexchars
[sigval
& 0xf];
605 *ptr
++ = hexchars
[PC
>> 4];
606 *ptr
++ = hexchars
[PC
& 0xf];
608 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
611 *ptr
++ = hexchars
[FP
>> 4];
612 *ptr
++ = hexchars
[FP
& 0xf];
614 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
617 *ptr
++ = hexchars
[SP
>> 4];
618 *ptr
++ = hexchars
[SP
& 0xf];
620 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
623 *ptr
++ = hexchars
[NPC
>> 4];
624 *ptr
++ = hexchars
[NPC
& 0xf];
626 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
629 *ptr
++ = hexchars
[O7
>> 4];
630 *ptr
++ = hexchars
[O7
& 0xf];
632 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
637 putpacket(remcomOutBuffer
);
641 remcomOutBuffer
[0] = 0;
643 getpacket(remcomInBuffer
);
644 switch (remcomInBuffer
[0])
647 remcomOutBuffer
[0] = 'S';
648 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
649 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
650 remcomOutBuffer
[3] = 0;
654 /* toggle debug flag */
657 case 'g': /* return the value of the CPU registers */
659 ptr
= remcomOutBuffer
;
660 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
661 ptr
= mem2hex(sp
+ 0, ptr
, 16 * 4, 0); /* L & I regs */
662 memset(ptr
, '0', 32 * 8); /* Floating point */
663 mem2hex((char *)®isters
[Y
],
666 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
670 case 'G': /* set the value of the CPU registers - return OK */
672 unsigned long *newsp
, psr
;
674 psr
= registers
[PSR
];
676 ptr
= &remcomInBuffer
[1];
677 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
678 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 16 * 4, 0); /* L & I regs */
679 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
680 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
682 /* See if the stack pointer has moved. If so, then copy the saved
683 locals and ins to the new location. This keeps the window
684 overflow and underflow routines happy. */
686 newsp
= (unsigned long *)registers
[SP
];
688 sp
= memcpy(newsp
, sp
, 16 * 4);
690 /* Don't allow CWP to be modified. */
692 if (psr
!= registers
[PSR
])
693 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
695 strcpy(remcomOutBuffer
,"OK");
699 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
700 /* Try to read %x,%x. */
702 ptr
= &remcomInBuffer
[1];
704 if (hexToInt(&ptr
, &addr
)
706 && hexToInt(&ptr
, &length
))
708 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
711 strcpy (remcomOutBuffer
, "E03");
714 strcpy(remcomOutBuffer
,"E01");
717 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
718 /* Try to read '%x,%x:'. */
720 ptr
= &remcomInBuffer
[1];
722 if (hexToInt(&ptr
, &addr
)
724 && hexToInt(&ptr
, &length
)
727 if (hex2mem(ptr
, (char *)addr
, length
, 1))
728 strcpy(remcomOutBuffer
, "OK");
730 strcpy(remcomOutBuffer
, "E03");
733 strcpy(remcomOutBuffer
, "E02");
736 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
737 /* try to read optional parameter, pc unchanged if no parm */
739 ptr
= &remcomInBuffer
[1];
740 if (hexToInt(&ptr
, &addr
))
742 registers
[PC
] = addr
;
743 registers
[NPC
] = addr
+ 4;
746 /* Need to flush the instruction cache here, as we may have deposited a
747 breakpoint, and the icache probably has no way of knowing that a data ref to
748 some location may have changed something that is in the instruction cache.
754 /* kill the program */
755 case 'k' : /* do nothing */
758 case 't': /* Test feature */
759 asm (" std %f31,[%sp]");
762 case 'r': /* Reset */
768 Disabled until we can unscrew
this properly
770 case 'b': /* bBB... Set baud rate to BB... */
773 extern void set_timer_3();
775 ptr
= &remcomInBuffer
[1];
776 if (!hexToInt(&ptr
, &baudrate
))
778 strcpy(remcomOutBuffer
,"B01");
782 /* Convert baud rate to uart clock divider */
795 strcpy(remcomOutBuffer
,"B02");
799 putpacket("OK"); /* Ack before changing speed */
800 set_timer_3(baudrate
); /* Set it */
806 /* reply to the request */
807 putpacket(remcomOutBuffer
);
811 /* This function will generate a breakpoint exception. It is used at the
812 beginning of a program to sync up with a debugger and can be used
813 otherwise as a quick means to stop program execution and "break" into
822 asm(" .globl _breakinst