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