1 /* -*-C-*-
2 *******************************************************************************
3 *
4 * File:         pa_stub.c
5 * RCS:          $Header$
6 * Description:  main routines for PA RISC monitor stub
7 * Author:       Robert Quist
8 * Created:      Mon Nov  1 10:00:36 1993
9 * Modified:     Fri Nov 12 15:14:23 1993 (Robert Quist) quist@hpfcrdq
10 * Language:     C
11 * Package:      N/A
12 * Status:       Experimental (Do Not Distribute)
13 *
14 *******************************************************************************
15 */
16 
17 /****************************************************************************
18 
19 		THIS SOFTWARE IS NOT COPYRIGHTED
20 
21    HP offers the following for use in the public domain.  HP makes no
22    warranty with regard to the software or it's performance and the
23    user accepts the software "AS IS" with all faults.
24 
25    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
26    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 
29 ****************************************************************************/
30 
31 /****************************************************************************
32  *
33  *  Description:     low level support for gdb debugger. $
34  *
35  *  Considerations:  only works on target hardware $
36  *
37  *  NOTES:           See Below $
38  *
39  *    To enable debugger support, two things need to happen.
40  *
41  *  One, a call to set_debug_traps() is necessary in order to allow
42  *  any breakpoints or error conditions to be properly intercepted and
43  *  reported to gdb.
44  *
45  *  Two, a breakpoint needs to be generated to begin communication.
46  *  This is most easily accomplished by a call to breakpoint().
47  *  breakpoint() simulates a breakpoint
48 
49 
50  *************
51  *
52  *    The following gdb commands are supported:
53  *
54  * command          function                               Return value
55  *
56  *    g             return the value of the CPU registers  hex data or ENN
57  *    G             set the value of the CPU registers     OK or ENN
58  *
59  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
60  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
61  *
62  *    c             Resume at current address              SNN   ( signal NN)
63  *    cAA..AA       Continue at address AA..AA             SNN
64  *
65  *    s             Step one instruction                   SNN
66  *    sAA..AA       Step one instruction from AA..AA       SNN
67  *
68  *    k             kill
69  *
70  *    ?             What was the last sigval ?             SNN   (signal NN)
71  *
72  *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
73  *							   baud rate
74  *
75 
76  ************
77  * All commands and responses are sent with a packet which includes a
78  * checksum.  A packet consists of :
79  *
80  * $<packet info>#<checksum>.
81  *
82  * where
83  * <packet info> :: <characters representing the command or response>
84  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
85  *
86  * When a packet is received, it is first acknowledged with either '+' or '-'.
87  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
88  *
89  * Example:
90  *
91  * Host:                  Reply:
92  * $m0,10#2a               +$00010203040506070809101112131415#42
93  *
94  ****************************************************************************/
95 #include <signal.h>
96 #include "hppa-defs.h"
97 
98 /************************************************************************
99  *
100  * external low-level support
101  */
102 #define	OPT_PDC_CACHE	     5
103 #define	OPT_PDC_ADD_VALID   12
104 #define PGZ_MEM_PDC	0x0388	/* location of PDC_ENTRY in memory    */
105 #define CALL_PDC	(*(int (*)())((int *)(*((int *)PGZ_MEM_PDC))))
106 
107 extern putDebugChar();   /* write a single character      */
108 extern getDebugChar();   /* read and return a single char */
109 extern FICE();           /* flush i cache entry */
110 extern INLINE_BREAK();   /* break for user call */
111 
112 #define RADDR_ALIGN(s,r) (s = ((unsigned int *) ((((int) r ) + 7 ) & 0xFFFFFFF8)))
113 
114 /************************************************************************/
115 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
116 /* at least NUMREGBYTES*2 are needed for register packets */
117 
118 #define BUFMAX 2048
119 
120 #define NUMGPRS	  32
121 #define NUMSRS	   8
122 #define	NUMCRS	  32
123 #define	NUMSPCLS   3
124 #define	NUMFPRS	  32
125 
126 #define NUMGPRBYTES	4
127 #define NUMSRBYTES	4
128 #define	NUMCRBYTES	4
129 #define	NUMSPCLBYTES	4
130 #define NUMFPRBYTES	8
131 
132 /* Number of bytes of registers.  */
133 #define	NUMREGBYTES \
134 	(  (NUMGPRS * NUMGPRBYTES) \
135          + (NUMSRS * NUMSRBYTES)   \
136          + (NUMCRS * NUMCRBYTES)   \
137 	 + (NUMSPCLS * NUMSPCLBYTES) \
138 	 + (NUMFPRS * NUMFPRBYTES) \
139         )
140 
141 
142 enum regnames   {GR0,  GR1,  GR2,  GR3,  GR4,  GR5,  GR6,  GR7,
143 		 GR8,  GR9,  GR10, GR11, GR12, GR13, GR14, GR15,
144 		 GR16, GR17, GR18, GR19, GR20, GR21, GR22, GR23,
145 		 GR24, GR25, GR26, GR27, GR28, GR29, GR30, GR31,
146 
147                  SR0,  SR1,  SR2,  SR3,  SR4,  SR5,  SR6,  SR7,
148 
149                  CR0,  CR1,  CR2,  CR3,  CR4,  CR5,  CR6,  CR7,
150 		 CR8,  CR9,  CR10, CR11, CR12, CR13, CR14, CR15,
151 		 CR16, CR17H,CR18H,CR19, CR20, CR21, CR22, CR23,
152 		 CR24, CR25, CR26, CR27, CR28, CR29, CR30, CR31,
153 
154                  CR17T,CR18T,CPUD0 };
155 
156 enum fregnames  {FPR0,  FPR1,  FPR2,  FPR3,  FPR4,  FPR5,  FPR6,  FPR7,
157 		 FPR8,  FPR9,  FPR10, FPR11, FPR12, FPR13, FPR14, FPR15,
158 		 FPR16, FPR17, FPR18, FPR19, FPR20, FPR21, FPR22, FPR23,
159 		 FPR24, FPR25, FPR26, FPR27, FPR28, FPR29, FPR30, FPR31 };
160 
161 #define PC  CR18H
162 #define NPC CR18T
163 #define SP  GR30
164 
165 struct registers {
166        int intregs[NUMGPRS + NUMSRS + NUMCRS + NUMSPCLS];
167        int fpregs [NUMFPRS * 2];
168                  };
169 /* Global Variables */
170 
171 static int initialized = 0;	/* !0 means we've been initialized */
172 static unsigned char hexchars[]="0123456789abcdef";
173 static unsigned char remcomInBuffer[BUFMAX];
174 static unsigned char remcomOutBuffer[BUFMAX];
175 static unsigned int  i_cache_params[6];
176 
177 /* This table contains the mapping between PA hardware exception
178    types, and signals, which are primarily what GDB understands.  It also
179    indicates which hardware traps we need to commandeer when initializing
180    the stub.
181 
182    The only two currently used are Recovery counter (single stepping)
183    and Break trap ( break points ).
184 */
185 
186 static struct hard_trap_info
187 {
188   unsigned char tt;		/* Trap number for PA-RISC */
189   unsigned char signo;		/* Signal that we map this trap into */
190 } hard_trap_info[] = {
191 /* 1  High priority machine check */
192 /* 2  Power failure interrupt*/
193 /* 3  Recovery counter -- init */
194 /* 4  External interrupt */
195 /* 5  Low priority machine check */
196   {6, SIGSEGV},			/* Instruction TLB miss/page fault */
197   {7, SIGSEGV},			/* Memory protection */
198   {8, SIGILL},			/* Illegal instruction */
199   {9, SIGTRAP},			/* Break instruction -- init */
200   {10,SIGILL},			/* Privileged instruction */
201   {11,SIGILL},			/* Privileged register */
202   {12,SIGUSR1},			/* Overflow */
203   {13,SIGUSR2},			/* Conditional */
204   {14,SIGEMT},			/* Assist Exception */
205   {15,SIGSEGV},			/* Data TLB miss/page fault */
206   {16,SIGSEGV},			/* Non-access Instruction TLB miss */
207   {17,SIGSEGV},			/* Non-access Data TLB miss/page fault */
208   {18,SIGSEGV},			/* Data memory protection/ unaligned data reference */
209   {19,SIGTRAP},			/* Data memory break */
210   {20,SIGSEGV},			/* TLB dirty bit */
211   {21,SIGSEGV},			/* Page reference */
212   {22,SIGEMT},			/* Assist emulation */
213   {23,SIGILL},			/* Higher-privilege */
214   {24,SIGILL},			/* Lower-privilege */
215   {25,SIGTRAP},			/* Taken branch */
216   {0, 0}			/* Must be last */
217 };
218 
219 /* Functions */
220 /*========================================================================== */
221 
222 /* Convert ch from a hex digit to an int */
223 
224 static int
hex(ch)225 hex(ch)
226      unsigned char ch;
227 {
228   if (ch >= 'a' && ch <= 'f')
229     return ch-'a'+10;
230   if (ch >= '0' && ch <= '9')
231     return ch-'0';
232   if (ch >= 'A' && ch <= 'F')
233     return ch-'A'+10;
234   return -1;
235 }
236 
237 /* scan for the sequence $<data>#<checksum>     */
238 
239 static void
getpacket(buffer)240 getpacket(buffer)
241      char *buffer;
242 {
243   unsigned char checksum;
244   unsigned char xmitcsum;
245   int i;
246   int count;
247   unsigned char ch;
248 
249   do
250     {
251       /* wait around for the start character, ignore all other characters */
252       strobe();
253       while ((ch = getDebugChar()) != '$') ;
254 
255       checksum = 0;
256       xmitcsum = -1;
257 
258       count = 0;
259 
260       /* now, read until a # or end of buffer is found */
261       while (count < BUFMAX)
262 	{
263 	  ch = getDebugChar();
264 	  if (ch == '#')
265 	    break;
266 	  checksum = checksum + ch;
267 	  buffer[count] = ch;
268 	  count = count + 1;
269 	}
270 
271       if (count >= BUFMAX)
272 	continue;
273 
274       buffer[count] = 0;
275 
276       if (ch == '#')
277 	{
278 	  xmitcsum = hex(getDebugChar()) << 4;
279 	  xmitcsum |= hex(getDebugChar());
280 
281 #if TESTING
282 	  /* Humans shouldn't have to figure out checksums to type to it. */
283 	  putDebugChar ('+');
284 	  return;
285 #endif
286 	  if (checksum != xmitcsum)
287 	    putDebugChar('-');	/* failed checksum */
288 	  else
289 	    {
290 	      putDebugChar('+'); /* successful transfer */
291 	      /* if a sequence char is present, reply the sequence ID */
292 	      if (buffer[2] == ':')
293 		{
294 		  putDebugChar(buffer[0]);
295 		  putDebugChar(buffer[1]);
296 		  /* remove sequence chars from buffer */
297 		  count = strlen(buffer);
298 		  for (i=3; i <= count; i++)
299 		    buffer[i-3] = buffer[i];
300 		}
301 	    }
302 	}
303     }
304   while (checksum != xmitcsum);
305 }
306 
307 /* send the packet in buffer.  */
308 
309 static void
putpacket(buffer)310 putpacket(buffer)
311      unsigned char *buffer;
312 {
313   unsigned char checksum;
314   int count;
315   unsigned char ch;
316 
317   /*  $<packet info>#<checksum>. */
318 
319   do
320     {
321       putDebugChar('$');
322       checksum = 0;
323       count = 0;
324 
325       while (ch = buffer[count])
326 	{
327 	  if (! putDebugChar(ch))
328 	    return;
329 	  checksum += ch;
330 	  count += 1;
331 	}
332 
333       putDebugChar('#');
334       putDebugChar(hexchars[checksum >> 4]);
335       putDebugChar(hexchars[checksum & 0xf]);
336       } while (getDebugChar() != '+');
337 }
338 
339 /* Convert the memory pointed to by mem into hex, placing result in buf.
340  * Return a pointer to the last char put in buf (null), in case of mem fault,
341  * return 0.
342  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
343  * a 0, else treat a fault like any other fault in the stub.
344  */
345 
346 static unsigned char *
mem2hex(mem,buf,count,may_fault)347 mem2hex(mem, buf, count, may_fault)
348      unsigned char *mem;
349      unsigned char *buf;
350      int count;
351      int may_fault;
352 {
353   unsigned char ch;
354   int           check_addr,
355                 new_addr;
356 
357   check_addr = 0;
358 
359   while (count-- > 0)
360     {
361       if (may_fault)
362       { new_addr = ((int) (mem+3)) & 0xFFFFFFF8;
363         if (new_addr != check_addr)
364         { check_addr = new_addr;
365           if (pdc_call(OPT_PDC_ADD_VALID,0,check_addr)) return 0;
366         }
367       }
368       ch = *mem++;
369       *buf++ = hexchars[ch >> 4];
370       *buf++ = hexchars[ch & 0xf];
371     }
372 
373   *buf = 0;
374 
375   return buf;
376 }
377 
378 /* convert the hex array pointed to by buf into binary to be placed in mem
379  * return a pointer to the character AFTER the last byte written */
380 
381 static unsigned char *
hex2mem(buf,mem,count,may_fault)382 hex2mem(buf, mem, count, may_fault)
383      unsigned char *buf;
384      unsigned char *mem;
385      int count;
386      int may_fault;
387 {
388   int          i;
389   unsigned int ch;
390   int          check_addr,
391                new_addr;
392 
393   check_addr = 0;
394 
395   for (i=0; i<count; i++)
396     {
397       ch = hex(*buf++) << 4;
398       ch |= hex(*buf++);
399       if (may_fault)
400       { new_addr = ((int)(mem+3)) & 0xFFFFFFF8;
401         if (new_addr != check_addr)
402         { check_addr = new_addr;
403           if (pdc_call(OPT_PDC_ADD_VALID,0,check_addr)) return 0;
404         }
405       }
406       *mem++ = ch;
407     }
408 
409   return mem;
410 }
411 
412 /* Set up exception handlers for traceing and breakpoints */
413 
414 void
set_debug_traps()415 set_debug_traps()
416 {
417   unsigned int	R_addr[33];
418   unsigned int	*Raddr_ptr;
419 
420   setup_vectors();
421 
422   /* get cache params for use by flush_i_cache */
423   RADDR_ALIGN(Raddr_ptr,R_addr);
424 
425   if (pdc_call(OPT_PDC_CACHE,0,Raddr_ptr,0))
426     i_cache_params[0] = -1;
427   else
428     i_cache_params[0] = R_addr[0];
429 
430   i_cache_params[1] = Raddr_ptr[1];
431   i_cache_params[2] = Raddr_ptr[2];
432   i_cache_params[3] = Raddr_ptr[3];
433   i_cache_params[4] = Raddr_ptr[4];
434   i_cache_params[5] = Raddr_ptr[5];
435 
436   /* In case GDB is started before us, ack any packets (presumably
437      "$?#xx") sitting there.  */
438 
439   putDebugChar ('+');
440 
441   initialized = 1;
442 }
443 
444 
445 /* Convert the PA-RISC hardware trap number to a unix signal number. */
446 
447 static int
computeSignal(tt)448 computeSignal(tt)
449      int tt;
450 {
451   struct hard_trap_info *ht;
452 
453   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
454     if (ht->tt == tt)
455       return ht->signo;
456 
457   return SIGHUP;		/* default for things we don't know about */
458 }
459 
460 /*
461  * While we find nice hex chars, build an int.
462  * Return number of chars processed.
463  */
464 
465 static int
hexToInt(ptr,intValue)466 hexToInt(ptr, intValue)
467      unsigned char **ptr;
468      int *intValue;
469 {
470   int numChars = 0;
471   int hexValue;
472 
473   *intValue = 0;
474 
475   while (**ptr)
476     {
477       hexValue = hex(**ptr);
478       if (hexValue < 0)
479 	break;
480 
481       *intValue = (*intValue << 4) | hexValue;
482       numChars ++;
483 
484       (*ptr)++;
485     }
486 
487   return (numChars);
488 }
489 
490 void
flush_i_cache()491 flush_i_cache()
492 
493 {
494   unsigned int addr,count,loop;
495 
496   if (i_cache_params[0] <= 0) return;
497 
498   addr = i_cache_params[2];
499   for (count = 0; count < i_cache_params[4]; count++)
500     { for ( loop = 0; loop < i_cache_params[5]; loop++) FICE(addr);
501       addr = addr + i_cache_params[3];
502     }
503 }
504 
505 /*
506  * This function does all command procesing for interfacing to gdb.
507    return of 0 will execute DEBUG_GO (continue)
508    return of 1 will execute DEBUG_SS (single step)
509  */
510 
511 int
handle_exception(registers,tt)512 handle_exception (registers,tt)
513   unsigned long *registers;
514   int  tt;			/* Trap type */
515 {
516   int sigval;
517   int addr;
518   int length;
519   unsigned char *ptr;
520 
521   /* reply to host that an exception has occurred */
522   sigval = computeSignal(tt);
523   ptr = remcomOutBuffer;
524 
525   *ptr++ = 'T';
526   *ptr++ = hexchars[sigval >> 4];
527   *ptr++ = hexchars[sigval & 0xf];
528 
529 /* could be lots of stuff here like PC and SP registers */
530 
531   *ptr++ = 0;
532 
533   putpacket(remcomOutBuffer);
534 
535   while (1)
536     {
537       remcomOutBuffer[0] = 0;
538 
539       getpacket(remcomInBuffer);
540       switch (remcomInBuffer[0])
541 	{
542 	case '?':
543 	  remcomOutBuffer[0] = 'S';
544 	  remcomOutBuffer[1] = hexchars[sigval >> 4];
545 	  remcomOutBuffer[2] = hexchars[sigval & 0xf];
546 	  remcomOutBuffer[3] = 0;
547 	  break;
548 
549 	case 'd':
550 	  /* toggle debug flag */
551 	  led_putnum (16);
552 	  break;
553 
554 	case 'g':		/* return the value of the CPU registers */
555 	  {
556 	    ptr = remcomOutBuffer;
557             /* GR0..GR31 SR0..SR7 CR0..CR31 specials */
558 	    ptr = mem2hex((char *)registers, ptr, NUMREGBYTES, 0);
559             /* need to add floating point registers */
560 	  }
561 	  break;
562 
563 	case 'G':	   /* set the value of the CPU registers - return OK */
564 	  {
565 	    ptr = &remcomInBuffer[1];
566             /* GR0..GR31 SR0..SR7 CR0..CR31 specials */
567 	    hex2mem(ptr, (char *)registers, NUMREGBYTES, 0);
568 	    strcpy(remcomOutBuffer,"OK 1");
569 	  }
570 	  break;
571 
572 	case 'm':	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
573 	  /* Try to read %x,%x.  */
574 
575 	  ptr = &remcomInBuffer[1];
576 
577 	  if (hexToInt(&ptr, &addr)
578 	      && *ptr++ == ','
579 	      && hexToInt(&ptr, &length))
580 	    {
581 	      if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
582 		break;
583 
584 	      strcpy (remcomOutBuffer, "E03");
585 	    }
586 	  else
587 	    strcpy(remcomOutBuffer,"E01");
588 	  break;
589 
590 	case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
591 	  /* Try to read '%x,%x:'.  */
592 
593 	  ptr = &remcomInBuffer[1];
594 
595 	  if (hexToInt(&ptr, &addr)
596 	      && *ptr++ == ','
597 	      && hexToInt(&ptr, &length)
598 	      && *ptr++ == ':')
599 	    {
600 	      if (hex2mem(ptr, (char *)addr, length, 1))
601 		strcpy(remcomOutBuffer, "OK");
602 	      else
603 		strcpy(remcomOutBuffer, "E03");
604 	    }
605 	  else
606 	    strcpy(remcomOutBuffer, "E02");
607 	  break;
608 
609 	case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
610 	  /* try to read optional parameter, pc unchanged if no parm */
611 
612 	  ptr = &remcomInBuffer[1];
613 	  if (hexToInt(&ptr, &addr))
614 	    {
615 	      registers[PC] = addr;
616 	      registers[NPC] = addr + 4;
617 	    }
618 
619 /* Need to flush the instruction cache here, as we may have deposited a
620    breakpoint, and the icache probably has no way of knowing that a data ref to
621    some location may have changed something that is in the instruction cache.
622  */
623 
624 	  flush_i_cache();
625 	  return 0;		/* execute GO */
626 
627 	  /* kill the program */
628 	case 'k' :		/* do nothing */
629 	  break;
630 
631         case 's' :              /* single step */
632 	  /* try to read optional parameter, pc unchanged if no parm */
633 
634 	  ptr = &remcomInBuffer[1];
635 	  if (hexToInt(&ptr, &addr))
636 	    {
637 	      registers[PC] = addr;
638 	      registers[NPC] = addr + 4;
639 	    }
640 /* Need to flush the instruction cache here, as we may have deposited a
641    breakpoint, and the icache probably has no way of knowing that a data ref to
642    some location may have changed something that is in the instruction cache.
643  */
644 	  flush_i_cache();
645 	  return 1;		/* execute Single Step */
646           break;
647 
648 #if TESTING1
649 	case 't':		/* Test feature */
650 	  break;
651 #endif
652 	case 'r':		/* Reset */
653 	  break;
654 
655 #if TESTING2
656 Disabled until we can unscrew this properly
657 
658 	case 'b':	  /* bBB...  Set baud rate to BB... */
659 	  {
660 	    int baudrate;
661 	    extern void set_timer_3();
662 
663 	    ptr = &remcomInBuffer[1];
664 	    if (!hexToInt(&ptr, &baudrate))
665 	      {
666 		strcpy(remcomOutBuffer,"B01");
667 		break;
668 	      }
669 
670 	    /* Convert baud rate to uart clock divider */
671 	    switch (baudrate)
672 	      {
673 	      case 38400:
674 		baudrate = 16;
675 		break;
676 	      case 19200:
677 		baudrate = 33;
678 		break;
679 	      case 9600:
680 		baudrate = 65;
681 		break;
682 	      default:
683 		strcpy(remcomOutBuffer,"B02");
684 		goto x1;
685 	      }
686 
687 	    putpacket("OK 2");	/* Ack before changing speed */
688 	    set_timer_3(baudrate); /* Set it */
689 	  }
690 x1:	  break;
691 #endif
692 	}			/* switch */
693 
694       /* reply to the request */
695       putpacket(remcomOutBuffer);
696     }
697   print ("\r\nEscaped handle_exception\r\n");
698 }
699