Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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 Diff line number Diff line
@@ -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
+0 −1
Original line number 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-$(CONFIG_SH_DSP)			+= -Wa,-dsp
cflags-$(CONFIG_SH_KGDB)		+= -g

cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
+0 −148
Original line number Diff line number Diff line
@@ -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,
+54 −52
Original line number Diff line number Diff line
@@ -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;
@@ -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 */
	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;
}
@@ -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
+1 −93
Original line number Diff line number Diff line
@@ -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 */
Loading