patch-2.3.41 linux/arch/m68k/kernel/kgdb.c
Next file: linux/arch/m68k/kernel/m68k_ksyms.c
Previous file: linux/arch/m68k/kernel/head.S
Back to the patch index
Back to the overall index
- Lines: 1363
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.40/linux/arch/m68k/kernel/kgdb.c
- Orig date:
Tue Sep 7 12:14:06 1999
diff -u --recursive --new-file v2.3.40/linux/arch/m68k/kernel/kgdb.c linux/arch/m68k/kernel/kgdb.c
@@ -1,1362 +0,0 @@
-/*
- * arch/m68k/kernel/kgdb.c -- Stub for GDB remote debugging protocol
- *
- * Originally written by Glenn Engel, Lake Stevens Instrument Division
- *
- * Contributed by HP Systems
- *
- * Modified for SPARC by Stu Grossman, Cygnus Support.
- * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
- * Modified and extended for Linux/68k by Roman Hodek
- *
- * Send complaints, suggestions etc. to
- * <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * Copyright (C) 1996-97 Roman Hodek
- */
-
-/*
- * kgdb usage notes:
- * -----------------
- *
- * If you select CONFIG_KGDB in the configuration, the kernel will be built
- * with different gccc flags: "-g" is added to get debug infos, and
- * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
- * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
- * before compresion. Such a kernel will behave just as usually, except if
- * given a "debug=<device>" command line option. (Only serial devices are
- * allowed for <device>, i.e. no printers or the like; possible values are
- * machine depedend and are the same as for the usual debug device, the one
- * for logging kernel messages.) If that option is given and the device can be
- * initialized, the kernel will connect to the remote gdb in trap_init(). The
- * serial parameters are fixed to 8N1 and 9600bps, for easyness of
- * implementation.
- *
- * Of course, you need a remote machine a suitable gdb there. I.e., it must
- * have support for a m68k-linux target built in. If the remote machine
- * doesn't run Linux/68k itself, you have to build a cross gdb. This is done
- * by
- * ./configure --target=m68k-linux
- * in the gdb source directory. Until gdb comes with m68k-linux support by
- * default, you have to apply some patches before. The remote debugging
- * protocol itself is always built into gdb anyway, so you don't have to take
- * special care about it.
- *
- * To start a debugging session, start that gdb with the debugging kernel
- * image (the one with the symbols, vmlinux.debug) named on the command line.
- * This file will be used by gdb to get symbol and debugging infos about the
- * kernel. Next, select remote debug mode by
- * target remote <device>
- * where <device> is the name of the serial device over which the debugged
- * machine is connected. Maybe you have to adjust the baud rate by
- * set remotebaud <rate>
- * or also other parameters with stty:
- * shell stty ... </dev/...
- * If the kernel to debug has already booted, it waited for gdb and now
- * connects, and you'll see a breakpoint being reported. If the kernel isn't
- * running yet, start it now. The order of gdb and the kernel doesn't matter.
- * Another thing worth knowing about in the getting-started phase is how to
- * debug the remote protocol itself. This is activated with
- * set remotedebug 1
- * gdb will then print out each packet sent or received. You'll also get some
- * messages about the gdb stub on the console of the debugged machine.
- *
- * If all that works, you can use lots of the usual debugging techniques on
- * the kernel, e.g. inspecting and changing variables/memory, setting
- * breakpoints, single stepping and so on. It's also possible to interrupt the
- * debugged kernel by pressing C-c in gdb. Have fun! :-)
- *
- * The gdb stub is entered (and thus the remote gdb gets control) in the
- * following situations:
- *
- * - If breakpoint() is called. This is just after kgdb initialization, or if
- * a breakpoint() call has been put somewhere into the kernel source.
- * (Breakpoints can of course also be set the usual way in gdb.)
- *
- * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
- * are entered. All the CPU exceptions are mapped to (more or less..., see
- * the hard_trap_info array below) appropriate signal, which are reported
- * to gdb. die_if_kernel() is usually called after some kind of access
- * error and thus is reported as SIGSEGV.
- *
- * - When panic() is called. This is reported as SIGABRT.
- *
- * - If C-c is received over the serial line, which is treated as
- * SIGINT.
- *
- * Of course, all these signals are just faked for gdb, since there is no
- * signal concept as such for the kernel. It also isn't possible --obviously--
- * to set signal handlers from inside gdb, or restart the kernel with a
- * signal.
- *
- * Current limitations:
- *
- * - While the kernel is stopped, interrupts are disabled for safety reasons
- * (i.e., variables not changing magically or the like). But this also
- * means that the clock isn't running anymore, and that interrupts from the
- * hardware may get lost/not be served in time. This can cause some device
- * errors...
- *
- * - When single-stepping, only one instruction of the current thread is
- * executed, but interrupts are allowed for that time and will be serviced
- * if pending. Be prepared for that.
- *
- * - All debugging happens in kernel virtual address space. There's no way to
- * access physical memory not mapped in kernel space, or to access user
- * space. A way to work around this is using get_user_long & Co. in gdb
- * expressions, but only for the current process.
- *
- * - Interrupting the kernel only works if interrupts are currently allowed,
- * and the interrupt of the serial line isn't blocked by some other means
- * (IPL too high, disabled, ...)
- *
- * - The gdb stub is currently not reentrant, i.e. errors that happen therein
- * (e.g. accesing invalid memory) may not be caught correctly. This could
- * be removed in future by introducing a stack of struct registers.
- *
- */
-
-/*
- * To enable debugger support, two things need to happen. One, a
- * call to kgdb_init() is necessary in order to allow any breakpoints
- * or error conditions to be properly intercepted and reported to gdb.
- * (Linux/68k note: Due to the current design, kgdb has to be initialized
- * after traps and interrupts.)
- * Two, a breakpoint needs to be generated to begin communication. This
- * is most easily accomplished by a call to breakpoint(). Breakpoint()
- * simulates a breakpoint by executing a TRAP #15 instruction.
- *
- *
- * The following gdb commands are supported:
- *
- * command function Return value
- *
- * g return the value of the CPU registers hex data or ENN
- * G set the value of the CPU registers OK or ENN
- *
- * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
- * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
- *
- * c Resume at current address SNN ( signal NN)
- * cAA..AA Continue at address AA..AA SNN
- *
- * s Step one instruction SNN
- * sAA..AA Step one instruction from AA..AA SNN
- *
- * k kill
- *
- * ? What was the last sigval ? SNN (signal NN)
- *
- * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
- * baud rate
- *
- * All commands and responses are sent with a packet which includes a
- * checksum. A packet consists of
- *
- * $<packet info>#<checksum>.
- *
- * where
- * <packet info> :: <characters representing the command or response>
- * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
- *
- * When a packet is received, it is first acknowledged with either '+' or '-'.
- * '+' indicates a successful transfer. '-' indicates a failed transfer.
- *
- * Example:
- *
- * Host: Reply:
- * $m0,10#2a +$00010203040506070809101112131415#42
- *
- */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/linkage.h>
-
-#include <asm/setup.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/kgdb.h>
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#endif
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif
-#ifdef CONFIG_MAC
-#include <linux/tty.h>
-#include <asm/bootinfo.h>
-#include <asm/macints.h>
-#endif
-
-
-#undef DEBUG
-
-/*
- * global variable: register structure
- */
-
-struct gdb_regs kgdb_registers;
-
-/*
- * serial i/o functions
- */
-
-static int (*serial_out)( unsigned char c );
-static unsigned char (*serial_in)( void );
-static unsigned char (*serial_intr)( void );
-
-#define putDebugChar(c) serial_out(c)
-#define getDebugChar() serial_in()
-
-
-/***************************** Prototypes *****************************/
-
-static int hex( unsigned char ch);
-static void getpacket( char *buffer);
-static void putpacket( char *buffer, int expect_ack);
-static inline unsigned long *get_vbr( void );
-static int protected_read( char *p, unsigned long *vbr );
-static int protected_write( char *p, char val, unsigned long *vbr );
-static unsigned char *mem2hex( char *mem, char *buf, int count, int
- may_fault);
-static char *hex2mem( char *buf, char *mem, int count, int may_fault);
-static int computeSignal( int tt);
-static int hexToInt( char **ptr, int *intValue);
-extern asmlinkage void kgdb_intr( int intno, void *data, struct pt_regs *fp );
-static asmlinkage void handle_exception( void );
-static void show_gdbregs( void );
-#ifdef CONFIG_ATARI
-static int atari_mfp_out( unsigned char c );
-static unsigned char atari_mfp_in( void );
-static unsigned char atari_mfp_intr( void );
-static int atari_scc_out( unsigned char c );
-static unsigned char atari_scc_in( void );
-static unsigned char atari_scc_intr( void );
-#endif
-#ifdef CONFIG_AMIGA
-extern int amiga_ser_out( unsigned char c );
-extern unsigned char amiga_ser_in( void );
-#endif
-#ifdef CONFIG_MAC
-static unsigned char mac_scca_in( void );
-static unsigned char mac_scca_out( unsigned char c );
-static unsigned char mac_scca_intr( void );
-static unsigned char mac_sccb_in( void );
-static unsigned char mac_sccb_out( unsigned char c);
-static unsigned char mac_sccb_intr( void );
-extern void mac_init_scc_port( int cflag, int port );
-#endif
-
-/************************* End of Prototypes **************************/
-
-
-int kgdb_initialized = 0; /* !0 means we've been initialized */
-
-/*
- * BUFMAX defines the maximum number of characters in inbound/outbound buffers
- * at least NUMREGBYTES*2 are needed for register packets
- */
-#define BUFMAX 2048
-
-static char input_buffer[BUFMAX];
-static char output_buffer[BUFMAX];
-static const char hexchars[]="0123456789abcdef";
-/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
-static int remote_debug = 0;
-
-/* sizes (in bytes) of CPU stack frames */
-static int frame_sizes[16] = {
- 8, 8, 12, 12, /* $0..$3 */
- 16, 8, 8, 60, /* $4..$7 */
- 8, 20, 32, 92, /* $8..$B */
- 12, 4, 4, 4 /* $C..$F */
-};
-
-/*
- * Convert ch from a hex digit to an int
- */
-static int hex(unsigned char ch)
-{
- if (ch >= 'a' && ch <= 'f')
- return ch-'a'+10;
- if (ch >= '0' && ch <= '9')
- return ch-'0';
- if (ch >= 'A' && ch <= 'F')
- return ch-'A'+10;
- return -1;
-}
-
-/*
- * scan for the sequence $<data>#<checksum>
- */
-static void getpacket(char *buffer)
-{
- unsigned char checksum;
- unsigned char xmitcsum;
- int i;
- int count;
- unsigned char ch;
-
- do {
- /*
- * wait around for the start character,
- * ignore all other characters
- */
- while ((ch = (getDebugChar() & 0x7f)) != '$') ;
-
- checksum = 0;
- xmitcsum = -1;
- count = 0;
-
- /*
- * now, read until a # or end of buffer is found
- */
- while (count < BUFMAX) {
- ch = getDebugChar() & 0x7f;
- if (ch == '#')
- break;
- checksum = checksum + ch;
- buffer[count] = ch;
- count = count + 1;
- }
-
- if (count >= BUFMAX)
- continue;
-
- buffer[count] = 0;
-#ifdef DEBUG
- printk( "kgdb: received packet %s\n", buffer );
-#endif
-
- if (ch == '#') {
- xmitcsum = hex(getDebugChar() & 0x7f) << 4;
- xmitcsum |= hex(getDebugChar() & 0x7f);
-
- if (checksum != xmitcsum) {
- if (remote_debug)
- printk( "kgdb: bad checksum. count = 0x%x sent=0x%x "
- "buf=%s\n", checksum, xmitcsum, buffer );
- putDebugChar('-'); /* failed checksum */
- }
- else {
- putDebugChar('+'); /* successful transfer */
-
- /*
- * if a sequence char is present,
- * reply the sequence ID
- */
- if (buffer[2] == ':') {
- putDebugChar(buffer[0]);
- putDebugChar(buffer[1]);
-
- /*
- * remove sequence chars from buffer
- */
- count = strlen(buffer);
- for (i=3; i <= count; i++)
- buffer[i-3] = buffer[i];
- }
- }
- }
- }
- while (checksum != xmitcsum);
-}
-
-/*
- * send the packet in buffer.
- */
-static void putpacket(char *buffer, int expect_ack)
-{
- unsigned char checksum;
- int count;
- unsigned char ch;
-
- /*
- * $<packet info>#<checksum>.
- */
-
-#ifdef DEBUG
- printk( "kgdb: sending packet %s\n", buffer );
-#endif
- do {
- putDebugChar('$');
- checksum = 0;
- count = 0;
-
- while ((ch = buffer[count]) != 0) {
- if (!(putDebugChar(ch)))
- return;
- checksum += ch;
- count += 1;
- }
-
- putDebugChar('#');
- putDebugChar(hexchars[checksum >> 4]);
- putDebugChar(hexchars[checksum & 0xf]);
-
- }
- while (expect_ack && (getDebugChar() & 0x7f) != '+');
-}
-
-
-static inline unsigned long *get_vbr( void )
-
-{ unsigned long *vbr;
-
- __asm__ __volatile__ ( "movec %/vbr,%0" : "=d" (vbr) : );
- return( vbr );
-}
-
-static int protected_read( char *p, unsigned long *vbr )
-
-{ unsigned char val;
- int rv;
-
- __asm__ __volatile__
- ( "movel %3@(8),%/a0\n\t"
- "movel #Lberr1,%3@(8)\n\t"
- "movel %/sp,%/a1\n\t"
- "moveq #1,%1\n\t"
- "moveb %2@,%0\n"
- "nop \n\t"
- "moveq #0,%1\n\t"
- "Lberr1:\t"
- "movel %/a1,%/sp\n\t"
- "movel %/a0,%3@(8)"
- : "=&d" (val), "=&r" (rv)
- : "a" (p), "a" (vbr)
- : "a0", "a1" );
-
- return( rv ? -1 : val );
-}
-
-static int protected_write( char *p, char val, unsigned long *vbr )
-
-{ int rv;
-
- __asm__ __volatile__
- ( "movel %3@(8),%/a0\n\t"
- "movel #Lberr2,%3@(8)\n\t"
- "movel %/sp,%/a1\n\t"
- "moveq #1,%0\n\t"
- "moveb %2,%1@\n"
- "nop \n\t"
- "moveq #0,%0\n\t"
- "Lberr2:\t"
- "movel %/a1,%/sp\n\t"
- "movel %/a0,%3@(8)"
- : "=&r" (rv)
- : "a" (p), "d" (val), "a" (vbr)
- : "a0", "a1" );
-
- return( rv );
-}
-
-/*
- * Convert the memory pointed to by mem into hex, placing result in buf.
- * Return a pointer to the last char put in buf (null), in case of mem fault,
- * return 0.
- * If MAY_FAULT is non-zero, then we will handle memory faults by returning
- * a 0, else treat a fault like any other fault in the stub.
- */
-static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
-{
- int ch;
- unsigned long *vbr = get_vbr();
-
- for( ; count-- > 0; ++mem ) {
- if ((ch = protected_read( mem, vbr )) < 0) {
- /* bus error happened */
- if (may_fault)
- return 0;
- else {
- /* ignore, but print a warning */
- printk( "Bus error on read from %p\n", mem );
- ch = 0;
- }
- }
- *buf++ = hexchars[(ch >> 4) & 0xf];
- *buf++ = hexchars[ch & 0xf];
- }
-
- *buf = 0;
-
- return buf;
-}
-
-/*
- * convert the hex array pointed to by buf into binary to be placed in mem
- * return a pointer to the character AFTER the last byte written
- */
-static char *hex2mem(char *buf, char *mem, int count, int may_fault)
-{
- int i;
- unsigned char ch;
- unsigned long *vbr = get_vbr();
-
- for( i = 0; i < count; i++, mem++ ) {
- ch = hex(*buf++) << 4;
- ch |= hex(*buf++);
- if (protected_write( mem, ch, vbr )) {
- /* bus error happened */
- if (may_fault)
- return 0;
- else
- /* ignore, but print a warning */
- printk( "Bus error on write to %p\n", mem );
- }
- }
-
- return mem;
-}
-
-/*
- * This table contains the mapping between SPARC hardware trap types, and
- * signals, which are primarily what GDB understands. It also indicates
- * which hardware traps we need to commandeer when initializing the stub.
- */
-static struct hard_trap_info
-{
- unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
- unsigned char signo; /* Signal that we map this trap into */
-} hard_trap_info[] = {
- { 1, SIGINT }, /* excep. 1 is used to fake SIGINT */
- { VEC_BUSERR, SIGSEGV }, /* bus/access error */
- { VEC_ADDRERR, SIGBUS }, /* address error */
- { VEC_ILLEGAL, SIGILL }, /* illegal insn */
- { VEC_ZERODIV, SIGFPE }, /* (integer) divison by zero */
- { VEC_CHK, SIGILL }, /* CHK insn */
- { VEC_TRAP, SIGFPE }, /* [F]TRAPcc insn */
- { VEC_PRIV, SIGILL }, /* priviledge violation (cannot happen) */
- { VEC_TRACE, SIGTRAP }, /* trace trap (single-stepping) */
- { VEC_LINE10, SIGILL }, /* A-line insn */
- { VEC_LINE11, SIGILL }, /* F-line insn */
- { VEC_COPROC, SIGIOT }, /* coprocessor protocol error */
- { VEC_FORMAT, SIGIOT }, /* frame format error */
- { VEC_UNINT, SIGIOT }, /* uninitialized intr. (should not happen) */
- { VEC_SYS, SIGILL }, /* TRAP #0 = system call (illegal in kernel) */
- { VEC_TRAP1, SIGILL }, /* TRAP #1 */
- { VEC_TRAP2, SIGILL }, /* TRAP #2 */
- { VEC_TRAP3, SIGILL }, /* TRAP #3 */
- { VEC_TRAP4, SIGILL }, /* TRAP #4 */
- { VEC_TRAP5, SIGILL }, /* TRAP #5 */
- { VEC_TRAP6, SIGILL }, /* TRAP #6 */
- { VEC_TRAP7, SIGILL }, /* TRAP #7 */
- { VEC_TRAP8, SIGILL }, /* TRAP #8 */
- { VEC_TRAP9, SIGILL }, /* TRAP #9 */
- { VEC_TRAP10, SIGILL }, /* TRAP #10 */
- { VEC_TRAP11, SIGILL }, /* TRAP #11 */
- { VEC_TRAP12, SIGILL }, /* TRAP #12 */
- { VEC_TRAP13, SIGILL }, /* TRAP #13 */
- { VEC_TRAP14, SIGABRT }, /* TRAP #14 (used by kgdb_abort) */
- { VEC_TRAP15, SIGTRAP }, /* TRAP #15 (breakpoint) */
- { VEC_FPBRUC, SIGFPE }, /* FPU */
- { VEC_FPIR, SIGFPE }, /* FPU */
- { VEC_FPDIVZ, SIGFPE }, /* FPU */
- { VEC_FPUNDER, SIGFPE }, /* FPU */
- { VEC_FPOE, SIGFPE }, /* FPU */
- { VEC_FPOVER, SIGFPE }, /* FPU */
- { VEC_FPNAN, SIGFPE }, /* FPU */
- { VEC_FPUNSUP, SIGFPE }, /* FPU */
- { VEC_UNIMPEA, SIGILL }, /* unimpl. effective address */
- { VEC_UNIMPII, SIGILL }, /* unimpl. integer insn */
-
- { 0, 0 } /* Must be last */
-};
-
-
-/*
- * Set up exception handlers for tracing and breakpoints
- */
-void kgdb_init(void)
-{
- extern char m68k_debug_device[];
-
- /* fake usage to avoid gcc warnings about unused stuff (they're used in
- * assembler code) The local variables will be optimized away... */
- void (*fake1)(void) = handle_exception;
- int *fake2 = frame_sizes;
- (void)fake1; (void)fake2;
-
- /* We don't modify the real exception vectors here for the m68k.
- * handle_exception() will be called from bad_kernel_trap() or
- * die_if_kernel() as needed. */
-
- /*
- * Initialize the serial port (name in 'm68k_debug_device')
- */
-
- serial_in = NULL;
- serial_out = NULL;
- serial_intr = NULL;
-
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI) {
- if (!strcmp( m68k_debug_device, "ser" )) {
- /* defaults to ser2 for a Falcon and ser1 otherwise */
- strcpy( m68k_debug_device,
- ((atari_mch_cookie>>16) == ATARI_MCH_FALCON) ?
- "ser2" : "ser1" );
- }
-
- if (!strcmp( m68k_debug_device, "ser1" )) {
- /* ST-MFP Modem1 serial port init */
- mfp.trn_stat &= ~0x01; /* disable TX */
- mfp.rcv_stat &= ~0x01; /* disable RX */
- mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */
- mfp.tim_ct_cd &= 0x70; /* stop timer D */
- mfp.tim_dt_d = 2; /* 9600 bps */
- mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
- mfp.trn_stat |= 0x01; /* enable TX */
- mfp.rcv_stat |= 0x01; /* enable RX */
-
- /* set function pointers */
- serial_in = atari_mfp_in;
- serial_out = atari_mfp_out;
- serial_intr = atari_mfp_intr;
-
- /* allocate interrupt */
- request_irq( IRQ_MFP_RECFULL, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
- NULL );
- }
- else if (!strcmp( m68k_debug_device, "ser2" )) {
- extern int atari_SCC_reset_done;
-
- /* SCC Modem2 serial port init */
- static unsigned char *p, scc_table[] = {
- 9, 0xc0, /* Reset */
- 4, 0x44, /* x16, 1 stopbit, no parity */
- 3, 0xc0, /* receiver: 8 bpc */
- 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */
- 2, 0x60, /* base int vector */
- 9, 0x09, /* int enab, with status low */
- 10, 0, /* NRZ */
- 11, 0x50, /* use baud rate generator */
- 12, 24, 13, 0, /* 9600 baud */
- 14, 2, 14, 3, /* use master clock for BRG, enable */
- 3, 0xc1, /* enable receiver */
- 5, 0xea, /* enable transmitter */
- 15, 0, /* no stat ints */
- 1, 0x10, /* Rx int every char, other ints off */
- 0
- };
-
- (void)scc.cha_b_ctrl; /* reset reg pointer */
- MFPDELAY();
- for( p = scc_table; *p != 0; ) {
- scc.cha_b_ctrl = *p++;
- MFPDELAY();
- scc.cha_b_ctrl = *p++;
- MFPDELAY();
- if (p[-2] == 9)
- udelay(40); /* extra delay after WR9 access */
- }
- /* avoid that atari_SCC.c resets the whole SCC again */
- atari_SCC_reset_done = 1;
-
- /* set function pointers */
- serial_in = atari_scc_in;
- serial_out = atari_scc_out;
- serial_intr = atari_scc_intr;
-
- /* allocate rx and spcond ints */
- request_irq( IRQ_SCCB_RX, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL );
- request_irq( IRQ_SCCB_SPCOND, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
- NULL );
- }
- }
-#endif
-
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA) {
- /* always use built-in serial port, no init required */
- serial_in = amiga_ser_in;
- serial_out = amiga_ser_out;
- }
-#endif
-
-#ifdef CONFIG_MAC
- if (MACH_IS_MAC) {
- if (!strcmp( m68k_debug_device, "ser" ) ||
- !strcmp( m68k_debug_device, "ser1" )) {
- mac_init_scc_port( B9600|CS8, 0 );
- serial_in = mac_scca_in;
- serial_out = mac_scca_out;
- serial_intr = mac_scca_intr;
- } else if (!strcmp( m68k_debug_device, "ser2" )) {
- mac_init_scc_port( B9600|CS8, 1 );
- serial_in = mac_sccb_in;
- serial_out = mac_sccb_out;
- serial_intr = mac_sccb_intr;
- }
- }
- if (!serial_in || !serial_out) {
- if (*m68k_debug_device)
- printk( "kgdb_init failed: no valid serial device!\n" );
- else
- printk( "kgdb not enabled\n" );
- return;
- }
- request_irq(4, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL);
-#endif
-
-#ifdef CONFIG_ATARI
- if (!serial_in || !serial_out) {
- if (*m68k_debug_device)
- printk( "kgdb_init failed: no valid serial device!\n" );
- else
- printk( "kgdb not enabled\n" );
- return;
- }
-#endif
-
- /*
- * In case GDB is started before us, ack any packets
- * (presumably "$?#xx") sitting there.
- */
-
- putDebugChar ('+');
- kgdb_initialized = 1;
- printk( KERN_INFO "kgdb initialized.\n" );
-}
-
-
-/*
- * Convert the MIPS hardware trap type code to a unix signal number.
- */
-static int computeSignal(int tt)
-{
- struct hard_trap_info *ht;
-
- for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
- if (ht->tt == tt)
- return ht->signo;
-
- return SIGHUP; /* default for things we don't know about */
-}
-
-/*
- * While we find nice hex chars, build an int.
- * Return number of chars processed.
- */
-static int hexToInt(char **ptr, int *intValue)
-{
- int numChars = 0;
- int hexValue;
-
- *intValue = 0;
-
- while (**ptr)
- {
- hexValue = hex(**ptr);
- if (hexValue < 0)
- break;
-
- *intValue = (*intValue << 4) | hexValue;
- numChars ++;
-
- (*ptr)++;
- }
-
- return (numChars);
-}
-
-
-/*
- * This assembler stuff copies a struct frame (passed as argument) into struct
- * gdb_regs registers and then calls handle_exception. After return from
- * there, register and the like are restored from 'registers', the stack is
- * set up and execution is continued where registers->pc tells us.
- */
-
-/* offsets in struct frame */
-#define FRAMEOFF_D1 "0" /* d1..d5 */
-#define FRAMEOFF_A0 "5*4" /* a0..a2 */
-#define FRAMEOFF_D0 "8*4"
-#define FRAMEOFF_SR "11*4"
-#define FRAMEOFF_PC "11*4+2"
-#define FRAMEOFF_VECTOR "12*4+2"
-
-/* offsets in struct gdb_regs */
-#define GDBOFF_D0 "0"
-#define GDBOFF_D1 "1*4"
-#define GDBOFF_D6 "6*4"
-#define GDBOFF_A0 "8*4"
-#define GDBOFF_A3 "11*4"
-#define GDBOFF_A7 "15*4"
-#define GDBOFF_VECTOR "16*4"
-#define GDBOFF_SR "16*4+2"
-#define GDBOFF_PC "17*4"
-#define GDBOFF_FP0 "18*4"
-#define GDBOFF_FPCTL "42*4"
-
-__asm__
-( " .globl " SYMBOL_NAME_STR(enter_kgdb) "\n"
- SYMBOL_NAME_STR(enter_kgdb) ":\n"
- /* return if not initialized */
- " tstl "SYMBOL_NAME_STR(kgdb_initialized)"\n"
- " bne 1f\n"
- " rts \n"
- "1: orw #0x700,%sr\n" /* disable interrupts while in stub */
- " tstl %sp@+\n" /* pop off return address */
- " movel %sp@+,%a0\n" /* get pointer to fp->ptregs (param) */
- " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
- /* copy d0-d5/a0-a1 into gdb_regs */
- " movel %a0@("FRAMEOFF_D0"),%a1@("GDBOFF_D0")\n"
- " moveml %a0@("FRAMEOFF_D1"),%d1-%d5\n"
- " moveml %d1-%d5,%a1@("GDBOFF_D1")\n"
- " moveml %a0@("FRAMEOFF_A0"),%d0-%d2\n"
- " moveml %d0-%d2,%a1@("GDBOFF_A0")\n"
- /* copy sr and pc */
- " movel %a0@("FRAMEOFF_PC"),%a1@("GDBOFF_PC")\n"
- " movew %a0@("FRAMEOFF_SR"),%a1@("GDBOFF_SR")\n"
- /* copy format/vector word */
- " movew %a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n"
- /* save FPU regs */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
- " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n"
- " jeq 1f\n"
-#endif
- " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n"
- " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
- "1:\n"
-#endif /* CONFIG_M68KFPU_EMU_ONLY */
-
- /* set stack to CPU frame */
- " addl #"FRAMEOFF_SR",%a0\n"
- " movel %a0,%sp\n"
- " movew %sp@(6),%d0\n"
- " andl #0xf000,%d0\n"
- " lsrl #8,%d0\n"
- " lsrl #2,%d0\n" /* get frame format << 2 */
- " lea "SYMBOL_NAME_STR(frame_sizes)",%a2\n"
- " addl %a2@(%d0),%sp\n"
- " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
-
- /* call handle_exception() now that the stack is set up */
- "Lcall_handle_excp:"
- " jsr "SYMBOL_NAME_STR(handle_exception)"\n"
-
- /* after return, first restore FPU registers */
- " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
- " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n"
- " jeq 1f\n"
-#endif
- " fmovemx %a0@("GDBOFF_FP0"),%fp0-%fp7\n"
- " fmoveml %a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n"
- "1:\n"
-#endif /* CONFIG_M68KFPU_EMU_ONLY */
- /* set new stack pointer */
- " movel %a0@("GDBOFF_A7"),%sp\n"
- " clrw %sp@-\n" /* fake format $0 frame */
- " movel %a0@("GDBOFF_PC"),%sp@-\n" /* new PC into frame */
- " movew %a0@("GDBOFF_SR"),%sp@-\n" /* new SR into frame */
- /* restore general registers */
- " moveml %a0@("GDBOFF_D0"),%d0-%d7/%a0-%a6\n"
- /* and jump to new PC */
- " rte"
- );
-
-
-/*
- * This is the entry point for the serial interrupt handler. It calls the
- * machine specific function pointer 'serial_intr' to get the char that
- * interrupted. If that was C-c, the stub is entered as above, but based on
- * just a struct intframe, not a struct frame.
- */
-
-__asm__
-( SYMBOL_NAME_STR(kgdb_intr) ":\n"
- /* return if not initialized */
- " tstl "SYMBOL_NAME_STR(kgdb_initialized)"\n"
- " bne 1f\n"
- "2: rts \n"
- "1: movel "SYMBOL_NAME_STR(serial_intr)",%a0\n"
- " jsr (%a0)\n" /* get char from serial */
- " cmpb #3,%d0\n" /* is it C-c ? */
- " bne 2b\n" /* no -> just ignore */
- " orw #0x700,%sr\n" /* disable interrupts */
- " subql #1,"SYMBOL_NAME_STR(local_irq_count)"\n"
- " movel %sp@(12),%sp\n" /* revert stack to where 'inthandler' set
- * it up */
- /* restore regs from frame */
- " moveml %sp@+,%d1-%d5/%a0-%a2\n"
- " movel %sp@+,%d0\n"
- " addql #8,%sp\n" /* throw away orig_d0 and stkadj */
- /* save them into 'registers' */
- " moveml %d0-%d7/%a0-%a6,"SYMBOL_NAME_STR(kgdb_registers)"\n"
- " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
- /* copy sr and pc */
- " movel %sp@(2),%a1@("GDBOFF_PC")\n"
- " movew %sp@,%a1@("GDBOFF_SR")\n"
- /* fake format 0 and vector 1 (translated to SIGINT) */
- " movew #4,%a1@("GDBOFF_VECTOR")\n"
- /* save FPU regs */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
- " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n"
- " jeq 1f\n"
-#endif
- " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n"
- " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
- "1:\n"
-#endif /* CONFIG_M68KFPU_EMU_ONLY */
- /* pop off the CPU stack frame */
- " addql #8,%sp\n"
- " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
- /* proceed as in enter_kgdb */
- " jbra Lcall_handle_excp\n"
- );
-
-/*
- * This function does all command processing for interfacing to gdb. It
- * returns 1 if you should skip the instruction at the trap address, 0
- * otherwise.
- */
-static asmlinkage void handle_exception( void )
-{
- int trap; /* Trap type */
- int sigval;
- int addr;
- int length;
- char *ptr;
-
- trap = kgdb_registers.vector >> 2;
- sigval = computeSignal(trap);
- /* clear upper half of vector/sr word */
- kgdb_registers.vector = 0;
- kgdb_registers.format = 0;
-
-#ifndef DEBUG
- if (remote_debug) {
-#endif
- printk("in handle_exception() trap=%d sigval=%d\n", trap, sigval );
- show_gdbregs();
-#ifndef DEBUG
- }
-#endif
-
- /*
- * reply to host that an exception has occurred
- */
- ptr = output_buffer;
-
- /*
- * Send trap type (converted to signal)
- */
- *ptr++ = 'T';
- *ptr++ = hexchars[sigval >> 4];
- *ptr++ = hexchars[sigval & 0xf];
-
- /*
- * Send Error PC
- */
- *ptr++ = hexchars[GDBREG_PC >> 4];
- *ptr++ = hexchars[GDBREG_PC & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)&kgdb_registers.pc, ptr, 4, 0);
- *ptr++ = ';';
-
- /*
- * Send frame pointer
- */
- *ptr++ = hexchars[GDBREG_A6 >> 4];
- *ptr++ = hexchars[GDBREG_A6 & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_A6], ptr, 4, 0);
- *ptr++ = ';';
-
- /*
- * Send stack pointer
- */
- *ptr++ = hexchars[GDBREG_SP >> 4];
- *ptr++ = hexchars[GDBREG_SP & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_SP], ptr, 4, 0);
- *ptr++ = ';';
-
- *ptr++ = 0;
- putpacket(output_buffer,1); /* send it off... */
-
- /*
- * Wait for input from remote GDB
- */
- for(;;) {
- output_buffer[0] = 0;
- getpacket(input_buffer);
-
- switch (input_buffer[0]) {
- case '?':
- output_buffer[0] = 'S';
- output_buffer[1] = hexchars[sigval >> 4];
- output_buffer[2] = hexchars[sigval & 0xf];
- output_buffer[3] = 0;
- break;
-
- case 'd':
- /* toggle debug flag */
- remote_debug = !remote_debug;
- break;
-
- /*
- * Return the value of the CPU registers
- */
- case 'g':
- ptr = output_buffer;
- ptr = mem2hex((char *)&kgdb_registers, ptr, NUMREGSBYTES, 0);
- break;
-
- /*
- * set the value of the CPU registers - return OK
- */
- case 'G':
- ptr = &input_buffer[1];
- ptr = hex2mem(ptr, (char *)&kgdb_registers, NUMREGSBYTES, 0);
- strcpy(output_buffer,"OK");
- break;
-
- /*
- * Pn...=r... Write register n
- */
- case 'P':
- ptr = &input_buffer[1];
- if (hexToInt(&ptr, &addr) && *ptr++ == '=') {
- if (addr >= 0 && addr <= GDBREG_PC)
- hex2mem(ptr, (char *)&kgdb_registers.regs[addr], 4, 0);
- else if (addr >= GDBREG_FP0 && addr <= GDBREG_FP7)
- hex2mem(ptr, (char *)&kgdb_registers.fpregs[addr-GDBREG_FP0],
- 12, 0);
- else if (addr >= GDBREG_FPCR && addr <= GDBREG_FPIAR)
- hex2mem(ptr, (char *)&kgdb_registers.fpcntl[addr-GDBREG_FPCR],
- 4, 0);
- }
- else
- strcpy(output_buffer,"E01");
- break;
-
- /*
- * mAA..AA,LLLL Read LLLL bytes at address AA..AA
- */
- case 'm':
- ptr = &input_buffer[1];
-
- if (hexToInt(&ptr, &addr)
- && *ptr++ == ','
- && hexToInt(&ptr, &length)) {
- if (mem2hex((char *)addr, output_buffer, length, 1))
- break;
- strcpy (output_buffer, "E03");
- } else
- strcpy(output_buffer,"E01");
- break;
-
- /*
- * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
- */
- case 'M':
- ptr = &input_buffer[1];
-
- if (hexToInt(&ptr, &addr)
- && *ptr++ == ','
- && hexToInt(&ptr, &length)
- && *ptr++ == ':') {
- if (hex2mem(ptr, (char *)addr, length, 1))
- strcpy(output_buffer, "OK");
- else
- strcpy(output_buffer, "E03");
- }
- else
- strcpy(output_buffer, "E02");
- break;
-
- /*
- * cAA..AA Continue at address AA..AA(optional)
- * sAA..AA Step one instruction from AA..AA(optional)
- */
- case 'c':
- case 's':
- /* try to read optional parameter, pc unchanged if no parm */
-
- ptr = &input_buffer[1];
- if (hexToInt(&ptr, &addr))
- kgdb_registers.pc = addr;
-
- kgdb_registers.sr &= 0x7fff; /* clear Trace bit */
- if (input_buffer[0] == 's')
- kgdb_registers.sr |= 0x8000; /* set it if step command */
-
- if (remote_debug)
- printk( "cont; new PC=0x%08lx SR=0x%04x\n",
- kgdb_registers.pc, kgdb_registers.sr );
-
- /*
- * Need to flush the instruction cache here, as we may
- * have deposited a breakpoint, and the icache probably
- * has no way of knowing that a data ref to some location
- * may have changed something that is in the instruction
- * cache.
- */
-
- if (m68k_is040or060)
- __asm__ __volatile__
- ( ".word 0xf4f8\n\t" /* CPUSHA I/D */
- ".word 0xf498" /* CINVA I */
- );
- else
- __asm__ __volatile__
- ( "movec %/cacr,%/d0\n\t"
- "oriw #0x0008,%/d0\n\t"
- "movec %/d0,%/cacr"
- : : : "d0" );
-
- return;
-
- /*
- * kill the program means reset the machine
- */
- case 'k' :
- case 'r':
- if (mach_reset) {
- /* reply OK before actual reset */
- strcpy(output_buffer,"OK");
- putpacket(output_buffer,0);
- mach_reset();
- }
- else
- strcpy(output_buffer,"E01");
- break;
-
- /*
- * Set baud rate (bBB)
- * FIXME: Needs to be written (in gdb, too...)
- */
- case 'b':
- strcpy(output_buffer,"E01");
- break;
-
- } /* switch */
-
- /*
- * reply to the request
- */
-
- putpacket(output_buffer,1);
-
- }
-}
-
-
-/*
- * Print registers (on target console)
- * Used only to debug the stub...
- */
-static void show_gdbregs( void )
-{
- printk( "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
- kgdb_registers.regs[0], kgdb_registers.regs[1],
- kgdb_registers.regs[2], kgdb_registers.regs[3] );
- printk( "d4: %08lx d5: %08lx d6: %08lx d7: %08lx\n",
- kgdb_registers.regs[4], kgdb_registers.regs[5],
- kgdb_registers.regs[6], kgdb_registers.regs[7] );
- printk( "a0: %08lx a1: %08lx a2: %08lx a3: %08lx\n",
- kgdb_registers.regs[8], kgdb_registers.regs[9],
- kgdb_registers.regs[10], kgdb_registers.regs[11] );
- printk( "a4: %08lx a5: %08lx a6: %08lx a7: %08lx\n",
- kgdb_registers.regs[12], kgdb_registers.regs[13],
- kgdb_registers.regs[14], kgdb_registers.regs[15] );
- printk( "pc: %08lx sr: %04x\n", kgdb_registers.pc, kgdb_registers.sr );
-}
-
-
-/* -------------------- Atari serial I/O -------------------- */
-
-#ifdef CONFIG_ATARI
-
-static int atari_mfp_out( unsigned char c )
-
-{
- while( !(mfp.trn_stat & 0x80) ) /* wait for tx buf empty */
- barrier();
- mfp.usart_dta = c;
- return( 1 );
-}
-
-
-static unsigned char atari_mfp_in( void )
-
-{
- while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
- barrier();
- return( mfp.usart_dta );
-}
-
-
-static unsigned char atari_mfp_intr( void )
-
-{
- return( mfp.usart_dta );
-}
-
-
-static int atari_scc_out( unsigned char c )
-
-{
- do {
- MFPDELAY();
- } while( !(scc.cha_b_ctrl & 0x04) ); /* wait for tx buf empty */
- MFPDELAY();
- scc.cha_b_data = c;
- return( 1 );
-}
-
-
-static unsigned char atari_scc_in( void )
-
-{
- do {
- MFPDELAY();
- } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
- MFPDELAY();
- return( scc.cha_b_data );
-}
-
-
-static unsigned char atari_scc_intr( void )
-
-{ unsigned char c, stat;
-
- MFPDELAY();
- scc.cha_b_ctrl = 1; /* RR1 */
- MFPDELAY();
- stat = scc.cha_b_ctrl;
- MFPDELAY();
- c = scc.cha_b_data;
- MFPDELAY();
- if (stat & 0x30) {
- scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */
- MFPDELAY();
- }
- scc.cha_b_ctrl = 0x38; /* reset highest IUS */
- MFPDELAY();
- return( c );
-}
-
-#endif
-
-/* -------------------- Macintosh serial I/O -------------------- */
-
-#ifdef CONFIG_MAC
-
-struct SCC
- {
- u_char cha_b_ctrl;
- u_char char_dummy1;
- u_char cha_a_ctrl;
- u_char char_dummy2;
- u_char cha_b_data;
- u_char char_dummy3;
- u_char cha_a_data;
- };
-
-#define scc (*((volatile struct SCC*)mac_bi_data.sccbase))
-
-#define uSEC 1
-#define LONG_DELAY() \
- do { \
- int i; \
- for( i = 60*uSEC; i > 0; --i ) \
- barrier(); \
- } while(0)
-
-static unsigned char mac_sccb_out (unsigned char c)
-{
- int i;
- do {
- LONG_DELAY();
- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
- for( i = uSEC; i > 0; --i )
- barrier();
- scc.cha_b_data = c;
-}
-
-static unsigned char mac_scca_out (unsigned char c)
-{
- int i;
- do {
- LONG_DELAY();
- } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
- for( i = uSEC; i > 0; --i )
- barrier();
- scc.cha_a_data = c;
-}
-
-static unsigned char mac_sccb_in( void )
-{
- do {
- LONG_DELAY();
- } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
- LONG_DELAY();
- return( scc.cha_b_data );
-}
-
-static unsigned char mac_scca_in( void )
-
-{
- do {
- LONG_DELAY();
- } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
- LONG_DELAY();
- return( scc.cha_a_data );
-}
-
-static unsigned char mac_sccb_intr( void )
-
-{ unsigned char c, stat;
-
- LONG_DELAY();
- scc.cha_b_ctrl = 1; /* RR1 */
- LONG_DELAY();
- stat = scc.cha_b_ctrl;
- LONG_DELAY();
- c = scc.cha_b_data;
- LONG_DELAY();
- if (stat & 0x30) {
- scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */
- LONG_DELAY();
- }
- scc.cha_b_ctrl = 0x38; /* reset highest IUS */
- LONG_DELAY();
- return( c );
-}
-
-static unsigned char mac_scca_intr( void )
-
-{ unsigned char c, stat;
-
- LONG_DELAY();
- scc.cha_a_ctrl = 1; /* RR1 */
- LONG_DELAY();
- stat = scc.cha_a_ctrl;
- LONG_DELAY();
- c = scc.cha_a_data;
- LONG_DELAY();
- if (stat & 0x30) {
- scc.cha_a_ctrl = 0x30; /* error reset for overrun and parity */
- LONG_DELAY();
- }
- scc.cha_a_ctrl = 0x38; /* reset highest IUS */
- LONG_DELAY();
- return( c );
-}
-
-#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)