1 /* $Id: sparc-stub.c,v 1.28 2001/10/30 04:54:21 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.
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 $
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 $
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.
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
73 * ? What was the last sigval ? SNN (signal NN)
75 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
78 * All commands and responses are sent with a packet which includes a
79 * checksum. A packet consists of
81 * $<packet info>#<checksum>.
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.
93 * $m0,10#2a +$00010203040506070809101112131415#42
95 ****************************************************************************/
97 #include <linux/kernel.h>
98 #include <linux/string.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/pgalloc.h>
111 #include <asm/pgtable.h>
112 #include <asm/cacheflush.h>
116 * external low-level support routines
119 extern void putDebugChar(char); /* write a single character */
120 extern char getDebugChar(void); /* read and return a single char */
123 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
124 * at least NUMREGBYTES*2 are needed for register packets
128 static int initialized
; /* !0 means we've been initialized */
130 static const char hexchars
[]="0123456789abcdef";
134 /* Number of bytes of registers. */
135 #define NUMREGBYTES (NUMREGS * 4)
136 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
137 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
138 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
139 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
141 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
142 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
143 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
144 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
145 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
};
148 extern void trap_low(void); /* In arch/sparc/kernel/entry.S */
150 unsigned long get_sun4cpte(unsigned long addr
)
154 __asm__
__volatile__("\n\tlda [%1] %2, %0\n\t" :
156 "r" (addr
), "i" (ASI_PTE
));
160 unsigned long get_sun4csegmap(unsigned long addr
)
164 __asm__
__volatile__("\n\tlduba [%1] %2, %0\n\t" :
166 "r" (addr
), "i" (ASI_SEGMAP
));
171 /* Have to sort this out. This cannot be done after initialization. */
172 static void flush_cache_all_nop(void) {}
175 /* Place where we save old trap entries for restoration */
176 struct tt_entry kgdb_savettable
[256];
177 typedef void (*trapfunc_t
)(void);
179 /* Helper routine for manipulation of kgdb_savettable */
180 static inline void copy_ttentry(struct tt_entry
*src
, struct tt_entry
*dest
)
182 dest
->inst_one
= src
->inst_one
;
183 dest
->inst_two
= src
->inst_two
;
184 dest
->inst_three
= src
->inst_three
;
185 dest
->inst_four
= src
->inst_four
;
188 /* Initialize the kgdb_savettable so that debugging can commence */
189 static void eh_init(void)
193 for(i
=0; i
< 256; i
++)
194 copy_ttentry(&sparc_ttable
[i
], &kgdb_savettable
[i
]);
197 /* Install an exception handler for kgdb */
198 static void exceptionHandler(int tnum
, trapfunc_t trap_entry
)
200 unsigned long te_addr
= (unsigned long) trap_entry
;
202 /* Make new vector */
203 sparc_ttable
[tnum
].inst_one
=
204 SPARC_BRANCH((unsigned long) te_addr
,
205 (unsigned long) &sparc_ttable
[tnum
].inst_one
);
206 sparc_ttable
[tnum
].inst_two
= SPARC_RD_PSR_L0
;
207 sparc_ttable
[tnum
].inst_three
= SPARC_NOP
;
208 sparc_ttable
[tnum
].inst_four
= SPARC_NOP
;
211 /* Convert ch from a hex digit to an int */
213 hex(unsigned char ch
)
215 if (ch
>= 'a' && ch
<= 'f')
217 if (ch
>= '0' && ch
<= '9')
219 if (ch
>= 'A' && ch
<= 'F')
224 /* scan for the sequence $<data>#<checksum> */
226 getpacket(char *buffer
)
228 unsigned char checksum
;
229 unsigned char xmitcsum
;
235 /* wait around for the start character, ignore all other characters */
236 while ((ch
= (getDebugChar() & 0x7f)) != '$') ;
243 /* now, read until a # or end of buffer is found */
244 while (count
< BUFMAX
) {
245 ch
= getDebugChar() & 0x7f;
248 checksum
= checksum
+ ch
;
259 xmitcsum
= hex(getDebugChar() & 0x7f) << 4;
260 xmitcsum
|= hex(getDebugChar() & 0x7f);
261 if (checksum
!= xmitcsum
)
262 putDebugChar('-'); /* failed checksum */
264 putDebugChar('+'); /* successful transfer */
265 /* if a sequence char is present, reply the ID */
266 if (buffer
[2] == ':') {
267 putDebugChar(buffer
[0]);
268 putDebugChar(buffer
[1]);
269 /* remove sequence chars from buffer */
270 count
= strlen(buffer
);
271 for (i
=3; i
<= count
; i
++)
272 buffer
[i
-3] = buffer
[i
];
276 } while (checksum
!= xmitcsum
);
279 /* send the packet in buffer. */
282 putpacket(unsigned char *buffer
)
284 unsigned char checksum
;
286 unsigned char ch
, recv
;
288 /* $<packet info>#<checksum>. */
294 while ((ch
= buffer
[count
])) {
301 putDebugChar(hexchars
[checksum
>> 4]);
302 putDebugChar(hexchars
[checksum
& 0xf]);
303 recv
= getDebugChar();
304 } while ((recv
& 0x7f) != '+');
307 static char remcomInBuffer
[BUFMAX
];
308 static char remcomOutBuffer
[BUFMAX
];
310 /* Convert the memory pointed to by mem into hex, placing result in buf.
311 * Return a pointer to the last char put in buf (null), in case of mem fault,
315 static unsigned char *
316 mem2hex(char *mem
, char *buf
, int count
)
320 while (count
-- > 0) {
321 /* This assembler code is basically: ch = *mem++;
322 * except that we use the SPARC/Linux exception table
323 * mechanism (see how "fixup" works in kernel_mna_trap_fault)
324 * to arrange for a "return 0" upon a memory fault
330 ".section .fixup,#alloc,#execinstr\n\t"
335 ".section __ex_table, #alloc\n\t"
339 : "=r" (mem
), "=r" (ch
) : "0" (mem
));
340 *buf
++ = hexchars
[ch
>> 4];
341 *buf
++ = hexchars
[ch
& 0xf];
348 /* convert the hex array pointed to by buf into binary to be placed in mem
349 * return a pointer to the character AFTER the last byte written.
352 hex2mem(char *buf
, char *mem
, int count
)
357 for (i
=0; i
<count
; i
++) {
359 ch
= hex(*buf
++) << 4;
361 /* Assembler code is *mem++ = ch; with return 0 on fault */
366 ".section .fixup,#alloc,#execinstr\n\t"
371 ".section __ex_table, #alloc\n\t"
375 : "=r" (mem
) : "r" (ch
) , "0" (mem
));
380 /* This table contains the mapping between SPARC hardware trap types, and
381 signals, which are primarily what GDB understands. It also indicates
382 which hardware traps we need to commandeer when initializing the stub. */
384 static struct hard_trap_info
386 unsigned char tt
; /* Trap type code for SPARC */
387 unsigned char signo
; /* Signal that we map this trap into */
388 } hard_trap_info
[] = {
389 {SP_TRAP_SBPT
, SIGTRAP
}, /* ta 1 - Linux/KGDB software breakpoint */
390 {0, 0} /* Must be last */
393 /* Set up exception handlers for tracing and breakpoints */
396 set_debug_traps(void)
398 struct hard_trap_info
*ht
;
401 local_irq_save(flags
);
403 /* Have to sort this out. This cannot be done after initialization. */
404 BTFIXUPSET_CALL(flush_cache_all
, flush_cache_all_nop
, BTFIXUPCALL_NOP
);
407 /* Initialize our copy of the Linux Sparc trap table */
410 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++) {
411 /* Only if it doesn't destroy our fault handlers */
412 if((ht
->tt
!= SP_TRAP_TFLT
) &&
413 (ht
->tt
!= SP_TRAP_DFLT
))
414 exceptionHandler(ht
->tt
, trap_low
);
417 /* In case GDB is started before us, ack any packets (presumably
418 * "$?#xx") sitting there.
420 * I've found this code causes more problems than it solves,
421 * so that's why it's commented out. GDB seems to work fine
422 * now starting either before or after the kernel -bwb
425 while((c
= getDebugChar()) != '$');
426 while((c
= getDebugChar()) != '#');
427 c
= getDebugChar(); /* eat first csum byte */
428 c
= getDebugChar(); /* eat second csum byte */
429 putDebugChar('+'); /* ack it */
432 initialized
= 1; /* connect! */
433 local_irq_restore(flags
);
436 /* Convert the SPARC hardware trap type code to a unix signal number. */
439 computeSignal(int tt
)
441 struct hard_trap_info
*ht
;
443 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
447 return SIGHUP
; /* default for things we don't know about */
451 * While we find nice hex chars, build an int.
452 * Return number of chars processed.
456 hexToInt(char **ptr
, int *intValue
)
464 hexValue
= hex(**ptr
);
468 *intValue
= (*intValue
<< 4) | hexValue
;
478 * This function does all command processing for interfacing to gdb. It
479 * returns 1 if you should skip the instruction at the trap address, 0
483 extern void breakinst(void);
486 handle_exception (unsigned long *registers
)
488 int tt
; /* Trap type */
495 /* First, we must force all of the windows to be spilled out */
497 asm("save %sp, -64, %sp\n\t"
498 "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"
515 if (registers
[PC
] == (unsigned long)breakinst
) {
516 /* Skip over breakpoint trap insn */
517 registers
[PC
] = registers
[NPC
];
521 sp
= (unsigned long *)registers
[SP
];
523 tt
= (registers
[TBR
] >> 4) & 0xff;
525 /* reply to host that an exception has occurred */
526 sigval
= computeSignal(tt
);
527 ptr
= remcomOutBuffer
;
530 *ptr
++ = hexchars
[sigval
>> 4];
531 *ptr
++ = hexchars
[sigval
& 0xf];
533 *ptr
++ = hexchars
[PC
>> 4];
534 *ptr
++ = hexchars
[PC
& 0xf];
536 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4);
539 *ptr
++ = hexchars
[FP
>> 4];
540 *ptr
++ = hexchars
[FP
& 0xf];
542 ptr
= mem2hex((char *) (sp
+ 8 + 6), ptr
, 4); /* FP */
545 *ptr
++ = hexchars
[SP
>> 4];
546 *ptr
++ = hexchars
[SP
& 0xf];
548 ptr
= mem2hex((char *)&sp
, ptr
, 4);
551 *ptr
++ = hexchars
[NPC
>> 4];
552 *ptr
++ = hexchars
[NPC
& 0xf];
554 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4);
557 *ptr
++ = hexchars
[O7
>> 4];
558 *ptr
++ = hexchars
[O7
& 0xf];
560 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4);
565 putpacket(remcomOutBuffer
);
567 /* XXX We may want to add some features dealing with poking the
568 * XXX page tables, the real ones on the srmmu, and what is currently
569 * XXX loaded in the sun4/sun4c tlb at this point in time. But this
570 * XXX also required hacking to the gdb sources directly...
574 remcomOutBuffer
[0] = 0;
576 getpacket(remcomInBuffer
);
577 switch (remcomInBuffer
[0]) {
579 remcomOutBuffer
[0] = 'S';
580 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
581 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
582 remcomOutBuffer
[3] = 0;
586 /* toggle debug flag */
589 case 'g': /* return the value of the CPU registers */
591 ptr
= remcomOutBuffer
;
593 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4);
595 ptr
= mem2hex((char *) (sp
+ 0), ptr
, 16 * 4);
597 memset(ptr
, '0', 32 * 8);
598 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
599 mem2hex((char *)®isters
[Y
], (ptr
+ 32 * 4 * 2), (8 * 4));
603 case 'G': /* set the value of the CPU registers - return OK */
605 unsigned long *newsp
, psr
;
607 psr
= registers
[PSR
];
609 ptr
= &remcomInBuffer
[1];
611 hex2mem(ptr
, (char *)registers
, 16 * 4);
613 hex2mem(ptr
+ 16 * 4 * 2, (char *) (sp
+ 0), 16 * 4);
614 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
615 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
], 8 * 4);
617 /* See if the stack pointer has moved. If so,
618 * then copy the saved locals and ins to the
619 * new location. This keeps the window
620 * overflow and underflow routines happy.
623 newsp
= (unsigned long *)registers
[SP
];
625 sp
= memcpy(newsp
, sp
, 16 * 4);
627 /* Don't allow CWP to be modified. */
629 if (psr
!= registers
[PSR
])
630 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
632 strcpy(remcomOutBuffer
,"OK");
636 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
637 /* Try to read %x,%x. */
639 ptr
= &remcomInBuffer
[1];
641 if (hexToInt(&ptr
, &addr
)
643 && hexToInt(&ptr
, &length
)) {
644 if (mem2hex((char *)addr
, remcomOutBuffer
, length
))
647 strcpy (remcomOutBuffer
, "E03");
649 strcpy(remcomOutBuffer
,"E01");
653 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
654 /* Try to read '%x,%x:'. */
656 ptr
= &remcomInBuffer
[1];
658 if (hexToInt(&ptr
, &addr
)
660 && hexToInt(&ptr
, &length
)
662 if (hex2mem(ptr
, (char *)addr
, length
)) {
663 strcpy(remcomOutBuffer
, "OK");
665 strcpy(remcomOutBuffer
, "E03");
668 strcpy(remcomOutBuffer
, "E02");
672 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
673 /* try to read optional parameter, pc unchanged if no parm */
675 ptr
= &remcomInBuffer
[1];
676 if (hexToInt(&ptr
, &addr
)) {
677 registers
[PC
] = addr
;
678 registers
[NPC
] = addr
+ 4;
681 /* Need to flush the instruction cache here, as we may have deposited a
682 * breakpoint, and the icache probably has no way of knowing that a data ref to
683 * some location may have changed something that is in the instruction cache.
689 /* kill the program */
690 case 'k' : /* do nothing */
692 case 'r': /* Reset */
698 /* reply to the request */
699 putpacket(remcomOutBuffer
);
703 /* This function will generate a breakpoint exception. It is used at the
704 beginning of a program to sync up with a debugger and can be used
705 otherwise as a quick means to stop program execution and "break" into
714 /* Again, watch those c-prefixes for ELF kernels */
715 #if defined(__svr4__) || defined(__ELF__)
716 asm(".globl breakinst\n"
720 asm(".globl _breakinst\n"