1 /* $Id: sparc-stub.c,v 1.27 2000/10/03 07:28:49 anton 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>
114 * external low-level support routines
117 extern void putDebugChar(char); /* write a single character */
118 extern char getDebugChar(void); /* read and return a single char */
121 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
122 * at least NUMREGBYTES*2 are needed for register packets
126 static int initialized
; /* !0 means we've been initialized */
128 static const char hexchars
[]="0123456789abcdef";
132 /* Number of bytes of registers. */
133 #define NUMREGBYTES (NUMREGS * 4)
134 enum regnames
{G0
, G1
, G2
, G3
, G4
, G5
, G6
, G7
,
135 O0
, O1
, O2
, O3
, O4
, O5
, SP
, O7
,
136 L0
, L1
, L2
, L3
, L4
, L5
, L6
, L7
,
137 I0
, I1
, I2
, I3
, I4
, I5
, FP
, I7
,
139 F0
, F1
, F2
, F3
, F4
, F5
, F6
, F7
,
140 F8
, F9
, F10
, F11
, F12
, F13
, F14
, F15
,
141 F16
, F17
, F18
, F19
, F20
, F21
, F22
, F23
,
142 F24
, F25
, F26
, F27
, F28
, F29
, F30
, F31
,
143 Y
, PSR
, WIM
, TBR
, PC
, NPC
, FPSR
, CPSR
};
146 extern void trap_low(void); /* In arch/sparc/kernel/entry.S */
148 unsigned long get_sun4cpte(unsigned long addr
)
152 __asm__
__volatile__("\n\tlda [%1] %2, %0\n\t" :
154 "r" (addr
), "i" (ASI_PTE
));
158 unsigned long get_sun4csegmap(unsigned long addr
)
162 __asm__
__volatile__("\n\tlduba [%1] %2, %0\n\t" :
164 "r" (addr
), "i" (ASI_SEGMAP
));
169 /* Have to sort this out. This cannot be done after initialization. */
170 static void flush_cache_all_nop(void) {}
173 /* Place where we save old trap entries for restoration */
174 struct tt_entry kgdb_savettable
[256];
175 typedef void (*trapfunc_t
)(void);
177 /* Helper routine for manipulation of kgdb_savettable */
178 static inline void copy_ttentry(struct tt_entry
*src
, struct tt_entry
*dest
)
180 dest
->inst_one
= src
->inst_one
;
181 dest
->inst_two
= src
->inst_two
;
182 dest
->inst_three
= src
->inst_three
;
183 dest
->inst_four
= src
->inst_four
;
186 /* Initialize the kgdb_savettable so that debugging can commence */
187 static void eh_init(void)
192 for(i
=0; i
< 256; i
++)
193 copy_ttentry(&sparc_ttable
[i
], &kgdb_savettable
[i
]);
194 restore_flags(flags
);
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
;
203 /* We are dorking with a live trap table, all irqs off */
206 /* Make new vector */
207 sparc_ttable
[tnum
].inst_one
=
208 SPARC_BRANCH((unsigned long) te_addr
,
209 (unsigned long) &sparc_ttable
[tnum
].inst_one
);
210 sparc_ttable
[tnum
].inst_two
= SPARC_RD_PSR_L0
;
211 sparc_ttable
[tnum
].inst_three
= SPARC_NOP
;
212 sparc_ttable
[tnum
].inst_four
= SPARC_NOP
;
214 restore_flags(flags
);
217 /* Convert ch from a hex digit to an int */
219 hex(unsigned char ch
)
221 if (ch
>= 'a' && ch
<= 'f')
223 if (ch
>= '0' && ch
<= '9')
225 if (ch
>= 'A' && ch
<= 'F')
230 /* scan for the sequence $<data>#<checksum> */
232 getpacket(char *buffer
)
234 unsigned char checksum
;
235 unsigned char xmitcsum
;
241 /* wait around for the start character, ignore all other characters */
242 while ((ch
= (getDebugChar() & 0x7f)) != '$') ;
249 /* now, read until a # or end of buffer is found */
250 while (count
< BUFMAX
) {
251 ch
= getDebugChar() & 0x7f;
254 checksum
= checksum
+ ch
;
265 xmitcsum
= hex(getDebugChar() & 0x7f) << 4;
266 xmitcsum
|= hex(getDebugChar() & 0x7f);
267 if (checksum
!= xmitcsum
)
268 putDebugChar('-'); /* failed checksum */
270 putDebugChar('+'); /* successful transfer */
271 /* if a sequence char is present, reply the ID */
272 if (buffer
[2] == ':') {
273 putDebugChar(buffer
[0]);
274 putDebugChar(buffer
[1]);
275 /* remove sequence chars from buffer */
276 count
= strlen(buffer
);
277 for (i
=3; i
<= count
; i
++)
278 buffer
[i
-3] = buffer
[i
];
282 } while (checksum
!= xmitcsum
);
285 /* send the packet in buffer. */
288 putpacket(unsigned char *buffer
)
290 unsigned char checksum
;
292 unsigned char ch
, recv
;
294 /* $<packet info>#<checksum>. */
300 while ((ch
= buffer
[count
])) {
307 putDebugChar(hexchars
[checksum
>> 4]);
308 putDebugChar(hexchars
[checksum
& 0xf]);
309 recv
= getDebugChar();
310 } while ((recv
& 0x7f) != '+');
313 static char remcomInBuffer
[BUFMAX
];
314 static char remcomOutBuffer
[BUFMAX
];
316 /* Convert the memory pointed to by mem into hex, placing result in buf.
317 * Return a pointer to the last char put in buf (null), in case of mem fault,
321 static unsigned char *
322 mem2hex(char *mem
, char *buf
, int count
)
326 while (count
-- > 0) {
327 /* This assembler code is basically: ch = *mem++;
328 * except that we use the SPARC/Linux exception table
329 * mechanism (see how "fixup" works in kernel_mna_trap_fault)
330 * to arrange for a "return 0" upon a memory fault
335 .section .fixup,#alloc,#execinstr
339 .section __ex_table, #alloc
343 : "=r" (mem
), "=r" (ch
) : "0" (mem
));
344 *buf
++ = hexchars
[ch
>> 4];
345 *buf
++ = hexchars
[ch
& 0xf];
352 /* convert the hex array pointed to by buf into binary to be placed in mem
353 * return a pointer to the character AFTER the last byte written.
356 hex2mem(char *buf
, char *mem
, int count
)
361 for (i
=0; i
<count
; i
++) {
363 ch
= hex(*buf
++) << 4;
365 /* Assembler code is *mem++ = ch; with return 0 on fault */
369 .section .fixup,#alloc,#execinstr
373 .section __ex_table, #alloc
377 : "=r" (mem
) : "r" (ch
) , "0" (mem
));
382 /* This table contains the mapping between SPARC hardware trap types, and
383 signals, which are primarily what GDB understands. It also indicates
384 which hardware traps we need to commandeer when initializing the stub. */
386 static struct hard_trap_info
388 unsigned char tt
; /* Trap type code for SPARC */
389 unsigned char signo
; /* Signal that we map this trap into */
390 } hard_trap_info
[] = {
391 {SP_TRAP_SBPT
, SIGTRAP
}, /* ta 1 - Linux/KGDB software breakpoint */
392 {0, 0} /* Must be last */
395 /* Set up exception handlers for tracing and breakpoints */
398 set_debug_traps(void)
400 struct hard_trap_info
*ht
;
405 /* Have to sort this out. This cannot be done after initialization. */
406 BTFIXUPSET_CALL(flush_cache_all
, flush_cache_all_nop
, BTFIXUPCALL_NOP
);
409 /* Initialize our copy of the Linux Sparc trap table */
412 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++) {
413 /* Only if it doesn't destroy our fault handlers */
414 if((ht
->tt
!= SP_TRAP_TFLT
) &&
415 (ht
->tt
!= SP_TRAP_DFLT
))
416 exceptionHandler(ht
->tt
, trap_low
);
419 /* In case GDB is started before us, ack any packets (presumably
420 * "$?#xx") sitting there.
422 * I've found this code causes more problems than it solves,
423 * so that's why it's commented out. GDB seems to work fine
424 * now starting either before or after the kernel -bwb
427 while((c
= getDebugChar()) != '$');
428 while((c
= getDebugChar()) != '#');
429 c
= getDebugChar(); /* eat first csum byte */
430 c
= getDebugChar(); /* eat second csum byte */
431 putDebugChar('+'); /* ack it */
434 initialized
= 1; /* connect! */
435 restore_flags(flags
);
438 /* Convert the SPARC hardware trap type code to a unix signal number. */
441 computeSignal(int tt
)
443 struct hard_trap_info
*ht
;
445 for (ht
= hard_trap_info
; ht
->tt
&& ht
->signo
; ht
++)
449 return SIGHUP
; /* default for things we don't know about */
453 * While we find nice hex chars, build an int.
454 * Return number of chars processed.
458 hexToInt(char **ptr
, int *intValue
)
466 hexValue
= hex(**ptr
);
470 *intValue
= (*intValue
<< 4) | hexValue
;
480 * This function does all command processing for interfacing to gdb. It
481 * returns 1 if you should skip the instruction at the trap address, 0
485 extern void breakinst(void);
488 handle_exception (unsigned long *registers
)
490 int tt
; /* Trap type */
497 /* First, we must force all of the windows to be spilled out */
499 asm("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 "save %sp, -64, %sp\n\t"
517 if (registers
[PC
] == (unsigned long)breakinst
) {
518 /* Skip over breakpoint trap insn */
519 registers
[PC
] = registers
[NPC
];
523 sp
= (unsigned long *)registers
[SP
];
525 tt
= (registers
[TBR
] >> 4) & 0xff;
527 /* reply to host that an exception has occurred */
528 sigval
= computeSignal(tt
);
529 ptr
= remcomOutBuffer
;
532 *ptr
++ = hexchars
[sigval
>> 4];
533 *ptr
++ = hexchars
[sigval
& 0xf];
535 *ptr
++ = hexchars
[PC
>> 4];
536 *ptr
++ = hexchars
[PC
& 0xf];
538 ptr
= mem2hex((char *)®isters
[PC
], ptr
, 4);
541 *ptr
++ = hexchars
[FP
>> 4];
542 *ptr
++ = hexchars
[FP
& 0xf];
544 ptr
= mem2hex((char *) (sp
+ 8 + 6), ptr
, 4); /* FP */
547 *ptr
++ = hexchars
[SP
>> 4];
548 *ptr
++ = hexchars
[SP
& 0xf];
550 ptr
= mem2hex((char *)&sp
, ptr
, 4);
553 *ptr
++ = hexchars
[NPC
>> 4];
554 *ptr
++ = hexchars
[NPC
& 0xf];
556 ptr
= mem2hex((char *)®isters
[NPC
], ptr
, 4);
559 *ptr
++ = hexchars
[O7
>> 4];
560 *ptr
++ = hexchars
[O7
& 0xf];
562 ptr
= mem2hex((char *)®isters
[O7
], ptr
, 4);
567 putpacket(remcomOutBuffer
);
569 /* XXX We may want to add some features dealing with poking the
570 * XXX page tables, the real ones on the srmmu, and what is currently
571 * XXX loaded in the sun4/sun4c tlb at this point in time. But this
572 * XXX also required hacking to the gdb sources directly...
576 remcomOutBuffer
[0] = 0;
578 getpacket(remcomInBuffer
);
579 switch (remcomInBuffer
[0]) {
581 remcomOutBuffer
[0] = 'S';
582 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
583 remcomOutBuffer
[2] = hexchars
[sigval
& 0xf];
584 remcomOutBuffer
[3] = 0;
588 /* toggle debug flag */
591 case 'g': /* return the value of the CPU registers */
593 ptr
= remcomOutBuffer
;
595 ptr
= mem2hex((char *)registers
, ptr
, 16 * 4);
597 ptr
= mem2hex((char *) (sp
+ 0), ptr
, 16 * 4);
599 memset(ptr
, '0', 32 * 8);
600 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
601 mem2hex((char *)®isters
[Y
], (ptr
+ 32 * 4 * 2), (8 * 4));
605 case 'G': /* set the value of the CPU registers - return OK */
607 unsigned long *newsp
, psr
;
609 psr
= registers
[PSR
];
611 ptr
= &remcomInBuffer
[1];
613 hex2mem(ptr
, (char *)registers
, 16 * 4);
615 hex2mem(ptr
+ 16 * 4 * 2, (char *) (sp
+ 0), 16 * 4);
616 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
617 hex2mem(ptr
+ 64 * 4 * 2, (char *)®isters
[Y
], 8 * 4);
619 /* See if the stack pointer has moved. If so,
620 * then copy the saved locals and ins to the
621 * new location. This keeps the window
622 * overflow and underflow routines happy.
625 newsp
= (unsigned long *)registers
[SP
];
627 sp
= memcpy(newsp
, sp
, 16 * 4);
629 /* Don't allow CWP to be modified. */
631 if (psr
!= registers
[PSR
])
632 registers
[PSR
] = (psr
& 0x1f) | (registers
[PSR
] & ~0x1f);
634 strcpy(remcomOutBuffer
,"OK");
638 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
639 /* Try to read %x,%x. */
641 ptr
= &remcomInBuffer
[1];
643 if (hexToInt(&ptr
, &addr
)
645 && hexToInt(&ptr
, &length
)) {
646 if (mem2hex((char *)addr
, remcomOutBuffer
, length
))
649 strcpy (remcomOutBuffer
, "E03");
651 strcpy(remcomOutBuffer
,"E01");
655 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
656 /* Try to read '%x,%x:'. */
658 ptr
= &remcomInBuffer
[1];
660 if (hexToInt(&ptr
, &addr
)
662 && hexToInt(&ptr
, &length
)
664 if (hex2mem(ptr
, (char *)addr
, length
)) {
665 strcpy(remcomOutBuffer
, "OK");
667 strcpy(remcomOutBuffer
, "E03");
670 strcpy(remcomOutBuffer
, "E02");
674 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
675 /* try to read optional parameter, pc unchanged if no parm */
677 ptr
= &remcomInBuffer
[1];
678 if (hexToInt(&ptr
, &addr
)) {
679 registers
[PC
] = addr
;
680 registers
[NPC
] = addr
+ 4;
683 /* Need to flush the instruction cache here, as we may have deposited a
684 * breakpoint, and the icache probably has no way of knowing that a data ref to
685 * some location may have changed something that is in the instruction cache.
691 /* kill the program */
692 case 'k' : /* do nothing */
694 case 'r': /* Reset */
700 /* reply to the request */
701 putpacket(remcomOutBuffer
);
705 /* This function will generate a breakpoint exception. It is used at the
706 beginning of a program to sync up with a debugger and can be used
707 otherwise as a quick means to stop program execution and "break" into
716 /* Again, watch those c-prefixes for ELF kernels */
717 #if defined(__svr4__) || defined(__ELF__)
718 asm(" .globl breakinst
723 asm(" .globl _breakinst