* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / arch / sparc / kernel / sparc-stub.c
blob8cd0e8b6d3f48021ef3af87c52eac83249596418
1 /* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $
2 * sparc-stub.c: KGDB support for the Linux kernel.
4 * Modifications to run under Linux
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
7 * This file originally came from the gdb sources, and the
8 * copyright notices have been retained below.
9 */
11 /****************************************************************************
13 THIS SOFTWARE IS NOT COPYRIGHTED
15 HP offers the following for use in the public domain. HP makes no
16 warranty with regard to the software or its performance and the
17 user accepts the software "AS IS" with all faults.
19 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
20 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 ****************************************************************************/
25 /****************************************************************************
26 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
28 * Module name: remcom.c $
29 * Revision: 1.34 $
30 * Date: 91/03/09 12:29:49 $
31 * Contributor: Lake Stevens Instrument Division$
33 * Description: low level support for gdb debugger. $
35 * Considerations: only works on target hardware $
37 * Written by: Glenn Engel $
38 * ModuleState: Experimental $
40 * NOTES: See Below $
42 * Modified for SPARC by Stu Grossman, Cygnus Support.
44 * This code has been extensively tested on the Fujitsu SPARClite demo board.
46 * To enable debugger support, two things need to happen. One, a
47 * call to set_debug_traps() is necessary in order to allow any breakpoints
48 * or error conditions to be properly intercepted and reported to gdb.
49 * Two, a breakpoint needs to be generated to begin communication. This
50 * is most easily accomplished by a call to breakpoint(). Breakpoint()
51 * simulates a breakpoint by executing a trap #1.
53 *************
55 * The following gdb commands are supported:
57 * command function Return value
59 * g return the value of the CPU registers hex data or ENN
60 * G set the value of the CPU registers OK or ENN
62 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
63 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
65 * c Resume at current address SNN ( signal NN)
66 * cAA..AA Continue at address AA..AA SNN
68 * s Step one instruction SNN
69 * sAA..AA Step one instruction from AA..AA SNN
71 * k kill
73 * ? What was the last sigval ? SNN (signal NN)
75 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
76 * baud rate
78 * All commands and responses are sent with a packet which includes a
79 * checksum. A packet consists of
81 * $<packet info>#<checksum>.
83 * where
84 * <packet info> :: <characters representing the command or response>
85 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
87 * When a packet is received, it is first acknowledged with either '+' or '-'.
88 * '+' indicates a successful transfer. '-' indicates a failed transfer.
90 * Example:
92 * Host: Reply:
93 * $m0,10#2a +$00010203040506070809101112131415#42
95 ****************************************************************************/
97 #include <linux/kernel.h>
98 #include <linux/string.h>
99 #include <linux/mm.h>
100 #include <linux/smp.h>
101 #include <linux/smp_lock.h>
103 #include <asm/system.h>
104 #include <asm/signal.h>
105 #include <asm/oplib.h>
106 #include <asm/head.h>
107 #include <asm/traps.h>
108 #include <asm/vac-ops.h>
109 #include <asm/kgdb.h>
110 #include <asm/pgtable.h>
113 * external low-level support routines
116 extern void putDebugChar(char); /* write a single character */
117 extern char getDebugChar(void); /* read and return a single char */
120 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
121 * at least NUMREGBYTES*2 are needed for register packets
123 #define BUFMAX 2048
125 static int initialized = 0; /* !0 means we've been initialized */
127 static const char hexchars[]="0123456789abcdef";
129 #define NUMREGS 72
131 /* Number of bytes of registers. */
132 #define NUMREGBYTES (NUMREGS * 4)
133 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
134 O0, O1, O2, O3, O4, O5, SP, O7,
135 L0, L1, L2, L3, L4, L5, L6, L7,
136 I0, I1, I2, I3, I4, I5, FP, I7,
138 F0, F1, F2, F3, F4, F5, F6, F7,
139 F8, F9, F10, F11, F12, F13, F14, F15,
140 F16, F17, F18, F19, F20, F21, F22, F23,
141 F24, F25, F26, F27, F28, F29, F30, F31,
142 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
145 extern void trap_low(void); /* In arch/sparc/kernel/entry.S */
147 unsigned long get_sun4cpte(unsigned long addr)
149 unsigned long entry;
151 __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" :
152 "=r" (entry) :
153 "r" (addr), "i" (ASI_PTE));
154 return entry;
157 unsigned long get_sun4csegmap(unsigned long addr)
159 unsigned long entry;
161 __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
162 "=r" (entry) :
163 "r" (addr), "i" (ASI_SEGMAP));
164 return entry;
167 #if 0
168 /* Have to sort this out. This cannot be done after initialization. */
169 static void flush_cache_all_nop(void) {}
170 #endif
172 /* Place where we save old trap entries for restoration */
173 struct tt_entry kgdb_savettable[256];
174 typedef void (*trapfunc_t)(void);
176 /* Helper routine for manipulation of kgdb_savettable */
177 static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest)
179 dest->inst_one = src->inst_one;
180 dest->inst_two = src->inst_two;
181 dest->inst_three = src->inst_three;
182 dest->inst_four = src->inst_four;
185 /* Initialize the kgdb_savettable so that debugging can commence */
186 static void eh_init(void)
188 int i, flags;
190 save_and_cli(flags);
191 for(i=0; i < 256; i++)
192 copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]);
193 restore_flags(flags);
196 /* Install an exception handler for kgdb */
197 static void exceptionHandler(int tnum, trapfunc_t trap_entry)
199 unsigned long te_addr = (unsigned long) trap_entry;
200 int flags;
202 /* We are dorking with a live trap table, all irqs off */
203 save_and_cli(flags);
205 /* Make new vector */
206 sparc_ttable[tnum].inst_one =
207 SPARC_BRANCH((unsigned long) te_addr,
208 (unsigned long) &sparc_ttable[tnum].inst_one);
209 sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0;
210 sparc_ttable[tnum].inst_three = SPARC_NOP;
211 sparc_ttable[tnum].inst_four = SPARC_NOP;
213 restore_flags(flags);
216 /* Convert ch from a hex digit to an int */
217 static int
218 hex(unsigned char ch)
220 if (ch >= 'a' && ch <= 'f')
221 return ch-'a'+10;
222 if (ch >= '0' && ch <= '9')
223 return ch-'0';
224 if (ch >= 'A' && ch <= 'F')
225 return ch-'A'+10;
226 return -1;
229 /* scan for the sequence $<data>#<checksum> */
230 static void
231 getpacket(char *buffer)
233 unsigned char checksum;
234 unsigned char xmitcsum;
235 int i;
236 int count;
237 unsigned char ch;
239 do {
240 /* wait around for the start character, ignore all other characters */
241 while ((ch = (getDebugChar() & 0x7f)) != '$') ;
243 checksum = 0;
244 xmitcsum = -1;
246 count = 0;
248 /* now, read until a # or end of buffer is found */
249 while (count < BUFMAX) {
250 ch = getDebugChar() & 0x7f;
251 if (ch == '#')
252 break;
253 checksum = checksum + ch;
254 buffer[count] = ch;
255 count = count + 1;
258 if (count >= BUFMAX)
259 continue;
261 buffer[count] = 0;
263 if (ch == '#') {
264 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
265 xmitcsum |= hex(getDebugChar() & 0x7f);
266 if (checksum != xmitcsum)
267 putDebugChar('-'); /* failed checksum */
268 else {
269 putDebugChar('+'); /* successful transfer */
270 /* if a sequence char is present, reply the ID */
271 if (buffer[2] == ':') {
272 putDebugChar(buffer[0]);
273 putDebugChar(buffer[1]);
274 /* remove sequence chars from buffer */
275 count = strlen(buffer);
276 for (i=3; i <= count; i++)
277 buffer[i-3] = buffer[i];
281 } while (checksum != xmitcsum);
284 /* send the packet in buffer. */
286 static void
287 putpacket(unsigned char *buffer)
289 unsigned char checksum;
290 int count;
291 unsigned char ch, recv;
293 /* $<packet info>#<checksum>. */
294 do {
295 putDebugChar('$');
296 checksum = 0;
297 count = 0;
299 while ((ch = buffer[count])) {
300 putDebugChar(ch);
301 checksum += ch;
302 count += 1;
305 putDebugChar('#');
306 putDebugChar(hexchars[checksum >> 4]);
307 putDebugChar(hexchars[checksum & 0xf]);
308 recv = getDebugChar();
309 } while ((recv & 0x7f) != '+');
312 static char remcomInBuffer[BUFMAX];
313 static char remcomOutBuffer[BUFMAX];
315 /* Convert the memory pointed to by mem into hex, placing result in buf.
316 * Return a pointer to the last char put in buf (null), in case of mem fault,
317 * return 0.
320 static unsigned char *
321 mem2hex(char *mem, char *buf, int count)
323 unsigned char ch;
325 while (count-- > 0) {
326 /* This assembler code is basically: ch = *mem++;
327 * except that we use the SPARC/Linux exception table
328 * mechanism (see how "fixup" works in kernel_mna_trap_fault)
329 * to arrange for a "return 0" upon a memory fault
331 __asm__(
332 "1: ldub [%0], %1
333 inc %0
334 .section .fixup,#alloc,#execinstr
335 .align 4
336 2: retl
337 mov 0, %%o0
338 .section __ex_table, #alloc
339 .align 4
340 .word 1b, 2b
341 .text"
342 : "=r" (mem), "=r" (ch) : "0" (mem));
343 *buf++ = hexchars[ch >> 4];
344 *buf++ = hexchars[ch & 0xf];
347 *buf = 0;
348 return buf;
351 /* convert the hex array pointed to by buf into binary to be placed in mem
352 * return a pointer to the character AFTER the last byte written.
354 static char *
355 hex2mem(char *buf, char *mem, int count)
357 int i;
358 unsigned char ch;
360 for (i=0; i<count; i++) {
362 ch = hex(*buf++) << 4;
363 ch |= hex(*buf++);
364 /* Assembler code is *mem++ = ch; with return 0 on fault */
365 __asm__(
366 "1: stb %1, [%0]
367 inc %0
368 .section .fixup,#alloc,#execinstr
369 .align 4
370 2: retl
371 mov 0, %%o0
372 .section __ex_table, #alloc
373 .align 4
374 .word 1b, 2b
375 .text"
376 : "=r" (mem) : "r" (ch) , "0" (mem));
378 return mem;
381 /* This table contains the mapping between SPARC hardware trap types, and
382 signals, which are primarily what GDB understands. It also indicates
383 which hardware traps we need to commandeer when initializing the stub. */
385 static struct hard_trap_info
387 unsigned char tt; /* Trap type code for SPARC */
388 unsigned char signo; /* Signal that we map this trap into */
389 } hard_trap_info[] = {
390 {SP_TRAP_SBPT, SIGTRAP}, /* ta 1 - Linux/KGDB software breakpoint */
391 {0, 0} /* Must be last */
394 /* Set up exception handlers for tracing and breakpoints */
396 void
397 set_debug_traps(void)
399 struct hard_trap_info *ht;
400 unsigned long flags;
402 save_and_cli(flags);
403 #if 0
404 /* Have to sort this out. This cannot be done after initialization. */
405 BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
406 #endif
408 /* Initialize our copy of the Linux Sparc trap table */
409 eh_init();
411 for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
412 /* Only if it doesn't destroy our fault handlers */
413 if((ht->tt != SP_TRAP_TFLT) &&
414 (ht->tt != SP_TRAP_DFLT))
415 exceptionHandler(ht->tt, trap_low);
418 /* In case GDB is started before us, ack any packets (presumably
419 * "$?#xx") sitting there.
421 * I've found this code causes more problems than it solves,
422 * so that's why it's commented out. GDB seems to work fine
423 * now starting either before or after the kernel -bwb
425 #if 0
426 while((c = getDebugChar()) != '$');
427 while((c = getDebugChar()) != '#');
428 c = getDebugChar(); /* eat first csum byte */
429 c = getDebugChar(); /* eat second csum byte */
430 putDebugChar('+'); /* ack it */
431 #endif
433 initialized = 1; /* connect! */
434 restore_flags(flags);
437 /* Convert the SPARC hardware trap type code to a unix signal number. */
439 static int
440 computeSignal(int tt)
442 struct hard_trap_info *ht;
444 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
445 if (ht->tt == tt)
446 return ht->signo;
448 return SIGHUP; /* default for things we don't know about */
452 * While we find nice hex chars, build an int.
453 * Return number of chars processed.
456 static int
457 hexToInt(char **ptr, int *intValue)
459 int numChars = 0;
460 int hexValue;
462 *intValue = 0;
464 while (**ptr) {
465 hexValue = hex(**ptr);
466 if (hexValue < 0)
467 break;
469 *intValue = (*intValue << 4) | hexValue;
470 numChars ++;
472 (*ptr)++;
475 return (numChars);
479 * This function does all command processing for interfacing to gdb. It
480 * returns 1 if you should skip the instruction at the trap address, 0
481 * otherwise.
484 extern void breakinst(void);
486 void
487 handle_exception (unsigned long *registers)
489 int tt; /* Trap type */
490 int sigval;
491 int addr;
492 int length;
493 char *ptr;
494 unsigned long *sp;
496 /* First, we must force all of the windows to be spilled out */
498 asm("save %sp, -64, %sp\n\t"
499 "save %sp, -64, %sp\n\t"
500 "save %sp, -64, %sp\n\t"
501 "save %sp, -64, %sp\n\t"
502 "save %sp, -64, %sp\n\t"
503 "save %sp, -64, %sp\n\t"
504 "save %sp, -64, %sp\n\t"
505 "save %sp, -64, %sp\n\t"
506 "restore\n\t"
507 "restore\n\t"
508 "restore\n\t"
509 "restore\n\t"
510 "restore\n\t"
511 "restore\n\t"
512 "restore\n\t"
513 "restore\n\t");
515 lock_kernel();
516 if (registers[PC] == (unsigned long)breakinst) {
517 /* Skip over breakpoint trap insn */
518 registers[PC] = registers[NPC];
519 registers[NPC] += 4;
522 sp = (unsigned long *)registers[SP];
524 tt = (registers[TBR] >> 4) & 0xff;
526 /* reply to host that an exception has occurred */
527 sigval = computeSignal(tt);
528 ptr = remcomOutBuffer;
530 *ptr++ = 'T';
531 *ptr++ = hexchars[sigval >> 4];
532 *ptr++ = hexchars[sigval & 0xf];
534 *ptr++ = hexchars[PC >> 4];
535 *ptr++ = hexchars[PC & 0xf];
536 *ptr++ = ':';
537 ptr = mem2hex((char *)&registers[PC], ptr, 4);
538 *ptr++ = ';';
540 *ptr++ = hexchars[FP >> 4];
541 *ptr++ = hexchars[FP & 0xf];
542 *ptr++ = ':';
543 ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */
544 *ptr++ = ';';
546 *ptr++ = hexchars[SP >> 4];
547 *ptr++ = hexchars[SP & 0xf];
548 *ptr++ = ':';
549 ptr = mem2hex((char *)&sp, ptr, 4);
550 *ptr++ = ';';
552 *ptr++ = hexchars[NPC >> 4];
553 *ptr++ = hexchars[NPC & 0xf];
554 *ptr++ = ':';
555 ptr = mem2hex((char *)&registers[NPC], ptr, 4);
556 *ptr++ = ';';
558 *ptr++ = hexchars[O7 >> 4];
559 *ptr++ = hexchars[O7 & 0xf];
560 *ptr++ = ':';
561 ptr = mem2hex((char *)&registers[O7], ptr, 4);
562 *ptr++ = ';';
564 *ptr++ = 0;
566 putpacket(remcomOutBuffer);
568 /* XXX We may want to add some features dealing with poking the
569 * XXX page tables, the real ones on the srmmu, and what is currently
570 * XXX loaded in the sun4/sun4c tlb at this point in time. But this
571 * XXX also required hacking to the gdb sources directly...
574 while (1) {
575 remcomOutBuffer[0] = 0;
577 getpacket(remcomInBuffer);
578 switch (remcomInBuffer[0]) {
579 case '?':
580 remcomOutBuffer[0] = 'S';
581 remcomOutBuffer[1] = hexchars[sigval >> 4];
582 remcomOutBuffer[2] = hexchars[sigval & 0xf];
583 remcomOutBuffer[3] = 0;
584 break;
586 case 'd':
587 /* toggle debug flag */
588 break;
590 case 'g': /* return the value of the CPU registers */
592 ptr = remcomOutBuffer;
593 /* G & O regs */
594 ptr = mem2hex((char *)registers, ptr, 16 * 4);
595 /* L & I regs */
596 ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4);
597 /* Floating point */
598 memset(ptr, '0', 32 * 8);
599 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
600 mem2hex((char *)&registers[Y], (ptr + 32 * 4 * 2), (8 * 4));
602 break;
604 case 'G': /* set the value of the CPU registers - return OK */
606 unsigned long *newsp, psr;
608 psr = registers[PSR];
610 ptr = &remcomInBuffer[1];
611 /* G & O regs */
612 hex2mem(ptr, (char *)registers, 16 * 4);
613 /* L & I regs */
614 hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4);
615 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
616 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y], 8 * 4);
618 /* See if the stack pointer has moved. If so,
619 * then copy the saved locals and ins to the
620 * new location. This keeps the window
621 * overflow and underflow routines happy.
624 newsp = (unsigned long *)registers[SP];
625 if (sp != newsp)
626 sp = memcpy(newsp, sp, 16 * 4);
628 /* Don't allow CWP to be modified. */
630 if (psr != registers[PSR])
631 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
633 strcpy(remcomOutBuffer,"OK");
635 break;
637 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
638 /* Try to read %x,%x. */
640 ptr = &remcomInBuffer[1];
642 if (hexToInt(&ptr, &addr)
643 && *ptr++ == ','
644 && hexToInt(&ptr, &length)) {
645 if (mem2hex((char *)addr, remcomOutBuffer, length))
646 break;
648 strcpy (remcomOutBuffer, "E03");
649 } else {
650 strcpy(remcomOutBuffer,"E01");
652 break;
654 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
655 /* Try to read '%x,%x:'. */
657 ptr = &remcomInBuffer[1];
659 if (hexToInt(&ptr, &addr)
660 && *ptr++ == ','
661 && hexToInt(&ptr, &length)
662 && *ptr++ == ':') {
663 if (hex2mem(ptr, (char *)addr, length)) {
664 strcpy(remcomOutBuffer, "OK");
665 } else {
666 strcpy(remcomOutBuffer, "E03");
668 } else {
669 strcpy(remcomOutBuffer, "E02");
671 break;
673 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
674 /* try to read optional parameter, pc unchanged if no parm */
676 ptr = &remcomInBuffer[1];
677 if (hexToInt(&ptr, &addr)) {
678 registers[PC] = addr;
679 registers[NPC] = addr + 4;
682 /* Need to flush the instruction cache here, as we may have deposited a
683 * breakpoint, and the icache probably has no way of knowing that a data ref to
684 * some location may have changed something that is in the instruction cache.
686 flush_cache_all();
687 unlock_kernel();
688 return;
690 /* kill the program */
691 case 'k' : /* do nothing */
692 break;
693 case 'r': /* Reset */
694 asm ("call 0\n\t"
695 "nop\n\t");
696 break;
697 } /* switch */
699 /* reply to the request */
700 putpacket(remcomOutBuffer);
701 } /* while(1) */
704 /* This function will generate a breakpoint exception. It is used at the
705 beginning of a program to sync up with a debugger and can be used
706 otherwise as a quick means to stop program execution and "break" into
707 the debugger. */
709 void
710 breakpoint(void)
712 if (!initialized)
713 return;
715 /* Again, watch those c-prefixes for ELF kernels */
716 #if defined(__svr4__) || defined(__ELF__)
717 asm(" .globl breakinst
719 breakinst: ta 1
721 #else
722 asm(" .globl _breakinst
724 _breakinst: ta 1
726 #endif