source: trunk/libs/newlib/src/libgloss/hp74x/pa_stub.c @ 458

Last change on this file since 458 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 17.4 KB
Line 
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
107extern putDebugChar();   /* write a single character      */
108extern getDebugChar();   /* read and return a single char */
109extern FICE();           /* flush i cache entry */
110extern 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
142enum 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
156enum 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               
165struct registers {
166       int intregs[NUMGPRS + NUMSRS + NUMCRS + NUMSPCLS];
167       int fpregs [NUMFPRS * 2];
168                 };   
169/* Global Variables */
170
171static int initialized = 0;     /* !0 means we've been initialized */
172static unsigned char hexchars[]="0123456789abcdef";
173static unsigned char remcomInBuffer[BUFMAX];
174static unsigned char remcomOutBuffer[BUFMAX];
175static 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
186static 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
224static int
225hex(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
239static void
240getpacket(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
309static void
310putpacket(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
346static unsigned char *
347mem2hex(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
381static unsigned char *
382hex2mem(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
414void
415set_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
447static int
448computeSignal(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
465static int
466hexToInt(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
490void
491flush_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
511int
512handle_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
656Disabled 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          }
690x1:       break;
691#endif
692        }                       /* switch */
693
694      /* reply to the request */
695      putpacket(remcomOutBuffer);
696    }
697  print ("\r\nEscaped handle_exception\r\n");
698}
Note: See TracBrowser for help on using the repository browser.