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
; /* boolean flag. != 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 #define BREAKPOINT() asm(" ta 1");
128 extern unsigned long rdtbr();
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.
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 sub %fp, (16+1+6+1+72)*4, %sp ! Make room for input & locals
180 ! + hidden arg + arg spill
181 ! + doubleword alignment
182 ! + registers[72] local var
184 std %g0, [%fp + (-72 + 0) * 4] ! registers[Gx]
185 std %g2, [%fp + (-72 + 2) * 4]
186 std %g4, [%fp + (-72 + 4) * 4]
187 std %g6, [%fp + (-72 + 6) * 4]
189 std %i0, [%fp + (-72 + 8) * 4] ! registers[Ox]
190 std %i2, [%fp + (-72 + 10) * 4]
191 std %i4, [%fp + (-72 + 12) * 4]
192 std %i6, [%fp + (-72 + 14) * 4]
193 ! F0->F31 not implemented
196 st %l4, [%fp + (-72 + 64) * 4] ! Y
197 st %l0, [%fp + (-72 + 65) * 4] ! PSR
198 st %l3, [%fp + (-72 + 66) * 4] ! WIM
199 st %l5, [%fp + (-72 + 67) * 4] ! TBR
200 st %l1, [%fp + (-72 + 68) * 4] ! PC
201 st %l2, [%fp + (-72 + 69) * 4] ! NPC
203 ! CPSR and FPSR not impl
206 mov %l4, %psr ! Turn on traps, disable interrupts
208 call _handle_exception
209 add %fp, -72 * 4, %o0 ! Pass address of registers
211 restore ! Ensure that previous window is valid
212 save %g0, %g0, %g0 ! by causing a window_underflow trap
214 ! Reload all of the registers that aren't on the stack
216 ld [%fp + (-72 + 1) * 4], %g1 ! registers[Gx]
217 ldd [%fp + (-72 + 2) * 4], %g2
218 ldd [%fp + (-72 + 4) * 4], %g4
219 ldd [%fp + (-72 + 6) * 4], %g6
221 ldd [%fp + (-72 + 8) * 4], %o0 ! registers[Ox]
222 ldd [%fp + (-72 + 10) * 4], %o2
223 ldd [%fp + (-72 + 12) * 4], %o4
224 ldd [%fp + (-72 + 14) * 4], %o6
226 ldd [%fp + (-72 + 64) * 4], %l0 ! Y & PSR
227 ldd [%fp + (-72 + 68) * 4], %l2 ! PC & NPC
229 mov %l1, %psr ! Make sure that traps are disabled
231 jmpl %l2, %g0 ! Restore old PC
232 rett %l3 ! Restore old nPC
235 /* Convert ch from a hex digit to an int */
241 if (ch
>= 'a' && ch
<= 'f')
243 if (ch
>= '0' && ch
<= '9')
245 if (ch
>= 'A' && ch
<= 'F')
250 /* scan for the sequence $<data>#<checksum> */
256 unsigned char checksum
;
257 unsigned char xmitcsum
;
264 /* wait around for the start character, ignore all other characters */
265 while ((ch
= getDebugChar()) != '$') ;
272 /* now, read until a # or end of buffer is found */
273 while (count
< BUFMAX
)
278 checksum
= checksum
+ ch
;
290 xmitcsum
= hex(getDebugChar()) << 4;
291 xmitcsum
|= hex(getDebugChar());
292 if (checksum
!= xmitcsum
)
293 putDebugChar('-'); /* failed checksum */
296 putDebugChar('+'); /* successful transfer */
297 /* if a sequence char is present, reply the sequence ID */
298 if (buffer
[2] == ':')
300 putDebugChar(buffer
[0]);
301 putDebugChar(buffer
[1]);
302 /* remove sequence chars from buffer */
303 count
= strlen(buffer
);
304 for (i
=3; i
<= count
; i
++)
305 buffer
[i
-3] = buffer
[i
];
310 while (checksum
!= xmitcsum
);
313 /* send the packet in buffer. */
317 unsigned char *buffer
;
319 unsigned char checksum
;
323 /* $<packet info>#<checksum>. */
330 while (ch
= buffer
[count
])
332 if (! putDebugChar(ch
))
339 putDebugChar(hexchars
[checksum
>> 4]);
340 putDebugChar(hexchars
[checksum
& 0xf]);
343 while (getDebugChar() != '+');
346 static char remcomInBuffer
[BUFMAX
];
347 static char remcomOutBuffer
[BUFMAX
];
349 /* Indicate to caller of mem2hex or hex2mem that there has been an
351 static volatile int mem_err
= 0;
353 /* Convert the memory pointed to by mem into hex, placing result in buf.
354 * Return a pointer to the last char put in buf (null), in case of mem fault,
356 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
357 * a 0, else treat a fault like any other fault in the stub.
360 static unsigned char *
361 mem2hex(mem
, buf
, count
, may_fault
)
369 set_mem_fault_trap(may_fault
);
376 *buf
++ = hexchars
[ch
>> 4];
377 *buf
++ = hexchars
[ch
& 0xf];
382 set_mem_fault_trap(0);
387 /* convert the hex array pointed to by buf into binary to be placed in mem
388 * return a pointer to the character AFTER the last byte written */
391 hex2mem(buf
, mem
, count
, may_fault
)
400 set_mem_fault_trap(may_fault
);
402 for (i
=0; i
<count
; i
++)
404 ch
= hex(*buf
++) << 4;
411 set_mem_fault_trap(0);
416 /* This table contains the mapping between SPARC hardware trap types, and
417 signals, which are primarily what GDB understands. It also indicates
418 which hardware traps we need to commandeer when initializing the stub. */
420 static struct hard_trap_info
422 unsigned char tt
; /* Trap type code for SPARClite */
423 unsigned char signo
; /* Signal that we map this trap into */
424 } hard_trap_info
[] = {
425 {1, SIGSEGV
}, /* instruction access error */
426 {2, SIGILL
}, /* privileged instruction */
427 {3, SIGILL
}, /* illegal instruction */
428 {4, SIGEMT
}, /* fp disabled */
429 {36, SIGEMT
}, /* cp disabled */
430 {7, SIGBUS
}, /* mem address not aligned */
431 {9, SIGSEGV
}, /* data access exception */
432 {10, SIGEMT
}, /* tag overflow */
433 {128+1, SIGTRAP
}, /* ta 1 - normal breakpoint instruction */
434 {0, 0} /* Must be last */
437 /* Each entry in the trap vector occupies four words. */
444 extern struct trap_entry fltr_proto
;
445 extern struct trap_entry fltr_set_mem_err
;
450 _fltr_proto: ! First level trap routine prototype
451 sethi %hi(trap_low), %l0
452 jmpl %lo(trap_low)+%l0, %g0
456 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
457 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
458 ! 0 would ever contain code that could mem fault. This routine will skip
459 ! past the faulting instruction after setting mem_err.
462 sethi %hi(_mem_err), %l0
463 st %l1, [%l0 + %lo(_mem_err)]
470 /* Set up exception handlers for tracing and breakpoints */
475 struct trap_entry
*tb
; /* Trap vector base address */
476 struct hard_trap_info
*ht
;
478 tb
= (struct trap_entry
*)(rdtbr() & ~0xfff);
480 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
481 tb
[ht
->tt
] = fltr_proto
;
483 /* In case GDB is started before us, ack any packets (presumably
484 "$?#xx") sitting there. */
492 set_mem_fault_trap(enable
)
495 struct trap_entry
*tb
; /* Trap vector base address */
499 tb
= (struct trap_entry
*)(rdtbr() & ~0xfff);
502 tb
[9] = fltr_set_mem_err
;
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
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 sp
= (unsigned long *)registers
[SP
];
589 tt
= (registers
[TBR
] >> 4) & 0xff;
591 /* reply to host that an exception has occurred */
592 sigval
= computeSignal(tt
);
593 ptr
= remcomOutBuffer
;
596 *ptr
++ = hexchars
[sigval
>> 4];
597 *ptr
++ = hexchars
[sigval
& 0xf];
599 *ptr
++ = hexchars
[PC
>> 4];
600 *ptr
++ = hexchars
[PC
& 0xf];
602 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4, 0);
605 *ptr
++ = hexchars
[FP
>> 4];
606 *ptr
++ = hexchars
[FP
& 0xf];
608 ptr
= mem2hex(sp
+ 8 + 6, ptr
, 4, 0); /* FP */
611 *ptr
++ = hexchars
[SP
>> 4];
612 *ptr
++ = hexchars
[SP
& 0xf];
614 ptr
= mem2hex((char *)&sp
, ptr
, 4, 0);
617 *ptr
++ = hexchars
[NPC
>> 4];
618 *ptr
++ = hexchars
[NPC
& 0xf];
620 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4, 0);
623 *ptr
++ = hexchars
[O7
>> 4];
624 *ptr
++ = hexchars
[O7
& 0xf];
626 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4, 0);
631 putpacket(remcomOutBuffer
);
635 remcomOutBuffer
[0] = 0;
637 getpacket(remcomInBuffer
);
638 switch (remcomInBuffer
[0])
641 remcomOutBuffer
[0] = 'S';
642 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
643 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
644 remcomOutBuffer
[3] = 0;
648 /* toggle debug flag */
651 case 'g': /* return the value of the CPU registers */
653 ptr
= remcomOutBuffer
;
654 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4, 0); /* G & O regs */
655 ptr
= mem2hex(sp
+ 0, ptr
, 8 * 4, 0); /* L regs */
656 ptr
= mem2hex(sp
+ 8, ptr
, 8 * 4, 0); /* I regs */
657 memset(ptr
, '0', 32 * 8); /* Floating point */
658 mem2hex((char *)®isters
[Y
],
661 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
665 case 'G': /* set the value of the CPU registers - return OK */
667 ptr
= &remcomInBuffer
[1];
668 hex2mem(ptr
, (char *)registers
, 16 * 4, 0); /* G & O regs */
669 hex2mem(ptr
+ 16 * 4 * 2, sp
+ 0, 8 * 4, 0); /* L regs */
670 hex2mem(ptr
+ 24 * 4 * 2, sp
+ 8, 8 * 4, 0); /* I regs */
671 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
],
672 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
673 strcpy(remcomOutBuffer
,"OK");
677 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
678 /* Try to read %x,%x. */
680 ptr
= &remcomInBuffer
[1];
682 if (hexToInt(&ptr
, &addr
)
684 && hexToInt(&ptr
, &length
))
686 if (mem2hex((char *)addr
, remcomOutBuffer
, length
, 1))
689 strcpy (remcomOutBuffer
, "E03");
692 strcpy(remcomOutBuffer
,"E01");
695 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
696 /* Try to read '%x,%x:'. */
698 ptr
= &remcomInBuffer
[1];
700 if (hexToInt(&ptr
, &addr
)
702 && hexToInt(&ptr
, &length
)
705 if (hex2mem(ptr
, (char *)addr
, length
, 1))
706 strcpy(remcomOutBuffer
, "OK");
708 strcpy(remcomOutBuffer
, "E03");
711 strcpy(remcomOutBuffer
, "E02");
714 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
715 case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
716 /* try to read optional parameter, pc unchanged if no parm */
718 ptr
= &remcomInBuffer
[1];
719 if (hexToInt(&ptr
, &addr
))
721 registers
[PC
] = addr
;
722 registers
[NPC
] = addr
+ 4;
725 /* Need to flush the instruction cache here, as we may have deposited a
726 breakpoint, and the icache probably has no way of knowing that a data ref to
727 some location may have changed something that is in the instruction cache.
733 /* kill the program */
734 case 'k' : /* do nothing */
737 Disabled until we can unscrew
this properly
739 case 'b': /* bBB... Set baud rate to BB... */
742 extern void set_timer_3();
744 ptr
= &remcomInBuffer
[1];
745 if (!hexToInt(&ptr
, &baudrate
))
747 strcpy(remcomOutBuffer
,"B01");
751 /* Convert baud rate to uart clock divider */
764 strcpy(remcomOutBuffer
,"B02");
768 putpacket("OK"); /* Ack before changing speed */
769 set_timer_3(baudrate
); /* Set it */
775 /* reply to the request */
776 putpacket(remcomOutBuffer
);
780 /* This function will generate a breakpoint exception. It is used at the
781 beginning of a program to sync up with a debugger and can be used
782 otherwise as a quick means to stop program execution and "break" into