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>
This commit is contained in:
Paul Mundt 2007-03-08 17:27:37 +09:00 committed by Paul Mundt
parent 15700770ef
commit fa5da2f7bd
8 changed files with 101 additions and 369 deletions

View File

@ -77,16 +77,17 @@ config 4KSTACKS
on the VM subsystem for higher order allocations. This option on the VM subsystem for higher order allocations. This option
will also use IRQ stacks to compensate for the reduced stackspace. will also use IRQ stacks to compensate for the reduced stackspace.
config KGDB config SH_KGDB
bool "Include KGDB kernel debugger" bool "Include KGDB kernel debugger"
select FRAME_POINTER select FRAME_POINTER
select DEBUG_INFO
help help
Include in-kernel hooks for kgdb, the Linux kernel source level Include in-kernel hooks for kgdb, the Linux kernel source level
debugger. See <http://kgdb.sourceforge.net/> for more information. debugger. See <http://kgdb.sourceforge.net/> for more information.
Unless you are intending to debug the kernel, say N here. Unless you are intending to debug the kernel, say N here.
menu "KGDB configuration options" menu "KGDB configuration options"
depends on KGDB depends on SH_KGDB
config MORE_COMPILE_OPTIONS config MORE_COMPILE_OPTIONS
bool "Add any additional compile options" bool "Add any additional compile options"
@ -109,16 +110,14 @@ config KGDB_THREAD
config SH_KGDB_CONSOLE config SH_KGDB_CONSOLE
bool "Console messages through GDB" bool "Console messages through GDB"
depends on !SERIAL_SH_SCI_CONSOLE
select SERIAL_CORE_CONSOLE
default n default n
config KGDB_SYSRQ config KGDB_SYSRQ
bool "Allow SysRq 'G' to enter KGDB" bool "Allow SysRq 'G' to enter KGDB"
default y default y
config KGDB_KERNEL_ASSERTS
bool "Include KGDB kernel assertions"
default n
comment "Serial port setup" comment "Serial port setup"
config KGDB_DEFPORT config KGDB_DEFPORT
@ -131,7 +130,7 @@ config KGDB_DEFBAUD
choice choice
prompt "Parity" prompt "Parity"
depends on KGDB depends on SH_KGDB
default KGDB_DEFPARITY_N default KGDB_DEFPARITY_N
config KGDB_DEFPARITY_N config KGDB_DEFPARITY_N
@ -147,7 +146,7 @@ endchoice
choice choice
prompt "Data bits" prompt "Data bits"
depends on KGDB depends on SH_KGDB
default KGDB_DEFBITS_8 default KGDB_DEFBITS_8
config KGDB_DEFBITS_8 config KGDB_DEFBITS_8

View File

@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding
cflags-$(CONFIG_SH_DSP) += -Wa,-dsp cflags-$(CONFIG_SH_DSP) += -Wa,-dsp
cflags-$(CONFIG_SH_KGDB) += -g
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \ cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g') $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')

View File

@ -14,153 +14,6 @@
#include <asm/se7751.h> #include <asm/se7751.h>
#include <asm/io.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 unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
static struct resource heartbeat_resources[] = { static struct resource heartbeat_resources[] = {
@ -197,7 +50,6 @@ __initcall(se7751_devices_setup);
*/ */
struct sh_machine_vector mv_7751se __initmv = { struct sh_machine_vector mv_7751se __initmv = {
.mv_name = "7751 SolutionEngine", .mv_name = "7751 SolutionEngine",
.mv_setup = sh7751se_setup,
.mv_nr_irqs = 72, .mv_nr_irqs = 72,
.mv_inb = sh7751se_inb, .mv_inb = sh7751se_inb,

View File

@ -6,11 +6,11 @@
* David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>, * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
* Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>, * Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>,
* Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>. * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
* *
* This version by Henry Bell <henry.bell@st.com> * This version by Henry Bell <henry.bell@st.com>
* Minor modifications by Jeremy Siegel <jsiegel@mvista.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 * To enable debugger support, two things need to happen. A call to
* set_debug_traps() is necessary in order to allow any breakpoints * set_debug_traps() is necessary in order to allow any breakpoints
@ -48,7 +48,7 @@
* k kill (Detach GDB) * k kill (Detach GDB)
* *
* d Toggle debug flag * d Toggle debug flag
* D Detach GDB * D Detach GDB
* *
* Hct Set thread t for operations, OK or ENN * Hct Set thread t for operations, OK or ENN
* c = 'c' (step, cont), c = 'g' (other * c = 'c' (step, cont), c = 'g' (other
@ -58,7 +58,7 @@
* qfThreadInfo Get list of current threads (first) m<id> * qfThreadInfo Get list of current threads (first) m<id>
* qsThreadInfo " " " " " (subsequent) * qsThreadInfo " " " " " (subsequent)
* qOffsets Get section offsets Text=x;Data=y;Bss=z * qOffsets Get section offsets Text=x;Data=y;Bss=z
* *
* TXX Find if thread XX is alive OK or ENN * TXX Find if thread XX is alive OK or ENN
* ? What was the last sigval ? SNN (signal NN) * ? What was the last sigval ? SNN (signal NN)
* O Output to GDB console * O Output to GDB console
@ -74,7 +74,7 @@
* '$' or '#'. If <data> starts with two characters followed by * '$' or '#'. If <data> starts with two characters followed by
* ':', then the existing stubs interpret this as a sequence number. * ':', 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. * checksum of <data>, the most significant nibble is sent first.
* the hex digits 0-9,a-f are used. * 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 * Responses can be run-length encoded to save space. A '*' means that
* the next character is an ASCII encoding giving a repeat count which * the next character is an ASCII encoding giving a repeat count which
* stands for that many repititions of the character preceding the '*'. * stands for that many repititions of the character preceding the '*'.
* The encoding is n+29, yielding a printable character where n >=3 * 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. * (which is where RLE starts to win). Don't use an n > 126.
* *
* So "0* " means the same as "0000". * So "0* " means the same as "0000".
*/ */
@ -100,12 +100,10 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#ifdef CONFIG_SH_KGDB_CONSOLE
#include <linux/console.h> #include <linux/console.h>
#endif #include <linux/sysrq.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
@ -153,7 +151,6 @@ char kgdb_in_gdb_mode;
char in_nmi; /* Set during NMI to prevent reentry */ char in_nmi; /* Set during NMI to prevent reentry */
int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */
int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */ int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */
int kgdb_halt;
/* Exposed for user access */ /* Exposed for user access */
struct task_struct *kgdb_current; 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 $, #, /* 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. */ after the last byte written. */
static char *ebin_to_mem(const char *buf, char *mem, int count) 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 */ /* Ack successful transfer */
put_debug_char('+'); put_debug_char('+');
/* If a sequence char is present, reply /* If a sequence char is present, reply
the sequence ID */ the sequence ID */
if (buffer[2] == ':') { if (buffer[2] == ':') {
put_debug_char(buffer[0]); put_debug_char(buffer[0]);
@ -759,7 +756,7 @@ static short *get_step_address(void)
return (short *) addr; 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 current instruction (i.e. next in the expected flow of control) with a
trap instruction, so that returning will cause only a single instruction trap instruction, so that returning will cause only a single instruction
to be executed. Note that this model is slightly broken for instructions to be executed. Note that this model is slightly broken for instructions
@ -1002,10 +999,8 @@ void set_thread_msg(void)
char *ptr; char *ptr;
switch (in_buffer[1]) { 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': case 'g':
ptr = &in_buffer[2]; ptr = &in_buffer[2];
hex_to_int(&ptr, &threadid); hex_to_int(&ptr, &threadid);
thread = get_thread(threadid); thread = get_thread(threadid);
@ -1173,6 +1168,7 @@ static void query_msg(void)
} }
#endif /* CONFIG_KGDB_THREAD */ #endif /* CONFIG_KGDB_THREAD */
#ifdef CONFIG_SH_KGDB_CONSOLE
/* /*
* Bring up the ports.. * Bring up the ports..
*/ */
@ -1185,6 +1181,9 @@ static int kgdb_serial_setup(void)
return 0; return 0;
} }
#else
#define kgdb_serial_setup() 0
#endif
/* The command loop, read and act on requests */ /* The command loop, read and act on requests */
static void kgdb_command_loop(const int excep_code, const int trapa_value) 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) { if (excep_code == NMI_VEC) {
#ifndef CONFIG_KGDB_NMI #ifndef CONFIG_KGDB_NMI
KGDB_PRINTK("Ignoring unexpected NMI?\n"); printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
return; return;
#else /* CONFIG_KGDB_NMI */ #else /* CONFIG_KGDB_NMI */
if (!kgdb_enabled) { 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) */ /* Enter GDB mode (e.g. after detach) */
if (!kgdb_in_gdb_mode) { if (!kgdb_in_gdb_mode) {
/* Do serial setup, notify user, issue preemptive ack */ /* Do serial setup, notify user, issue preemptive ack */
kgdb_serial_setup(); printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
(kgdb_porttype ? kgdb_porttype->name : ""),
kgdb_portnum, kgdb_baud);
kgdb_in_gdb_mode = 1; kgdb_in_gdb_mode = 1;
put_debug_char('+'); 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 will later be replaced by its original one. Do NOT do this for
trap 0xff, since that indicates a compiled-in breakpoint which trap 0xff, since that indicates a compiled-in breakpoint which
will not be replaced (and we would retake the trap forever) */ 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; trap_registers.pc -= 2;
}
/* Undo any stepping we may have done */ /* Undo any stepping we may have done */
undo_single_step(); undo_single_step();
while (1) { while (1) {
out_buffer[0] = 0; out_buffer[0] = 0;
get_packet(in_buffer, BUFMAX); get_packet(in_buffer, BUFMAX);
/* Examine first char of buffer to see what we need to do */ /* Examine first char of buffer to see what we need to do */
switch (in_buffer[0]) { switch (in_buffer[0]) {
case '?': /* Send which signal we've received */ case '?': /* Send which signal we've received */
send_signal_msg(sigval); send_signal_msg(sigval);
break; 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. */ /* There has been an exception, most likely a breakpoint. */
asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, static void handle_exception(struct pt_regs *regs)
unsigned long r6, unsigned long r7,
struct pt_regs __regs)
{ {
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int excep_code, vbr_val; int excep_code, vbr_val;
int count; int count;
int trapa_value = ctrl_inl(TRA); 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; kgdb_trapa_val = trapa_value;
/* Act on the exception */ /* Act on the exception */
kgdb_command_loop(excep_code >> 5, trapa_value); kgdb_command_loop(excep_code, trapa_value);
kgdb_current = NULL; 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)); asm("ldc %0, vbr": :"r"(vbr_val));
} }
/* Trigger a breakpoint by function */ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
void breakpoint(void) unsigned long r6, unsigned long r7,
struct pt_regs __regs)
{ {
if (!kgdb_enabled) { struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
kgdb_enabled = 1; handle_exception(regs);
kgdb_init();
}
BREAKPOINT();
} }
/* Initialise the KGDB data structures and serial configuration */ /* Initialise the KGDB data structures and serial configuration */
@ -1395,24 +1383,16 @@ int kgdb_init(void)
kgdb_in_gdb_mode = 0; kgdb_in_gdb_mode = 0;
if (kgdb_serial_setup() != 0) { if (kgdb_serial_setup() != 0) {
KGDB_PRINTK("serial setup error\n"); printk(KERN_NOTICE "KGDB: serial setup error\n");
return -1; return -1;
} }
/* Init ptr to exception handler */ /* Init ptr to exception handler */
kgdb_debug_hook = kgdb_handle_exception; kgdb_debug_hook = handle_exception;
kgdb_bus_err_hook = kgdb_handle_bus_error; kgdb_bus_err_hook = kgdb_handle_bus_error;
/* Enter kgdb now if requested, or just report init done */ /* Enter kgdb now if requested, or just report init done */
if (kgdb_halt) { printk(KERN_NOTICE "KGDB: stub is initialized.\n");
kgdb_in_gdb_mode = 1;
put_debug_char('+');
breakpoint();
}
else
{
KGDB_PRINTK("stub is initialized.\n");
}
return 0; return 0;
} }
@ -1437,7 +1417,7 @@ static void kgdb_msg_write(const char *s, unsigned count)
/* Calculate how many this time */ /* Calculate how many this time */
wcount = (count > MAXOUT) ? MAXOUT : count; wcount = (count > MAXOUT) ? MAXOUT : count;
/* Pack in hex chars */ /* Pack in hex chars */
for (i = 0; i < wcount; i++) for (i = 0; i < wcount; i++)
bufptr = pack_hex_byte(bufptr, s[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); kgdb_msg_write(s, count);
} }
#endif #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

View File

@ -25,11 +25,8 @@
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/clock.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; extern void * __rd_start, * __rd_end;
/* /*
* Machine setup.. * Machine setup..
*/ */
@ -499,92 +496,3 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo, .show = show_cpuinfo,
}; };
#endif /* CONFIG_PROC_FS */ #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 */

View File

@ -46,6 +46,7 @@
#endif #endif
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
#include <linux/ctype.h>
#include <asm/clock.h> #include <asm/clock.h>
#include <asm/sh_bios.h> #include <asm/sh_bios.h>
#include <asm/kgdb.h> #include <asm/kgdb.h>
@ -163,7 +164,7 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
usegdb |= sh_bios_in_gdb_mode(); usegdb |= sh_bios_in_gdb_mode();
#endif #endif
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
#endif #endif
if (usegdb) { if (usegdb) {
@ -204,7 +205,7 @@ static int kgdb_sci_getchar(void)
int c; int c;
/* Keep trying to read a character, this could be neater */ /* Keep trying to read a character, this could be neater */
while ((c = get_char(kgdb_sci_port)) < 0) while ((c = get_char(&kgdb_sci_port->port)) < 0)
cpu_relax(); cpu_relax();
return c; return c;
@ -212,7 +213,7 @@ static int kgdb_sci_getchar(void)
static inline void kgdb_sci_putchar(int c) static inline void kgdb_sci_putchar(int c)
{ {
put_char(kgdb_sci_port, c); put_char(&kgdb_sci_port->port, c);
} }
#endif /* CONFIG_SH_KGDB */ #endif /* CONFIG_SH_KGDB */
@ -738,7 +739,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
/* Break into the debugger if a break is detected */ /* Break into the debugger if a break is detected */
BREAKPOINT(); breakpoint();
#endif #endif
sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
@ -971,7 +972,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
{ {
struct sci_port *s = &sci_ports[port->line]; struct sci_port *s = &sci_ports[port->line];
unsigned int status, baud, smr_val; unsigned int status, baud, smr_val;
unsigned long flags;
int t; int t;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
@ -989,12 +989,10 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
#else #else
t = SCBRR_VALUE(baud); t = SCBRR_VALUE(baud);
#endif #endif
}
break; break;
}
} }
spin_lock_irqsave(&port->lock, flags);
do { do {
status = sci_in(port, SCxSR); status = sci_in(port, SCxSR);
} while (!(status & SCxSR_TEND(port))); } while (!(status & SCxSR_TEND(port)));
@ -1038,8 +1036,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CREAD) != 0) if ((termios->c_cflag & CREAD) != 0)
sci_start_rx(port,0); sci_start_rx(port,0);
spin_unlock_irqrestore(&port->lock, flags);
} }
static const char *sci_type(struct uart_port *port) static const char *sci_type(struct uart_port *port)
@ -1220,8 +1216,6 @@ static int __init serial_console_setup(struct console *co, char *options)
if (!port->membase || !port->mapbase) if (!port->membase || !port->mapbase)
return -ENODEV; return -ENODEV;
spin_lock_init(&port->lock);
port->type = serial_console_port->type; port->type = serial_console_port->type;
if (port->flags & UPF_IOREMAP) if (port->flags & UPF_IOREMAP)
@ -1247,7 +1241,7 @@ static struct console serial_console = {
.device = uart_console_device, .device = uart_console_device,
.write = serial_console_write, .write = serial_console_write,
.setup = serial_console_setup, .setup = serial_console_setup,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = -1, .index = -1,
.data = &sci_uart_driver, .data = &sci_uart_driver,
}; };
@ -1292,11 +1286,23 @@ int __init kgdb_console_setup(struct console *co, char *options)
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
spin_lock_init(&port->lock);
if (co->index != kgdb_portnum) if (co->index != kgdb_portnum)
co->index = kgdb_portnum; co->index = kgdb_portnum;
kgdb_sci_port = &sci_ports[co->index];
port = &kgdb_sci_port->port;
/*
* Also need to check port->type, we don't actually have any
* UPIO_PORT ports, but uart_report_port() handily misreports
* it anyways if we don't have a port available by the time this is
* called.
*/
if (!port->type)
return -ENODEV;
if (!port->membase || !port->mapbase)
return -ENODEV;
if (options) if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow); uart_parse_options(options, &baud, &parity, &bits, &flow);
else else
@ -1311,11 +1317,12 @@ int __init kgdb_console_setup(struct console *co, char *options)
#ifdef CONFIG_SH_KGDB_CONSOLE #ifdef CONFIG_SH_KGDB_CONSOLE
static struct console kgdb_console = { static struct console kgdb_console = {
.name = "ttySC", .name = "ttySC",
.write = kgdb_console_write, .device = uart_console_device,
.setup = kgdb_console_setup, .write = kgdb_console_write,
.flags = CON_PRINTBUFFER | CON_ENABLED, .setup = kgdb_console_setup,
.index = -1, .flags = CON_PRINTBUFFER,
.index = -1,
.data = &sci_uart_driver, .data = &sci_uart_driver,
}; };
@ -1386,6 +1393,12 @@ static int __devinit sci_probe(struct platform_device *dev)
uart_add_one_port(&sci_uart_driver, &sciport->port); uart_add_one_port(&sci_uart_driver, &sciport->port);
} }
#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
kgdb_sci_port = &sci_ports[kgdb_portnum];
kgdb_getchar = kgdb_sci_getchar;
kgdb_putchar = kgdb_sci_putchar;
#endif
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");

View File

@ -17,6 +17,7 @@
#define __KGDB_H #define __KGDB_H
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/cacheflush.h>
struct console; struct console;
@ -45,35 +46,21 @@ extern int kgdb_portnum;
extern int kgdb_baud; extern int kgdb_baud;
extern char kgdb_parity; extern char kgdb_parity;
extern char kgdb_bits; extern char kgdb_bits;
extern int kgdb_console_setup(struct console *, char *);
/* Init and interface stuff */ /* Init and interface stuff */
extern int kgdb_init(void); extern int kgdb_init(void);
extern int (*kgdb_serial_setup)(void);
extern int (*kgdb_getchar)(void); extern int (*kgdb_getchar)(void);
extern void (*kgdb_putchar)(int); extern void (*kgdb_putchar)(int);
struct kgdb_sermap {
char *name;
int namelen;
int (*setup_fn)(struct console *, char *);
struct kgdb_sermap *next;
};
extern void kgdb_register_sermap(struct kgdb_sermap *map);
extern struct kgdb_sermap *kgdb_porttype;
/* Trap functions */ /* Trap functions */
typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
typedef void (kgdb_bus_error_hook_t)(void); typedef void (kgdb_bus_error_hook_t)(void);
extern kgdb_debug_hook_t *kgdb_debug_hook; extern kgdb_debug_hook_t *kgdb_debug_hook;
extern kgdb_bus_error_hook_t *kgdb_bus_err_hook; extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
extern void breakpoint(void);
/* Console */ /* Console */
struct console;
void kgdb_console_write(struct console *co, const char *s, unsigned count); void kgdb_console_write(struct console *co, const char *s, unsigned count);
void kgdb_console_init(void); extern int kgdb_console_setup(struct console *, char *);
/* Prototypes for jmp fns */ /* Prototypes for jmp fns */
#define _JBLEN 9 #define _JBLEN 9
@ -81,11 +68,8 @@ typedef int jmp_buf[_JBLEN];
extern void longjmp(jmp_buf __jmpb, int __retval); extern void longjmp(jmp_buf __jmpb, int __retval);
extern int setjmp(jmp_buf __jmpb); extern int setjmp(jmp_buf __jmpb);
/* Variadic macro to print our own message to the console */
#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
/* Forced breakpoint */ /* Forced breakpoint */
#define BREAKPOINT() \ #define breakpoint() \
do { \ do { \
if (kgdb_enabled) \ if (kgdb_enabled) \
__asm__ __volatile__("trapa #0x3c"); \ __asm__ __volatile__("trapa #0x3c"); \
@ -95,7 +79,6 @@ do { \
#if defined(CONFIG_CPU_SH4) #if defined(CONFIG_CPU_SH4)
#define kgdb_flush_icache_range(start, end) \ #define kgdb_flush_icache_range(start, end) \
{ \ { \
extern void __flush_purge_region(void *, int); \
__flush_purge_region((void*)(start), (int)(end) - (int)(start));\ __flush_purge_region((void*)(start), (int)(end) - (int)(start));\
flush_icache_range((start), (end)); \ flush_icache_range((start), (end)); \
} }
@ -103,31 +86,6 @@ do { \
#define kgdb_flush_icache_range(start, end) do { } while (0) #define kgdb_flush_icache_range(start, end) do { } while (0)
#endif #endif
/* Kernel assert macros */
#ifdef CONFIG_KGDB_KERNEL_ASSERTS
/* Predefined conditions */
#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
#define KA_VALID_KPTR(ptr) (!(ptr) || \
((void *)(ptr) >= (void *)PAGE_OFFSET && \
(void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
#define KA_VALID_PTRORERR(errptr) \
(KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
#define KA_HELD_GKL() (current->lock_depth >= 0)
/* The actual assert */
#define KGDB_ASSERT(condition, message) do { \
if (!(condition) && (kgdb_enabled)) { \
KGDB_PRINTK("Assertion failed at %s:%d: %s\n", \
__FILE__, __LINE__, message);\
BREAKPOINT(); \
} \
} while (0)
#else
#define KGDB_ASSERT(condition, message)
#endif
/* Taken from sh-stub.c of GDB 4.18 */ /* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef"; static const char hexchars[] = "0123456789abcdef";
@ -142,5 +100,4 @@ static inline char lowhex(const int x)
{ {
return hexchars[x & 0xf]; return hexchars[x & 0xf];
} }
#endif #endif

View File

@ -65,6 +65,8 @@
#define IRQ_79C973 13 #define IRQ_79C973 13
void init_7751se_IRQ(void);
#define __IO_PREFIX sh7751se #define __IO_PREFIX sh7751se
#include <asm/io_generic.h> #include <asm/io_generic.h>