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 void putDebugChar(); /* write a single character */
96 extern int 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
161 bg good_wim ! Branch if new wim is non-zero
164 ! At this point, we need to bring a 1 into the high order bit of the wim.
165 ! Since we don't want to make any assumptions about the number of register
166 ! windows, we figure it out dynamically so as to setup the wim correctly.
168 not %g1 ! Fill g1 with ones
169 mov %g1, %wim ! Fill the wim with ones
173 mov %wim, %g1 ! Read back the wim
174 inc %g1 ! Now g1 has 1 just to left of wim
175 srl %g1, 1, %g1 ! Now put 1 at top of wim
176 mov %g0, %wim ! Clear wim so that subsequent save
182 save %g0, %g0, %g0 ! Slip into next window
183 mov %g1, %wim ! Install the new wim
185 std %l0, [%sp + 0 * 4] ! save L & I registers
186 std %l2, [%sp + 2 * 4]
187 std %l4, [%sp + 4 * 4]
188 std %l6, [%sp + 6 * 4]
190 std %i0, [%sp + 8 * 4]
191 std %i2, [%sp + 10 * 4]
192 std %i4, [%sp + 12 * 4]
193 std %i6, [%sp + 14 * 4]
195 restore ! Go back to trap window.
196 mov %l4, %g1 ! Restore %g1
199 sethi %hi(in_trap_handler), %l4
200 ld [%lo(in_trap_handler) + %l4], %l5
205 set trapstack+1000*4, %sp ! Switch to trap stack
208 st %l5, [%lo(in_trap_handler) + %l4]
209 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
210 ! + hidden arg + arg spill
211 ! + doubleword alignment
212 ! + registers[72] local var
214 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
215 std %g2, [%sp + (24 + 2) * 4]
216 std %g4, [%sp + (24 + 4) * 4]
217 std %g6, [%sp + (24 + 6) * 4]
219 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
220 std %i2, [%sp + (24 + 10) * 4]
221 std %i4, [%sp + (24 + 12) * 4]
222 std %i6, [%sp + (24 + 14) * 4]
223 ! F0->F31 not implemented
226 st %l4, [%sp + (24 + 64) * 4] ! Y
227 st %l0, [%sp + (24 + 65) * 4] ! PSR
228 st %l3, [%sp + (24 + 66) * 4] ! WIM
229 st %l5, [%sp + (24 + 67) * 4] ! TBR
230 st %l1, [%sp + (24 + 68) * 4] ! PC
231 st %l2, [%sp + (24 + 69) * 4] ! NPC
233 ! CPSR and FPSR not impl
236 mov %l4, %psr ! Turn on traps, disable interrupts
238 call _handle_exception
239 add %sp, 24 * 4, %o0 ! Pass address of registers
241 ! Reload all of the registers that aren't on the stack
243 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
244 ldd [%sp + (24 + 2) * 4], %g2
245 ldd [%sp + (24 + 4) * 4], %g4
246 ldd [%sp + (24 + 6) * 4], %g6
248 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
249 ldd [%sp + (24 + 10) * 4], %i2
250 ldd [%sp + (24 + 12) * 4], %i4
251 ldd [%sp + (24 + 14) * 4], %i6
253 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
254 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
256 restore ! Ensure that previous window is valid
257 save %g0, %g0, %g0 ! by causing a window_underflow trap
260 mov %l1, %psr ! Make sure that traps are disabled
263 sethi %hi(in_trap_handler), %l4
264 ld [%lo(in_trap_handler) + %l4], %l5
266 st %l5, [%lo(in_trap_handler) + %l4]
268 jmpl %l2, %g0 ! Restore old PC
269 rett %l3 ! Restore old nPC
272 /* Convert ch from a hex digit to an int */
278 if (ch >= 'a' && ch <= 'f')
280 if (ch >= '0' && ch <= '9')
282 if (ch >= 'A' && ch <= 'F')
287 /* scan for the sequence $<data>#<checksum> */
291 unsigned char *buffer;
293 unsigned char checksum;
294 unsigned char xmitcsum;
300 /* wait around for the start character, ignore all other characters */
301 while ((ch = getDebugChar ()) != '$')
309 /* now, read until a # or end of buffer is found */
310 while (count < BUFMAX)
312 ch = getDebugChar ();
317 checksum = checksum + ch;
325 ch = getDebugChar ();
326 xmitcsum = hex (ch) << 4;
327 ch = getDebugChar ();
328 xmitcsum += hex (ch);
330 if (checksum != xmitcsum)
332 putDebugChar ('-'); /* failed checksum */
336 putDebugChar ('+'); /* successful transfer */
338 /* if a sequence char is present, reply the sequence ID */
339 if (buffer[2] == ':')
341 putDebugChar (buffer[0]);
342 putDebugChar (buffer[1]);
353 /* send the packet in buffer. */
357 unsigned char *buffer;
359 unsigned char checksum;
363 /* $<packet info>#<checksum>. */
370 while (ch = buffer[count])
378 putDebugChar(hexchars[checksum >> 4]);
379 putDebugChar(hexchars[checksum & 0xf]);
382 while (getDebugChar() != '+');
385 static char remcomInBuffer[BUFMAX];
386 static char remcomOutBuffer[BUFMAX];
388 /* Indicate to caller of mem2hex or hex2mem that there has been an
390 static volatile int mem_err = 0;
392 /* Convert the memory pointed to by mem into hex, placing result in buf.
393 * Return a pointer to the last char put in buf (null), in case of mem fault,
395 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
396 * a 0, else treat a fault like any other fault in the stub.
399 static unsigned char *
400 mem2hex(mem, buf, count, may_fault)
408 set_mem_fault_trap(may_fault);
415 *buf++ = hexchars[ch >> 4];
416 *buf++ = hexchars[ch & 0xf];
421 set_mem_fault_trap(0);
426 /* convert the hex array pointed to by buf into binary to be placed in mem
427 * return a pointer to the character AFTER the last byte written */
430 hex2mem(buf, mem, count, may_fault)
439 set_mem_fault_trap(may_fault);
441 for (i=0; i<count; i++)
443 ch = hex(*buf++) << 4;
450 set_mem_fault_trap(0);
455 /* This table contains the mapping between SPARC hardware trap types, and
456 signals, which are primarily what GDB understands. It also indicates
457 which hardware traps we need to commandeer when initializing the stub. */
459 static struct hard_trap_info
461 unsigned char tt; /* Trap type code for SPARClite */
462 unsigned char signo; /* Signal that we map this trap into */
463 } hard_trap_info[] = {
464 {1, SIGSEGV}, /* instruction access error */
465 {2, SIGILL}, /* privileged instruction */
466 {3, SIGILL}, /* illegal instruction */
467 {4, SIGEMT}, /* fp disabled */
468 {36, SIGEMT}, /* cp disabled */
469 {7, SIGBUS}, /* mem address not aligned */
470 {9, SIGSEGV}, /* data access exception */
471 {10, SIGEMT}, /* tag overflow */
472 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
473 {0, 0} /* Must be last */
476 /* Set up exception handlers for tracing and breakpoints */
481 struct hard_trap_info *ht;
483 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
484 exceptionHandler(ht->tt, trap_low);
490 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
491 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
492 ! 0 would ever contain code that could mem fault. This routine will skip
493 ! past the faulting instruction after setting mem_err.
499 sethi %hi(_mem_err), %l0
500 st %l1, [%l0 + %lo(_mem_err)]
506 set_mem_fault_trap(enable)
509 extern void fltr_set_mem_err();
513 exceptionHandler(9, fltr_set_mem_err);
515 exceptionHandler(9, trap_low);
518 /* Convert the SPARC hardware trap type code to a unix signal number. */
524 struct hard_trap_info *ht;
526 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
530 return SIGHUP; /* default for things we don't know about */
534 * While we find nice hex chars, build an int.
535 * Return number of chars processed.
539 hexToInt(char **ptr, int *intValue)
548 hexValue = hex(**ptr);
552 *intValue = (*intValue << 4) | hexValue;
562 * This function does all command procesing for interfacing to gdb. It
563 * returns 1 if you should skip the instruction at the trap address, 0
567 extern void breakinst();
570 handle_exception (registers)
571 unsigned long *registers;
573 int tt; /* Trap type */
580 /* First, we must force all of the windows to be spilled out */
582 asm(" save %sp, -64, %sp
600 if (registers[PC] == (unsigned long)breakinst)
602 registers[PC] = registers[NPC];
606 sp = (unsigned long *)registers[SP];
608 tt = (registers[TBR] >> 4) & 0xff;
610 /* reply to host that an exception has occurred */
611 sigval = computeSignal(tt);
612 ptr = remcomOutBuffer;
615 *ptr++ = hexchars[sigval >> 4];
616 *ptr++ = hexchars[sigval & 0xf];
618 *ptr++ = hexchars[PC >> 4];
619 *ptr++ = hexchars[PC & 0xf];
621 ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
624 *ptr++ = hexchars[FP >> 4];
625 *ptr++ = hexchars[FP & 0xf];
627 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
630 *ptr++ = hexchars[SP >> 4];
631 *ptr++ = hexchars[SP & 0xf];
633 ptr = mem2hex((char *)&sp, ptr, 4, 0);
636 *ptr++ = hexchars[NPC >> 4];
637 *ptr++ = hexchars[NPC & 0xf];
639 ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0);
642 *ptr++ = hexchars[O7 >> 4];
643 *ptr++ = hexchars[O7 & 0xf];
645 ptr = mem2hex((char *)®isters[O7], ptr, 4, 0);
650 putpacket(remcomOutBuffer);
654 remcomOutBuffer[0] = 0;
656 ptr = getpacket(remcomInBuffer);
660 remcomOutBuffer[0] = 'S';
661 remcomOutBuffer[1] = hexchars[sigval >> 4];
662 remcomOutBuffer[2] = hexchars[sigval & 0xf];
663 remcomOutBuffer[3] = 0;
666 case 'd': /* toggle debug flag */
669 case 'g': /* return the value of the CPU registers */
671 ptr = remcomOutBuffer;
672 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
673 ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
674 memset(ptr, '0', 32 * 8); /* Floating point */
675 mem2hex((char *)®isters[Y],
678 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
682 case 'G': /* set the value of the CPU registers - return OK */
684 unsigned long *newsp, psr;
686 psr = registers[PSR];
688 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
689 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
690 hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
691 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
693 /* See if the stack pointer has moved. If so, then copy the saved
694 locals and ins to the new location. This keeps the window
695 overflow and underflow routines happy. */
697 newsp = (unsigned long *)registers[SP];
699 sp = memcpy(newsp, sp, 16 * 4);
701 /* Don't allow CWP to be modified. */
703 if (psr != registers[PSR])
704 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
706 strcpy(remcomOutBuffer,"OK");
710 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
711 /* Try to read %x,%x. */
713 if (hexToInt(&ptr, &addr)
715 && hexToInt(&ptr, &length))
717 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
720 strcpy (remcomOutBuffer, "E03");
723 strcpy(remcomOutBuffer,"E01");
726 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
727 /* Try to read '%x,%x:'. */
729 if (hexToInt(&ptr, &addr)
731 && hexToInt(&ptr, &length)
734 if (hex2mem(ptr, (char *)addr, length, 1))
735 strcpy(remcomOutBuffer, "OK");
737 strcpy(remcomOutBuffer, "E03");
740 strcpy(remcomOutBuffer, "E02");
743 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
744 /* try to read optional parameter, pc unchanged if no parm */
746 if (hexToInt(&ptr, &addr))
748 registers[PC] = addr;
749 registers[NPC] = addr + 4;
752 /* Need to flush the instruction cache here, as we may have deposited a
753 breakpoint, and the icache probably has no way of knowing that a data ref to
754 some location may have changed something that is in the instruction cache.
760 /* kill the program */
761 case 'k' : /* do nothing */
764 case 't': /* Test feature */
765 asm (" std %f30,[%sp]");
768 case 'r': /* Reset */
774 Disabled until we can unscrew this properly
776 case 'b': /* bBB... Set baud rate to BB... */
779 extern void set_timer_3();
781 if (!hexToInt(&ptr, &baudrate))
783 strcpy(remcomOutBuffer,"B01");
787 /* Convert baud rate to uart clock divider */
800 strcpy(remcomOutBuffer,"B02");
804 putpacket("OK"); /* Ack before changing speed */
805 set_timer_3(baudrate); /* Set it */
811 /* reply to the request */
812 putpacket(remcomOutBuffer);
816 /* This function will generate a breakpoint exception. It is used at the
817 beginning of a program to sync up with a debugger and can be used
818 otherwise as a quick means to stop program execution and "break" into
827 asm(" .globl _breakinst