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 ****************************************************************************/
91 /************************************************************************
93 * external low-level support routines
96 extern putDebugChar(); /* write a single character */
97 extern getDebugChar(); /* read and return a single char */
99 /************************************************************************/
100 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
101 /* at least NUMREGBYTES*2 are needed for register packets */
104 static int initialized = 0; /* !0 means we've been initialized */
106 static void set_mem_fault_trap();
108 static const char hexchars[]="0123456789abcdef";
112 /* Number of bytes of registers. */
113 #define NUMREGBYTES (NUMREGS * 4)
114 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
115 O0, O1, O2, O3, O4, O5, SP, O7,
116 L0, L1, L2, L3, L4, L5, L6, L7,
117 I0, I1, I2, I3, I4, I5, FP, I7,
119 F0, F1, F2, F3, F4, F5, F6, F7,
120 F8, F9, F10, F11, F12, F13, F14, F15,
121 F16, F17, F18, F19, F20, F21, F22, F23,
122 F24, F25, F26, F27, F28, F29, F30, F31,
123 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
125 /*************************** ASSEMBLY CODE MACROS *************************/
128 extern void trap_low();
131 .reserve trapstack, 1000 * 4, \"bss\", 8
142 ! This function is called when any SPARC trap (except window overflow or
143 ! underflow) occurs. It makes sure that the invalid register window is still
144 ! available before jumping into C code. It will also restore the world if you
145 ! return from handle_exception.
152 srl %l3, %l0, %l4 ! wim >> cwp
154 bne window_fine ! Branch if not in the invalid window
157 ! Handle window overflow
159 mov %g1, %l4 ! Save g1, we use it to hold the wim
160 srl %l3, 1, %g1 ! Rotate wim right
164 save %g0, %g0, %g0 ! Slip into next window
165 mov %g1, %wim ! Install the new wim
167 std %l0, [%sp + 0 * 4] ! save L & I registers
168 std %l2, [%sp + 2 * 4]
169 std %l4, [%sp + 4 * 4]
170 std %l6, [%sp + 6 * 4]
172 std %i0, [%sp + 8 * 4]
173 std %i2, [%sp + 10 * 4]
174 std %i4, [%sp + 12 * 4]
175 std %i6, [%sp + 14 * 4]
177 restore ! Go back to trap window.
178 mov %l4, %g1 ! Restore %g1
181 sethi %hi(in_trap_handler), %l4
182 ld [%lo(in_trap_handler) + %l4], %l5
187 set trapstack+1000*4, %sp ! Switch to trap stack
190 st %l5, [%lo(in_trap_handler) + %l4]
191 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
192 ! + hidden arg + arg spill
193 ! + doubleword alignment
194 ! + registers[72] local var
196 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
197 std %g2, [%sp + (24 + 2) * 4]
198 std %g4, [%sp + (24 + 4) * 4]
199 std %g6, [%sp + (24 + 6) * 4]
201 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
202 std %i2, [%sp + (24 + 10) * 4]
203 std %i4, [%sp + (24 + 12) * 4]
204 std %i6, [%sp + (24 + 14) * 4]
205 ! F0->F31 not implemented
208 st %l4, [%sp + (24 + 64) * 4] ! Y
209 st %l0, [%sp + (24 + 65) * 4] ! PSR
210 st %l3, [%sp + (24 + 66) * 4] ! WIM
211 st %l5, [%sp + (24 + 67) * 4] ! TBR
212 st %l1, [%sp + (24 + 68) * 4] ! PC
213 st %l2, [%sp + (24 + 69) * 4] ! NPC
215 ! CPSR and FPSR not impl
218 mov %l4, %psr ! Turn on traps, disable interrupts
220 call _handle_exception
221 add %sp, 24 * 4, %o0 ! Pass address of registers
223 ! Reload all of the registers that aren't on the stack
225 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
226 ldd [%sp + (24 + 2) * 4], %g2
227 ldd [%sp + (24 + 4) * 4], %g4
228 ldd [%sp + (24 + 6) * 4], %g6
230 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
231 ldd [%sp + (24 + 10) * 4], %i2
232 ldd [%sp + (24 + 12) * 4], %i4
233 ldd [%sp + (24 + 14) * 4], %i6
235 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
236 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
238 restore ! Ensure that previous window is valid
239 save %g0, %g0, %g0 ! by causing a window_underflow trap
242 mov %l1, %psr ! Make sure that traps are disabled
245 sethi %hi(in_trap_handler), %l4
246 ld [%lo(in_trap_handler) + %l4], %l5
248 st %l5, [%lo(in_trap_handler) + %l4]
250 jmpl %l2, %g0 ! Restore old PC
251 rett %l3 ! Restore old nPC
254 /* Convert ch from a hex digit to an int */
260 if (ch >= 'a' && ch <= 'f')
262 if (ch >= '0' && ch <= '9')
264 if (ch >= 'A' && ch <= 'F')
269 /* scan for the sequence $<data>#<checksum> */
275 unsigned char checksum;
276 unsigned char xmitcsum;
283 /* wait around for the start character, ignore all other characters */
284 while ((ch = getDebugChar()) != '$') ;
291 /* now, read until a # or end of buffer is found */
292 while (count < BUFMAX)
297 checksum = checksum + ch;
309 xmitcsum = hex(getDebugChar()) << 4;
310 xmitcsum |= hex(getDebugChar());
312 /* Humans shouldn't have to figure out checksums to type to it. */
316 if (checksum != xmitcsum)
317 putDebugChar('-'); /* failed checksum */
320 putDebugChar('+'); /* successful transfer */
321 /* if a sequence char is present, reply the sequence ID */
322 if (buffer[2] == ':')
324 putDebugChar(buffer[0]);
325 putDebugChar(buffer[1]);
326 /* remove sequence chars from buffer */
327 count = strlen(buffer);
328 for (i=3; i <= count; i++)
329 buffer[i-3] = buffer[i];
334 while (checksum != xmitcsum);
337 /* send the packet in buffer. */
341 unsigned char *buffer;
343 unsigned char checksum;
347 /* $<packet info>#<checksum>. */
354 while (ch = buffer[count])
356 if (! putDebugChar(ch))
363 putDebugChar(hexchars[checksum >> 4]);
364 putDebugChar(hexchars[checksum & 0xf]);
367 while (getDebugChar() != '+');
370 static char remcomInBuffer[BUFMAX];
371 static char remcomOutBuffer[BUFMAX];
373 /* Indicate to caller of mem2hex or hex2mem that there has been an
375 static volatile int mem_err = 0;
377 /* Convert the memory pointed to by mem into hex, placing result in buf.
378 * Return a pointer to the last char put in buf (null), in case of mem fault,
380 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
381 * a 0, else treat a fault like any other fault in the stub.
384 static unsigned char *
385 mem2hex(mem, buf, count, may_fault)
393 set_mem_fault_trap(may_fault);
400 *buf++ = hexchars[ch >> 4];
401 *buf++ = hexchars[ch & 0xf];
406 set_mem_fault_trap(0);
411 /* convert the hex array pointed to by buf into binary to be placed in mem
412 * return a pointer to the character AFTER the last byte written */
415 hex2mem(buf, mem, count, may_fault)
424 set_mem_fault_trap(may_fault);
426 for (i=0; i<count; i++)
428 ch = hex(*buf++) << 4;
435 set_mem_fault_trap(0);
440 /* This table contains the mapping between SPARC hardware trap types, and
441 signals, which are primarily what GDB understands. It also indicates
442 which hardware traps we need to commandeer when initializing the stub. */
444 static struct hard_trap_info
446 unsigned char tt; /* Trap type code for SPARClite */
447 unsigned char signo; /* Signal that we map this trap into */
448 } hard_trap_info[] = {
449 {1, SIGSEGV}, /* instruction access error */
450 {2, SIGILL}, /* privileged instruction */
451 {3, SIGILL}, /* illegal instruction */
452 {4, SIGEMT}, /* fp disabled */
453 {36, SIGEMT}, /* cp disabled */
454 {7, SIGBUS}, /* mem address not aligned */
455 {9, SIGSEGV}, /* data access exception */
456 {10, SIGEMT}, /* tag overflow */
457 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
458 {0, 0} /* Must be last */
461 /* Set up exception handlers for tracing and breakpoints */
466 struct hard_trap_info *ht;
468 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
469 exceptionHandler(ht->tt, trap_low);
471 /* In case GDB is started before us, ack any packets (presumably
472 "$?#xx") sitting there. */
480 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
481 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
482 ! 0 would ever contain code that could mem fault. This routine will skip
483 ! past the faulting instruction after setting mem_err.
489 sethi %hi(_mem_err), %l0
490 st %l1, [%l0 + %lo(_mem_err)]
496 set_mem_fault_trap(enable)
499 extern void fltr_set_mem_err();
503 exceptionHandler(9, fltr_set_mem_err);
505 exceptionHandler(9, trap_low);
508 /* Convert the SPARC hardware trap type code to a unix signal number. */
514 struct hard_trap_info *ht;
516 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
520 return SIGHUP; /* default for things we don't know about */
524 * While we find nice hex chars, build an int.
525 * Return number of chars processed.
529 hexToInt(char **ptr, int *intValue)
538 hexValue = hex(**ptr);
542 *intValue = (*intValue << 4) | hexValue;
552 * This function does all command procesing for interfacing to gdb. It
553 * returns 1 if you should skip the instruction at the trap address, 0
557 extern void breakinst();
560 handle_exception (registers)
561 unsigned long *registers;
563 int tt; /* Trap type */
570 /* First, we must force all of the windows to be spilled out */
572 asm(" save %sp, -64, %sp
590 if (registers[PC] == (unsigned long)breakinst)
592 registers[PC] = registers[NPC];
596 sp = (unsigned long *)registers[SP];
598 tt = (registers[TBR] >> 4) & 0xff;
600 /* reply to host that an exception has occurred */
601 sigval = computeSignal(tt);
602 ptr = remcomOutBuffer;
605 *ptr++ = hexchars[sigval >> 4];
606 *ptr++ = hexchars[sigval & 0xf];
608 *ptr++ = hexchars[PC >> 4];
609 *ptr++ = hexchars[PC & 0xf];
611 ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
614 *ptr++ = hexchars[FP >> 4];
615 *ptr++ = hexchars[FP & 0xf];
617 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
620 *ptr++ = hexchars[SP >> 4];
621 *ptr++ = hexchars[SP & 0xf];
623 ptr = mem2hex((char *)&sp, ptr, 4, 0);
626 *ptr++ = hexchars[NPC >> 4];
627 *ptr++ = hexchars[NPC & 0xf];
629 ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0);
632 *ptr++ = hexchars[O7 >> 4];
633 *ptr++ = hexchars[O7 & 0xf];
635 ptr = mem2hex((char *)®isters[O7], ptr, 4, 0);
640 putpacket(remcomOutBuffer);
644 remcomOutBuffer[0] = 0;
646 getpacket(remcomInBuffer);
647 switch (remcomInBuffer[0])
650 remcomOutBuffer[0] = 'S';
651 remcomOutBuffer[1] = hexchars[sigval >> 4];
652 remcomOutBuffer[2] = hexchars[sigval & 0xf];
653 remcomOutBuffer[3] = 0;
657 /* toggle debug flag */
660 case 'g': /* return the value of the CPU registers */
662 ptr = remcomOutBuffer;
663 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
664 ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
665 memset(ptr, '0', 32 * 8); /* Floating point */
666 mem2hex((char *)®isters[Y],
669 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
673 case 'G': /* set the value of the CPU registers - return OK */
675 unsigned long *newsp, psr;
677 psr = registers[PSR];
679 ptr = &remcomInBuffer[1];
680 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
681 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
682 hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
683 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
685 /* See if the stack pointer has moved. If so, then copy the saved
686 locals and ins to the new location. This keeps the window
687 overflow and underflow routines happy. */
689 newsp = (unsigned long *)registers[SP];
691 sp = memcpy(newsp, sp, 16 * 4);
693 /* Don't allow CWP to be modified. */
695 if (psr != registers[PSR])
696 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
698 strcpy(remcomOutBuffer,"OK");
702 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
703 /* Try to read %x,%x. */
705 ptr = &remcomInBuffer[1];
707 if (hexToInt(&ptr, &addr)
709 && hexToInt(&ptr, &length))
711 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
714 strcpy (remcomOutBuffer, "E03");
717 strcpy(remcomOutBuffer,"E01");
720 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
721 /* Try to read '%x,%x:'. */
723 ptr = &remcomInBuffer[1];
725 if (hexToInt(&ptr, &addr)
727 && hexToInt(&ptr, &length)
730 if (hex2mem(ptr, (char *)addr, length, 1))
731 strcpy(remcomOutBuffer, "OK");
733 strcpy(remcomOutBuffer, "E03");
736 strcpy(remcomOutBuffer, "E02");
739 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
740 /* try to read optional parameter, pc unchanged if no parm */
742 ptr = &remcomInBuffer[1];
743 if (hexToInt(&ptr, &addr))
745 registers[PC] = addr;
746 registers[NPC] = addr + 4;
749 /* Need to flush the instruction cache here, as we may have deposited a
750 breakpoint, and the icache probably has no way of knowing that a data ref to
751 some location may have changed something that is in the instruction cache.
757 /* kill the program */
758 case 'k' : /* do nothing */
761 case 't': /* Test feature */
762 asm (" std %f31,[%sp]");
765 case 'r': /* Reset */
771 Disabled until we can unscrew this properly
773 case 'b': /* bBB... Set baud rate to BB... */
776 extern void set_timer_3();
778 ptr = &remcomInBuffer[1];
779 if (!hexToInt(&ptr, &baudrate))
781 strcpy(remcomOutBuffer,"B01");
785 /* Convert baud rate to uart clock divider */
798 strcpy(remcomOutBuffer,"B02");
802 putpacket("OK"); /* Ack before changing speed */
803 set_timer_3(baudrate); /* Set it */
809 /* reply to the request */
810 putpacket(remcomOutBuffer);
814 /* This function will generate a breakpoint exception. It is used at the
815 beginning of a program to sync up with a debugger and can be used
816 otherwise as a quick means to stop program execution and "break" into
825 asm(" .globl _breakinst