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());
293 /* Humans shouldn't have to figure out checksums to type to it. */
297 if (checksum != xmitcsum)
298 putDebugChar('-'); /* failed checksum */
301 putDebugChar('+'); /* successful transfer */
302 /* if a sequence char is present, reply the sequence ID */
303 if (buffer[2] == ':')
305 putDebugChar(buffer[0]);
306 putDebugChar(buffer[1]);
307 /* remove sequence chars from buffer */
308 count = strlen(buffer);
309 for (i=3; i <= count; i++)
310 buffer[i-3] = buffer[i];
315 while (checksum != xmitcsum);
318 /* send the packet in buffer. */
322 unsigned char *buffer;
324 unsigned char checksum;
328 /* $<packet info>#<checksum>. */
335 while (ch = buffer[count])
337 if (! putDebugChar(ch))
344 putDebugChar(hexchars[checksum >> 4]);
345 putDebugChar(hexchars[checksum & 0xf]);
348 while (getDebugChar() != '+');
351 static char remcomInBuffer[BUFMAX];
352 static char remcomOutBuffer[BUFMAX];
354 /* Indicate to caller of mem2hex or hex2mem that there has been an
356 static volatile int mem_err = 0;
358 /* Convert the memory pointed to by mem into hex, placing result in buf.
359 * Return a pointer to the last char put in buf (null), in case of mem fault,
361 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
362 * a 0, else treat a fault like any other fault in the stub.
365 static unsigned char *
366 mem2hex(mem, buf, count, may_fault)
374 set_mem_fault_trap(may_fault);
381 *buf++ = hexchars[ch >> 4];
382 *buf++ = hexchars[ch & 0xf];
387 set_mem_fault_trap(0);
392 /* convert the hex array pointed to by buf into binary to be placed in mem
393 * return a pointer to the character AFTER the last byte written */
396 hex2mem(buf, mem, count, may_fault)
405 set_mem_fault_trap(may_fault);
407 for (i=0; i<count; i++)
409 ch = hex(*buf++) << 4;
416 set_mem_fault_trap(0);
421 /* This table contains the mapping between SPARC hardware trap types, and
422 signals, which are primarily what GDB understands. It also indicates
423 which hardware traps we need to commandeer when initializing the stub. */
425 static struct hard_trap_info
427 unsigned char tt; /* Trap type code for SPARClite */
428 unsigned char signo; /* Signal that we map this trap into */
429 } hard_trap_info[] = {
430 {1, SIGSEGV}, /* instruction access error */
431 {2, SIGILL}, /* privileged instruction */
432 {3, SIGILL}, /* illegal instruction */
433 {4, SIGEMT}, /* fp disabled */
434 {36, SIGEMT}, /* cp disabled */
435 {7, SIGBUS}, /* mem address not aligned */
436 {9, SIGSEGV}, /* data access exception */
437 {10, SIGEMT}, /* tag overflow */
438 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
439 {0, 0} /* Must be last */
442 /* Each entry in the trap vector occupies four words. */
449 extern struct trap_entry fltr_proto;
450 extern struct trap_entry fltr_set_mem_err;
455 _fltr_proto: ! First level trap routine prototype
456 sethi %hi(trap_low), %l0
457 jmpl %lo(trap_low)+%l0, %g0
461 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
462 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
463 ! 0 would ever contain code that could mem fault. This routine will skip
464 ! past the faulting instruction after setting mem_err.
467 sethi %hi(_mem_err), %l0
468 st %l1, [%l0 + %lo(_mem_err)]
475 /* Set up exception handlers for tracing and breakpoints */
480 struct trap_entry *tb; /* Trap vector base address */
481 struct hard_trap_info *ht;
483 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
485 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
486 tb[ht->tt] = fltr_proto;
488 /* In case GDB is started before us, ack any packets (presumably
489 "$?#xx") sitting there. */
497 set_mem_fault_trap(enable)
500 struct trap_entry *tb; /* Trap vector base address */
504 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
507 tb[9] = fltr_set_mem_err;
512 /* Convert the SPARC hardware trap type code to a unix signal number. */
518 struct hard_trap_info *ht;
520 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
524 return SIGHUP; /* default for things we don't know about */
528 * While we find nice hex chars, build an int.
529 * Return number of chars processed.
533 hexToInt(char **ptr, int *intValue)
542 hexValue = hex(**ptr);
546 *intValue = (*intValue << 4) | hexValue;
556 * This function does all command procesing for interfacing to gdb. It
557 * returns 1 if you should skip the instruction at the trap address, 0
562 handle_exception (registers)
563 unsigned long *registers;
565 int tt; /* Trap type */
572 /* First, we must force all of the windows to be spilled out */
574 asm(" save %sp, -64, %sp
592 sp = (unsigned long *)registers[SP];
594 tt = (registers[TBR] >> 4) & 0xff;
596 /* reply to host that an exception has occurred */
597 sigval = computeSignal(tt);
598 ptr = remcomOutBuffer;
601 *ptr++ = hexchars[sigval >> 4];
602 *ptr++ = hexchars[sigval & 0xf];
604 *ptr++ = hexchars[PC >> 4];
605 *ptr++ = hexchars[PC & 0xf];
607 ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
610 *ptr++ = hexchars[FP >> 4];
611 *ptr++ = hexchars[FP & 0xf];
613 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
616 *ptr++ = hexchars[SP >> 4];
617 *ptr++ = hexchars[SP & 0xf];
619 ptr = mem2hex((char *)&sp, ptr, 4, 0);
622 *ptr++ = hexchars[NPC >> 4];
623 *ptr++ = hexchars[NPC & 0xf];
625 ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0);
628 *ptr++ = hexchars[O7 >> 4];
629 *ptr++ = hexchars[O7 & 0xf];
631 ptr = mem2hex((char *)®isters[O7], ptr, 4, 0);
636 putpacket(remcomOutBuffer);
640 remcomOutBuffer[0] = 0;
642 getpacket(remcomInBuffer);
643 switch (remcomInBuffer[0])
646 remcomOutBuffer[0] = 'S';
647 remcomOutBuffer[1] = hexchars[sigval >> 4];
648 remcomOutBuffer[2] = hexchars[sigval & 0xf];
649 remcomOutBuffer[3] = 0;
653 /* toggle debug flag */
656 case 'g': /* return the value of the CPU registers */
658 ptr = remcomOutBuffer;
659 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
660 ptr = mem2hex(sp + 0, ptr, 8 * 4, 0); /* L regs */
661 ptr = mem2hex(sp + 8, ptr, 8 * 4, 0); /* 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 ptr = &remcomInBuffer[1];
673 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
674 hex2mem(ptr + 16 * 4 * 2, sp + 0, 8 * 4, 0); /* L regs */
675 hex2mem(ptr + 24 * 4 * 2, sp + 8, 8 * 4, 0); /* I regs */
676 hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
677 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
678 strcpy(remcomOutBuffer,"OK");
682 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
683 /* Try to read %x,%x. */
685 ptr = &remcomInBuffer[1];
687 if (hexToInt(&ptr, &addr)
689 && hexToInt(&ptr, &length))
691 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
694 strcpy (remcomOutBuffer, "E03");
697 strcpy(remcomOutBuffer,"E01");
700 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
701 /* Try to read '%x,%x:'. */
703 ptr = &remcomInBuffer[1];
705 if (hexToInt(&ptr, &addr)
707 && hexToInt(&ptr, &length)
710 if (hex2mem(ptr, (char *)addr, length, 1))
711 strcpy(remcomOutBuffer, "OK");
713 strcpy(remcomOutBuffer, "E03");
716 strcpy(remcomOutBuffer, "E02");
719 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
720 case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
721 /* try to read optional parameter, pc unchanged if no parm */
723 ptr = &remcomInBuffer[1];
724 if (hexToInt(&ptr, &addr))
726 registers[PC] = addr;
727 registers[NPC] = addr + 4;
732 /* kill the program */
733 case 'k' : /* do nothing */
736 Disabled until we can unscrew this properly
738 case 'b': /* bBB... Set baud rate to BB... */
741 extern void set_timer_3();
743 ptr = &remcomInBuffer[1];
744 if (!hexToInt(&ptr, &baudrate))
746 strcpy(remcomOutBuffer,"B01");
750 /* Convert baud rate to uart clock divider */
763 strcpy(remcomOutBuffer,"B02");
767 putpacket("OK"); /* Ack before changing speed */
768 set_timer_3(baudrate); /* Set it */
774 /* reply to the request */
775 putpacket(remcomOutBuffer);
779 /* This function will generate a breakpoint exception. It is used at the
780 beginning of a program to sync up with a debugger and can be used
781 otherwise as a quick means to stop program execution and "break" into