mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-07 03:18:31 +00:00
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:
parent
15700770ef
commit
fa5da2f7bd
8 changed files with 101 additions and 369 deletions
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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 */
|
|
||||||
|
|
|
@ -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,11 +989,9 @@ 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);
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -1312,9 +1318,10 @@ 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",
|
||||||
|
.device = uart_console_device,
|
||||||
.write = kgdb_console_write,
|
.write = kgdb_console_write,
|
||||||
.setup = kgdb_console_setup,
|
.setup = kgdb_console_setup,
|
||||||
.flags = CON_PRINTBUFFER | CON_ENABLED,
|
.flags = CON_PRINTBUFFER,
|
||||||
.index = -1,
|
.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");
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue