diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-03-08 17:27:37 +0900 |
---|---|---|
committer | Paul Mundt <lethal@hera.kernel.org> | 2007-05-07 02:10:51 +0000 |
commit | fa5da2f7bdcf885efe65a37df13907c7d72296f6 (patch) | |
tree | 54104d5f660a1ec824505b28540eb2c5e4be390a /arch/sh | |
parent | 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37 (diff) | |
download | lwn-fa5da2f7bdcf885efe65a37df13907c7d72296f6.tar.gz lwn-fa5da2f7bdcf885efe65a37df13907c7d72296f6.zip |
sh: Bring kgdb back from the dead.
This code has suffered quite a bit of bitrot, do some basic
tidying to get it to a reasonably functional state again.
This gets the basic support and the console working again.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/Kconfig.debug | 15 | ||||
-rw-r--r-- | arch/sh/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/boards/se/7751/setup.c | 148 | ||||
-rw-r--r-- | arch/sh/kernel/kgdb_stub.c | 106 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 94 |
5 files changed, 62 insertions, 302 deletions
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 87902e0298e2..6be2385c1ad2 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -77,16 +77,17 @@ config 4KSTACKS on the VM subsystem for higher order allocations. This option will also use IRQ stacks to compensate for the reduced stackspace. -config KGDB +config SH_KGDB bool "Include KGDB kernel debugger" select FRAME_POINTER + select DEBUG_INFO help Include in-kernel hooks for kgdb, the Linux kernel source level debugger. See <http://kgdb.sourceforge.net/> for more information. Unless you are intending to debug the kernel, say N here. menu "KGDB configuration options" - depends on KGDB + depends on SH_KGDB config MORE_COMPILE_OPTIONS bool "Add any additional compile options" @@ -109,16 +110,14 @@ config KGDB_THREAD config SH_KGDB_CONSOLE bool "Console messages through GDB" + depends on !SERIAL_SH_SCI_CONSOLE + select SERIAL_CORE_CONSOLE default n config KGDB_SYSRQ bool "Allow SysRq 'G' to enter KGDB" default y -config KGDB_KERNEL_ASSERTS - bool "Include KGDB kernel assertions" - default n - comment "Serial port setup" config KGDB_DEFPORT @@ -131,7 +130,7 @@ config KGDB_DEFBAUD choice prompt "Parity" - depends on KGDB + depends on SH_KGDB default KGDB_DEFPARITY_N config KGDB_DEFPARITY_N @@ -147,7 +146,7 @@ endchoice choice prompt "Data bits" - depends on KGDB + depends on SH_KGDB default KGDB_DEFBITS_8 config KGDB_DEFBITS_8 diff --git a/arch/sh/Makefile b/arch/sh/Makefile index bd9b1729f8b8..0fadde283368 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding cflags-$(CONFIG_SH_DSP) += -Wa,-dsp -cflags-$(CONFIG_SH_KGDB) += -g cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \ $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g') diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c index e3feae6ec0bf..770defed9c4a 100644 --- a/arch/sh/boards/se/7751/setup.c +++ b/arch/sh/boards/se/7751/setup.c @@ -14,153 +14,6 @@ #include <asm/se7751.h> #include <asm/io.h> -void init_7751se_IRQ(void); - -#ifdef CONFIG_SH_KGDB -#include <asm/kgdb.h> -static int kgdb_uart_setup(void); -static struct kgdb_sermap kgdb_uart_sermap = -{ "ttyS", 0, kgdb_uart_setup, NULL }; -#endif - -/* - * Initialize the board - */ -static void __init sh7751se_setup(char **cmdline_p) -{ - /* Call init_smsc() replacement to set up SuperIO. */ - /* XXX: RTC setting comes here */ -#ifdef CONFIG_SH_KGDB - kgdb_register_sermap(&kgdb_uart_sermap); -#endif -} - -/********************************************************************* - * Currently a hack (e.g. does not interact well w/serial.c, lots of * - * hardcoded stuff) but may be useful if SCI/F needs debugging. * - * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and * - * arch/i386/lib/kgdb_serial.c). * - *********************************************************************/ - -#ifdef CONFIG_SH_KGDB -#include <linux/types.h> -#include <linux/serial.h> -#include <linux/serialP.h> -#include <linux/serial_reg.h> - -#define COM1_PORT 0x3f8 /* Base I/O address */ -#define COM1_IRQ 4 /* IRQ not used yet */ -#define COM2_PORT 0x2f8 /* Base I/O address */ -#define COM2_IRQ 3 /* IRQ not used yet */ - -#define SB_CLOCK 1843200 /* Serial baud clock */ -#define SB_BASE (SB_CLOCK/16) -#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS - -struct uart_port { - int base; -}; -#define UART_NPORTS 2 -struct uart_port uart_ports[] = { - { COM1_PORT }, - { COM2_PORT }, -}; -struct uart_port *kgdb_uart_port; - -#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg) -#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg) - -/* Basic read/write functions for the UART */ -#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE) -static int kgdb_uart_getchar(void) -{ - int lsr; - int c = -1; - - while (c == -1) { - lsr = UART_IN(UART_LSR); - if (lsr & UART_LSR_DR) - c = UART_IN(UART_RX); - if ((lsr & UART_LSR_RXCERR)) - c = -1; - } - return c; -} - -static void kgdb_uart_putchar(int c) -{ - while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0) - ; - UART_OUT(UART_TX, c); -} - -/* - * Initialize UART to configured/requested values. - * (But we don't interrupts yet, or interact w/serial.c) - */ -static int kgdb_uart_setup(void) -{ - int port; - int lcr = 0; - int bdiv = 0; - - if (kgdb_portnum >= UART_NPORTS) { - KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum); - return -1; - } - - kgdb_uart_port = &uart_ports[kgdb_portnum]; - - /* Init sequence from gdb_hook_interrupt */ - UART_IN(UART_RX); - UART_OUT(UART_IER, 0); - - UART_IN(UART_RX); /* Serial driver comments say */ - UART_IN(UART_IIR); /* this clears interrupt regs */ - UART_IN(UART_MSR); - - /* Figure basic LCR values */ - switch (kgdb_bits) { - case '7': - lcr |= UART_LCR_WLEN7; - break; - default: case '8': - lcr |= UART_LCR_WLEN8; - break; - } - switch (kgdb_parity) { - case 'O': - lcr |= UART_LCR_PARITY; - break; - case 'E': - lcr |= (UART_LCR_PARITY | UART_LCR_EPAR); - break; - default: break; - } - - /* Figure the baud rate divisor */ - bdiv = (SB_BASE/kgdb_baud); - - /* Set the baud rate and LCR values */ - UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB)); - UART_OUT(UART_DLL, (bdiv & 0xff)); - UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff)); - UART_OUT(UART_LCR, lcr); - - /* Set the MCR */ - UART_OUT(UART_MCR, SB_MCR); - - /* Turn off FIFOs for now */ - UART_OUT(UART_FCR, 0); - - /* Setup complete: initialize function pointers */ - kgdb_getchar = kgdb_uart_getchar; - kgdb_putchar = kgdb_uart_putchar; - - return 0; -} -#endif /* CONFIG_SH_KGDB */ - static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct resource heartbeat_resources[] = { @@ -197,7 +50,6 @@ __initcall(se7751_devices_setup); */ struct sh_machine_vector mv_7751se __initmv = { .mv_name = "7751 SolutionEngine", - .mv_setup = sh7751se_setup, .mv_nr_irqs = 72, .mv_inb = sh7751se_inb, diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index d8927d85492e..737eadc8ce0f 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c @@ -6,11 +6,11 @@ * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>, * Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>, * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>. - * + * * This version by Henry Bell <henry.bell@st.com> * Minor modifications by Jeremy Siegel <jsiegel@mvista.com> - * - * Contains low-level support for remote debug using GDB. + * + * Contains low-level support for remote debug using GDB. * * To enable debugger support, two things need to happen. A call to * set_debug_traps() is necessary in order to allow any breakpoints @@ -48,7 +48,7 @@ * k kill (Detach GDB) * * d Toggle debug flag - * D Detach GDB + * D Detach GDB * * Hct Set thread t for operations, OK or ENN * c = 'c' (step, cont), c = 'g' (other @@ -58,7 +58,7 @@ * qfThreadInfo Get list of current threads (first) m<id> * qsThreadInfo " " " " " (subsequent) * qOffsets Get section offsets Text=x;Data=y;Bss=z - * + * * TXX Find if thread XX is alive OK or ENN * ? What was the last sigval ? SNN (signal NN) * O Output to GDB console @@ -74,7 +74,7 @@ * '$' or '#'. If <data> starts with two characters followed by * ':', then the existing stubs interpret this as a sequence number. * - * CSUM1 and CSUM2 are ascii hex representation of an 8-bit + * CSUM1 and CSUM2 are ascii hex representation of an 8-bit * checksum of <data>, the most significant nibble is sent first. * the hex digits 0-9,a-f are used. * @@ -86,8 +86,8 @@ * Responses can be run-length encoded to save space. A '*' means that * the next character is an ASCII encoding giving a repeat count which * stands for that many repititions of the character preceding the '*'. - * The encoding is n+29, yielding a printable character where n >=3 - * (which is where RLE starts to win). Don't use an n > 126. + * The encoding is n+29, yielding a printable character where n >=3 + * (which is where RLE starts to win). Don't use an n > 126. * * So "0* " means the same as "0000". */ @@ -100,12 +100,10 @@ #include <linux/delay.h> #include <linux/linkage.h> #include <linux/init.h> - -#ifdef CONFIG_SH_KGDB_CONSOLE #include <linux/console.h> -#endif - +#include <linux/sysrq.h> #include <asm/system.h> +#include <asm/cacheflush.h> #include <asm/current.h> #include <asm/signal.h> #include <asm/pgtable.h> @@ -153,7 +151,6 @@ char kgdb_in_gdb_mode; char in_nmi; /* Set during NMI to prevent reentry */ int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */ -int kgdb_halt; /* Exposed for user access */ struct task_struct *kgdb_current; @@ -328,7 +325,7 @@ static int hex_to_int(char **ptr, int *int_value) } /* Copy the binary array pointed to by buf into mem. Fix $, #, - and 0x7d escaped with 0x7d. Return a pointer to the character + and 0x7d escaped with 0x7d. Return a pointer to the character after the last byte written. */ static char *ebin_to_mem(const char *buf, char *mem, int count) { @@ -452,7 +449,7 @@ static void get_packet(char *buffer, int buflen) /* Ack successful transfer */ put_debug_char('+'); - /* If a sequence char is present, reply + /* If a sequence char is present, reply the sequence ID */ if (buffer[2] == ':') { put_debug_char(buffer[0]); @@ -759,7 +756,7 @@ static short *get_step_address(void) return (short *) addr; } -/* Set up a single-step. Replace the instruction immediately after the +/* Set up a single-step. Replace the instruction immediately after the current instruction (i.e. next in the expected flow of control) with a trap instruction, so that returning will cause only a single instruction to be executed. Note that this model is slightly broken for instructions @@ -1002,10 +999,8 @@ void set_thread_msg(void) char *ptr; switch (in_buffer[1]) { - - /* To select which thread for gG etc messages, i.e. supported */ + /* To select which thread for gG etc messages, i.e. supported */ case 'g': - ptr = &in_buffer[2]; hex_to_int(&ptr, &threadid); thread = get_thread(threadid); @@ -1173,6 +1168,7 @@ static void query_msg(void) } #endif /* CONFIG_KGDB_THREAD */ +#ifdef CONFIG_SH_KGDB_CONSOLE /* * Bring up the ports.. */ @@ -1185,6 +1181,9 @@ static int kgdb_serial_setup(void) return 0; } +#else +#define kgdb_serial_setup() 0 +#endif /* The command loop, read and act on requests */ static void kgdb_command_loop(const int excep_code, const int trapa_value) @@ -1193,7 +1192,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) if (excep_code == NMI_VEC) { #ifndef CONFIG_KGDB_NMI - KGDB_PRINTK("Ignoring unexpected NMI?\n"); + printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n"); return; #else /* CONFIG_KGDB_NMI */ if (!kgdb_enabled) { @@ -1216,10 +1215,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) /* Enter GDB mode (e.g. after detach) */ if (!kgdb_in_gdb_mode) { /* Do serial setup, notify user, issue preemptive ack */ - kgdb_serial_setup(); - KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n", - (kgdb_porttype ? kgdb_porttype->name : ""), - kgdb_portnum, kgdb_baud); + printk(KERN_NOTICE "KGDB: Waiting for GDB\n"); kgdb_in_gdb_mode = 1; put_debug_char('+'); } @@ -1233,21 +1229,18 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) will later be replaced by its original one. Do NOT do this for trap 0xff, since that indicates a compiled-in breakpoint which will not be replaced (and we would retake the trap forever) */ - if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) { + if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2))) trap_registers.pc -= 2; - } /* Undo any stepping we may have done */ undo_single_step(); while (1) { - out_buffer[0] = 0; get_packet(in_buffer, BUFMAX); /* Examine first char of buffer to see what we need to do */ switch (in_buffer[0]) { - case '?': /* Send which signal we've received */ send_signal_msg(sigval); break; @@ -1323,11 +1316,8 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) } /* There has been an exception, most likely a breakpoint. */ -asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs __regs) +static void handle_exception(struct pt_regs *regs) { - struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int excep_code, vbr_val; int count; int trapa_value = ctrl_inl(TRA); @@ -1355,7 +1345,7 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, kgdb_trapa_val = trapa_value; /* Act on the exception */ - kgdb_command_loop(excep_code >> 5, trapa_value); + kgdb_command_loop(excep_code, trapa_value); kgdb_current = NULL; @@ -1373,14 +1363,12 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, asm("ldc %0, vbr": :"r"(vbr_val)); } -/* Trigger a breakpoint by function */ -void breakpoint(void) +asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) { - if (!kgdb_enabled) { - kgdb_enabled = 1; - kgdb_init(); - } - BREAKPOINT(); + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + handle_exception(regs); } /* Initialise the KGDB data structures and serial configuration */ @@ -1395,24 +1383,16 @@ int kgdb_init(void) kgdb_in_gdb_mode = 0; if (kgdb_serial_setup() != 0) { - KGDB_PRINTK("serial setup error\n"); + printk(KERN_NOTICE "KGDB: serial setup error\n"); return -1; } /* Init ptr to exception handler */ - kgdb_debug_hook = kgdb_handle_exception; + kgdb_debug_hook = handle_exception; kgdb_bus_err_hook = kgdb_handle_bus_error; /* Enter kgdb now if requested, or just report init done */ - if (kgdb_halt) { - kgdb_in_gdb_mode = 1; - put_debug_char('+'); - breakpoint(); - } - else - { - KGDB_PRINTK("stub is initialized.\n"); - } + printk(KERN_NOTICE "KGDB: stub is initialized.\n"); return 0; } @@ -1437,7 +1417,7 @@ static void kgdb_msg_write(const char *s, unsigned count) /* Calculate how many this time */ wcount = (count > MAXOUT) ? MAXOUT : count; - + /* Pack in hex chars */ for (i = 0; i < wcount; i++) bufptr = pack_hex_byte(bufptr, s[i]); @@ -1467,3 +1447,25 @@ void kgdb_console_write(struct console *co, const char *s, unsigned count) kgdb_msg_write(s, count); } #endif + +#ifdef CONFIG_KGDB_SYSRQ +static void sysrq_handle_gdb(int key, struct tty_struct *tty) +{ + printk("Entering GDB stub\n"); + breakpoint(); +} + +static struct sysrq_key_op sysrq_gdb_op = { + .handler = sysrq_handle_gdb, + .help_msg = "Gdb", + .action_msg = "GDB", +}; + +static int gdb_register_sysrq(void) +{ + printk("Registering GDB sysrq handler\n"); + register_sysrq_key('g', &sysrq_gdb_op); + return 0; +} +module_init(gdb_register_sysrq); +#endif diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 98802ab28211..f96490419768 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -25,11 +25,8 @@ #include <asm/setup.h> #include <asm/clock.h> -#ifdef CONFIG_SH_KGDB -#include <asm/kgdb.h> -static int kgdb_parse_options(char *options); -#endif extern void * __rd_start, * __rd_end; + /* * Machine setup.. */ @@ -499,92 +496,3 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; #endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_SH_KGDB -/* - * Parse command-line kgdb options. By default KGDB is enabled, - * entered on error (or other action) using default serial info. - * The command-line option can include a serial port specification - * and an action to override default or configured behavior. - */ -struct kgdb_sermap kgdb_sci_sermap = -{ "ttySC", 5, kgdb_sci_setup, NULL }; - -struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap; -struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap; - -void kgdb_register_sermap(struct kgdb_sermap *map) -{ - struct kgdb_sermap *last; - - for (last = kgdb_serlist; last->next; last = last->next) - ; - last->next = map; - if (!map->namelen) { - map->namelen = strlen(map->name); - } -} - -static int __init kgdb_parse_options(char *options) -{ - char c; - int baud; - - /* Check for port spec (or use default) */ - - /* Determine port type and instance */ - if (!memcmp(options, "tty", 3)) { - struct kgdb_sermap *map = kgdb_serlist; - - while (map && memcmp(options, map->name, map->namelen)) - map = map->next; - - if (!map) { - KGDB_PRINTK("unknown port spec in %s\n", options); - return -1; - } - - kgdb_porttype = map; - kgdb_serial_setup = map->setup_fn; - kgdb_portnum = options[map->namelen] - '0'; - options += map->namelen + 1; - - options = (*options == ',') ? options+1 : options; - - /* Read optional parameters (baud/parity/bits) */ - baud = simple_strtoul(options, &options, 10); - if (baud != 0) { - kgdb_baud = baud; - - c = toupper(*options); - if (c == 'E' || c == 'O' || c == 'N') { - kgdb_parity = c; - options++; - } - - c = *options; - if (c == '7' || c == '8') { - kgdb_bits = c; - options++; - } - options = (*options == ',') ? options+1 : options; - } - } - - /* Check for action specification */ - if (!memcmp(options, "halt", 4)) { - kgdb_halt = 1; - options += 4; - } else if (!memcmp(options, "disabled", 8)) { - kgdb_enabled = 0; - options += 8; - } - - if (*options) { - KGDB_PRINTK("ignored unknown options: %s\n", options); - return 0; - } - return 1; -} -__setup("kgdb=", kgdb_parse_options); -#endif /* CONFIG_SH_KGDB */ |