Commit fa5da2f7 authored by Paul Mundt's avatar Paul Mundt Committed by Paul Mundt
Browse files

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: default avatarPaul Mundt <lethal@linux-sh.org>
parent 15700770
Loading
Loading
Loading
Loading
+7 −8
Original line number Original line Diff line number Diff line
@@ -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
+0 −1
Original line number Original line Diff line number Diff line
@@ -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')
+0 −148
Original line number Original line Diff line number Diff line
@@ -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,
+54 −52
Original line number Original line Diff line number Diff line
@@ -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
+1 −93
Original line number Original line Diff line number Diff line
@@ -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 */
Loading