lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat,  9 Feb 2008 07:35:13 -0600
From:	jason.wessel@...driver.com
To:	linux-kernel@...r.kernel.org
Cc:	Jason Wessel <jason.wessel@...driver.com>,
	linux-serial@...r.kernel.org, Jan Kiszka <jan.kiszka@....de>,
	Ingo Molnar <mingo@...e.hu>,
	Thomas Gleixner <tglx@...utronix.de>
Subject: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver

From: Jason Wessel <jason.wessel@...driver.com>

This patch some small hooks into the normal serial core so that a uart
can be unregistered to be exclusively used for KGDB.  These changes
allow for registering and unregistering a port with a struct
uart_port. From that point on KGDB does raw accesses to the serial
IO ports it has taken over.

CC: linux-serial@...r.kernel.org
Signed-off-by: Jason Wessel <jason.wessel@...driver.com>
Signed-off-by: Jan Kiszka <jan.kiszka@....de>
Signed-off-by: Ingo Molnar <mingo@...e.hu>
Signed-off-by: Thomas Gleixner <tglx@...utronix.de>
---
 Documentation/DocBook/kgdb.tmpl |   44 ++++
 drivers/serial/8250.c           |   30 +++
 drivers/serial/8250_kgdb.c      |  489 +++++++++++++++++++++++++++++++++++++++
 drivers/serial/Kconfig          |    2 +-
 drivers/serial/Makefile         |    1 +
 drivers/serial/serial_core.c    |   18 ++-
 include/linux/serial_8250.h     |    2 +
 lib/Kconfig.kgdb                |   21 ++
 8 files changed, 603 insertions(+), 4 deletions(-)
 create mode 100644 drivers/serial/8250_kgdb.c

diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index c423411..111a2a0 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -92,6 +92,50 @@
   <chapter id="BootingTheKernel">
     <title>Booting the kernel</title>
     <para>
+    The Kernel command line option <constant>kgdbwait</constant> makes kgdb
+    wait for gdb connection during booting of a kernel.  If the
+    <symbol>CONFIG_KGDB_8250</symbol> driver is used (or if applicable,
+    another serial driver) this breakpoint will happen very early on, before
+    console output.
+    </para>
+    <para>
+    The serial port configuration must be passed via the
+    option <constant>kgdb8250=&lt;io|mmio&gt;,&lt;address&gt;[/&lt;regshift&gt;],&lt;baud
+    rate&gt;,&lt;irq&gt;</constant>.  The values <constant>io</constant> or
+    <constant>mmio</constant> refer to if the address being passed next needs
+    to be memory mapped (<constant>mmio</constant>) or not.  The
+    <constant>address</constant> must be passed in hex and is the hardware
+    address and will be remapped if passed as <constant>mmio</constant>. An
+    optional <constant>regshift</constant> value can be given to express
+    address spreading of the 8250 registers. <constant>regshift</constant>
+    just as the succeeding <constant>baud rate</constant> and
+    <constant>irq</constant> values are base-10. The supported values for
+    <constant>baud rate</constant> are <constant>9600</constant>,
+    <constant>19200</constant>, <constant>38400</constant>,
+    <constant>57600</constant>, and <constant>115200</constant>.
+    </para>
+    <para>
+    To specify the values of the serial port at boot:
+    </para>
+    <para>
+    <constant>kgdb8250=io,3f8,115200,3</constant>
+    </para>
+    <para>
+    On IA64 this could also be:
+    </para>
+    <para>
+    <constant>kgdb8250=mmio,0xff5e0000,115200,74</constant>
+    </para>
+    <para>
+    If the debugger is not needed early, the alternative configuration format
+    <constant>kgdb8250=ttyS&lt;n&gt;,&lt;baud rate&gt;</constant> can be used.
+    The required parameters are then obtained from the standard 8250 driver.
+    Example:
+    </para>
+    <para>
+    <constant>kgdb8250=ttyS0,115200</constant>
+    </para>
+    <para>
     All drivers can be reconfigured at run time, if
     <symbol>CONFIG_SYSFS</symbol> and <symbol>CONFIG_MODULES</symbol> are
     enabled, by echo'ing a new config string to
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 77f7a7f..2b37370 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2580,6 +2580,7 @@ int serial8250_find_port(struct uart_port *p)
 	}
 	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(serial8250_find_port);
 
 #define SERIAL8250_CONSOLE	&serial8250_console
 #else
@@ -2863,6 +2864,35 @@ void serial8250_unregister_port(int line)
 }
 EXPORT_SYMBOL(serial8250_unregister_port);
 
+/**
+ *  serial8250_get_port_def - Get port definition for a specific line
+ *  @port: generic uart_port output for a specific serial line
+ *  @line: specific serial line index
+ *
+ *  Return 0 if the port existed
+ *  Return -errno on failure
+ */
+int serial8250_get_port_def(struct uart_port *port, int line)
+{
+	struct uart_port *port8250 = &serial8250_ports[line].port;
+
+	if (!port8250->iobase && !port8250->membase)
+		return -ENODEV;
+
+	port->iobase   = port8250->iobase;
+	port->membase  = port8250->membase;
+	port->irq      = port8250->irq;
+	port->uartclk  = port8250->uartclk;
+	port->fifosize = port8250->fifosize;
+	port->regshift = port8250->regshift;
+	port->iotype   = port8250->iotype;
+	port->flags    = port8250->flags;
+	port->mapbase  = port8250->mapbase;
+	port->dev      = port8250->dev;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_get_port_def);
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
diff --git a/drivers/serial/8250_kgdb.c b/drivers/serial/8250_kgdb.c
new file mode 100644
index 0000000..ef0ebcf
--- /dev/null
+++ b/drivers/serial/8250_kgdb.c
@@ -0,0 +1,489 @@
+/*
+ * 8250 serial I/O driver for KGDB.
+ *
+ * This is a merging of many different drivers, and all of the people have
+ * had an impact in some form or another:
+ *
+ * 2004-2005 (c) MontaVista Software, Inc.
+ * 2005-2006 (c) Wind River Systems, Inc.
+ *
+ * Amit Kale <amitkale@...yssoft.com>, David Grothe <dave@...m.com>,
+ * Scott Foehner <sfoehner@...r.sgi.com>, George Anzinger <george@...sta.com>,
+ * Robert Walsh <rjwalsh@...ables.org>, wangdi <wangdi@...sterfs.com>,
+ * San Mehat, Tom Rini <trini@...sta.com>,
+ * Jason Wessel <jason.wessel@...driver.com>
+ *
+ * Refactoring and cleanup for initial merge:
+ * 2008 (c) Jan Kiszka <jan.kiszka@....de>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/interrupt.h>
+#include <linux/serial_reg.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <asm/serial.h>		/* for BASE_BAUD */
+
+MODULE_DESCRIPTION("KGDB driver for the 8250");
+MODULE_LICENSE("GPL");
+
+#define KGD8250_MAX_CONFIG_STR	64
+static char config[KGD8250_MAX_CONFIG_STR];
+static struct kparam_string kps = {
+	.string = config,
+	.maxlen = KGD8250_MAX_CONFIG_STR,
+};
+
+static int kgdb8250_baud;
+static void *kgdb8250_addr;
+static int kgdb8250_irq = -1;
+static struct uart_port kgdb8250_port;
+
+/* UART port we might have stolen from the 8250 driver */
+static int hijacked_line;
+
+static int late_init_passed;
+static int fully_initialized;
+static int buffered_char = -1;
+
+static struct kgdb_io kgdb8250_io_ops;	/* initialized later */
+
+static int kgdb8250_uart_init(void);
+
+static inline unsigned int kgdb8250_ioread(u8 mask)
+{
+	return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift));
+}
+
+static inline void kgdb8250_iowrite(u8 val, u8 mask)
+{
+	iowrite8(val, kgdb8250_addr + (mask << kgdb8250_port.regshift));
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void kgdb8250_put_debug_char(u8 chr)
+{
+	while (!(kgdb8250_ioread(UART_LSR) & UART_LSR_THRE))
+		cpu_relax();
+
+	kgdb8250_iowrite(chr, UART_TX);
+}
+
+/*
+ * Get a byte from the hardware data buffer and return it.
+ */
+static int kgdb8250_get_debug_char(void)
+{
+	unsigned int lsr;
+
+	while (1) {
+		/* Did the interrupt handler catch something before us? */
+		if (buffered_char >= 0)
+			return xchg(&buffered_char, -1);
+
+		lsr = kgdb8250_ioread(UART_LSR);
+		if (lsr & UART_LSR_DR)
+			return kgdb8250_ioread(UART_RX);
+
+		/*
+		 * If we have a framing error assume somebody messed with
+		 * our uart.  Reprogram it and send '-' both ways...
+		 */
+		if (lsr & (UART_LSR_PE | UART_LSR_FE)) {
+			kgdb8250_uart_init();
+			kgdb8250_put_debug_char('-');
+			return '-';
+		}
+
+		cpu_relax();
+	}
+}
+
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * All that we need to do is verify that the interrupt happened on the
+ * line we're in charge of.  If this is true, schedule a breakpoint and
+ * return.
+ */
+static irqreturn_t kgdb8250_interrupt(int irq, void *dev_id)
+{
+	unsigned int iir = kgdb8250_ioread(UART_IIR);
+	char c;
+
+	if (iir & UART_IIR_NO_INT)
+		return IRQ_NONE;
+
+	if ((iir & UART_IIR_ID) == UART_IIR_RDI) {
+		c = kgdb8250_ioread(UART_RX);
+		if (c != 0x03)
+			buffered_char = c;
+		if (c == 0x03 || !kgdb_connected)
+			breakpoint();
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Initializes the UART.
+ *  Returns:
+ *	0 on success, -errno on failure.
+ */
+static int kgdb8250_uart_init(void)
+{
+	unsigned int ier;
+	unsigned int base_baud = kgdb8250_port.uartclk ?
+		kgdb8250_port.uartclk / 16 : BASE_BAUD;
+
+	/* Test UART existance. */
+	if (kgdb8250_ioread(UART_LSR) == 0xff)
+		return -EIO;
+
+	/* Disable interrupts. */
+	kgdb8250_iowrite(0, UART_IER);
+
+#ifdef CONFIG_ARCH_OMAP1510
+	/* Workaround to enable 115200 baud on OMAP1510 internal ports */
+	if (cpu_is_omap1510() && is_omap_port((void *)kgdb8250_addr)) {
+		if (kgdb8250_baud == 115200) {
+			base_baud = 1;
+			kgdb8250_baud = 1;
+			kgdb8250_iowrite(1, UART_OMAP_OSC_12M_SEL);
+		} else
+			kgdb8250_iowrite(0, UART_OMAP_OSC_12M_SEL);
+	}
+#endif
+
+	/* Line settings 8n1, no FIFO, DTR+RTS on. */
+	kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR);
+	kgdb8250_iowrite(0, UART_FCR);
+	kgdb8250_iowrite(UART_MCR_OUT2 | UART_MCR_DTR |
+			 UART_MCR_RTS, UART_MCR);
+
+	/* Set baud rate. */
+	kgdb8250_iowrite(UART_LCR_WLEN8 | UART_LCR_DLAB, UART_LCR);
+	kgdb8250_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL);
+	kgdb8250_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM);
+	kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR);
+
+	/* Clear pending interrupts. */
+	(void) kgdb8250_ioread(UART_IIR);
+	(void) kgdb8250_ioread(UART_RX);
+	(void) kgdb8250_ioread(UART_LSR);
+	(void) kgdb8250_ioread(UART_MSR);
+
+	/*
+	 * Borrowed from the main 8250 driver.
+	 * Try writing and reading the UART_IER_UUE bit (b6).
+	 * If it works, this is probably one of the Xscale platform's
+	 * internal UARTs.
+	 * We're going to explicitly set the UUE bit to 0 before
+	 * trying to write and read a 1 just to make sure it's not
+	 * already a 1 and maybe locked there before we even start start.
+	 */
+	ier = kgdb8250_ioread(UART_IER);
+	kgdb8250_iowrite(ier & ~UART_IER_UUE, UART_IER);
+	if (!(kgdb8250_ioread(UART_IER) & UART_IER_UUE)) {
+		/*
+		 * OK it's in a known zero state, try writing and reading
+		 * without disturbing the current state of the other bits.
+		 */
+		kgdb8250_iowrite(ier | UART_IER_UUE, UART_IER);
+		if (kgdb8250_ioread(UART_IER) & UART_IER_UUE)
+			/* It's an Xscale. */
+			ier |= UART_IER_UUE | UART_IER_RTOIE;
+	}
+	kgdb8250_iowrite(ier, UART_IER);
+
+	return 0;
+}
+
+/*
+ * Syntax for this cmdline option is:
+ *   <io|mmio>,<address>[/<regshift>],<baud rate>,<irq> or
+ *   ttyS<n>,<baud rate>
+ */
+static int kgdb8250_parse_config(char *str)
+{
+	int line, err;
+
+	/* Save the option string in case we fail and can retry later. */
+	strncpy(config, str, KGD8250_MAX_CONFIG_STR-1);
+
+	/* Empty config or leading white space (like LF) means "disabled" */
+	if (!strlen(config) || isspace(config[0]))
+		return 0;
+
+	if (!strncmp(str, "io", 2)) {
+		kgdb8250_port.iotype = UPIO_PORT;
+		str += 2;
+	} else if (!strncmp(str, "mmio", 4)) {
+		kgdb8250_port.iotype = UPIO_MEM;
+		kgdb8250_port.flags = UPF_IOREMAP;
+		str += 4;
+	} else if (!strncmp(str, "ttyS", 4)) {
+		str += 4;
+		if (*str < '0' || *str > '9')
+			return -EINVAL;
+		line = simple_strtoul(str, &str, 10);
+		if (line >= CONFIG_SERIAL_8250_NR_UARTS)
+			return -EINVAL;
+
+		err = serial8250_get_port_def(&kgdb8250_port, line);
+		if (err) {
+			if (late_init_passed)
+				return err;
+			printk(KERN_WARNING "kgdb8250: ttyS%d init delayed, "
+			       "use io/mmio syntax for early init.\n",
+			       line);
+			return 0;
+		}
+
+		if (*str != ',')
+			return -EINVAL;
+		str++;
+
+		kgdb8250_baud = simple_strtoul(str, &str, 10);
+		if (!kgdb8250_baud)
+			return -EINVAL;
+
+		if (*str == ',')
+			return -EINVAL;
+
+		goto finish;
+	} else
+		return -EINVAL;
+
+	if (*str != ',')
+		return -EINVAL;
+	str++;
+
+	if (kgdb8250_port.iotype == UPIO_PORT)
+		kgdb8250_port.iobase = simple_strtoul(str, &str, 16);
+	else
+		kgdb8250_port.mapbase =
+			(unsigned long)simple_strtoul(str, &str, 16);
+
+	if (*str == '/') {
+		str++;
+		kgdb8250_port.regshift = simple_strtoul(str, &str, 10);
+	}
+
+	if (*str != ',')
+		return -EINVAL;
+	str++;
+
+	kgdb8250_baud = simple_strtoul(str, &str, 10);
+	if (!kgdb8250_baud)
+		return -EINVAL;
+
+	if (*str != ',')
+		return -EINVAL;
+	str++;
+
+	kgdb8250_port.irq = simple_strtoul(str, &str, 10);
+
+finish:
+	err = kgdb_register_io_module(&kgdb8250_io_ops);
+	if (err)
+		kgdb8250_addr = 0;
+
+	return err;
+}
+
+static int kgdb8250_early_init(void)
+{
+	/* Internal driver setup. */
+	switch (kgdb8250_port.iotype) {
+	case UPIO_MEM:
+		if (kgdb8250_port.flags & UPF_IOREMAP)
+			kgdb8250_port.membase = ioremap(kgdb8250_port.mapbase,
+						8 << kgdb8250_port.regshift);
+		kgdb8250_addr = kgdb8250_port.membase;
+		break;
+	case UPIO_PORT:
+	default:
+		kgdb8250_addr = ioport_map(kgdb8250_port.iobase,
+					   8 << kgdb8250_port.regshift);
+	}
+	if (!kgdb8250_addr)
+		return -EIO;
+
+	if (kgdb8250_uart_init() < 0) {
+		printk(KERN_ERR "kgdb8250: UART initialization failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int kgdb8250_late_init(void)
+{
+	int err;
+
+	if (fully_initialized)
+		return 0;
+
+	late_init_passed = 1;
+
+	/*
+	 * If we didn't initialize yet or if an earlier attempt failed,
+	 * evaluate the configuration and register with KGDB.
+	 */
+	if (!kgdb8250_addr) {
+		err = kgdb8250_parse_config(config);
+		if (err || !kgdb8250_addr)
+			return err;
+	}
+
+	/* Take the port away from the main driver. */
+	hijacked_line = serial8250_find_port(&kgdb8250_port);
+	if (hijacked_line >= 0)
+		serial8250_unregister_port(hijacked_line);
+
+	/* Now reinit the port as the above has disabled things. */
+	kgdb8250_uart_init();
+
+	/* Request memory/io regions that we use. */
+	if (kgdb8250_port.iotype == UPIO_MEM) {
+		if (!request_mem_region(kgdb8250_port.mapbase,
+					8 << kgdb8250_port.regshift, "kgdb"))
+			goto rollback;
+	} else {
+		if (!request_region(kgdb8250_port.iobase,
+				    8 << kgdb8250_port.regshift, "kgdb"))
+			goto rollback;
+	}
+
+	if (request_irq(kgdb8250_port.irq, kgdb8250_interrupt, IRQF_SHARED,
+			"kgdb", &kgdb8250_port) == 0) {
+		/* Turn on RX interrupt only. */
+		kgdb8250_iowrite(UART_IER_RDI, UART_IER);
+
+		kgdb8250_irq = kgdb8250_port.irq;
+	} else {
+		/*
+		 * The IRQ line is not mandatory for KGDB to provide at least
+		 * basic services. So report the error and continue.
+		 */
+		printk(KERN_ERR "kgdb8250: failed to request the IRQ (%d)\n",
+		       kgdb8250_irq);
+		kgdb8250_irq = -1;
+	}
+
+	fully_initialized = 1;
+	return 0;
+
+rollback:
+	if (hijacked_line >= 0)
+		serial8250_register_port(&kgdb8250_port);
+
+	printk(KERN_CRIT "kgdb: Unable to reserve mandatory hardware "
+			 "resources.\n");
+	return -EBUSY;
+}
+
+static void kgdb8250_cleanup(void)
+{
+	void *ioaddr = kgdb8250_addr;
+
+	if (!kgdb8250_addr)
+		return;
+
+	/* Disable and unregister interrupt. */
+	kgdb8250_iowrite(0, UART_IER);
+	(void) kgdb8250_ioread(UART_RX);
+
+	if (kgdb8250_irq >= 0)
+		free_irq(kgdb8250_irq, &kgdb8250_port);
+
+	/* Deregister from KGDB core. */
+	kgdb_unregister_io_module(&kgdb8250_io_ops);
+	kgdb8250_addr = 0;
+
+	if (!fully_initialized)
+		return;
+
+	fully_initialized = 0;
+
+	if (kgdb8250_port.iotype == UPIO_MEM) {
+		if (kgdb8250_port.flags & UPF_IOREMAP)
+			iounmap(kgdb8250_port.membase);
+		release_mem_region(kgdb8250_port.mapbase,
+				   8 << kgdb8250_port.regshift);
+	} else {
+		ioport_unmap(ioaddr);
+		release_region(kgdb8250_port.iobase,
+			       8 << kgdb8250_port.regshift);
+	}
+
+	/* Give the port back to the 8250 driver. */
+	if (hijacked_line >= 0)
+		serial8250_register_port(&kgdb8250_port);
+}
+
+static int kgdb8250_set_config(const char *kmessage, struct kernel_param *kp)
+{
+	int err;
+
+	if (strlen(kmessage) >= KGD8250_MAX_CONFIG_STR) {
+		printk(KERN_ERR "%s: config string too long.\n", kp->name);
+		return -ENOSPC;
+	}
+
+	if (kgdb_connected) {
+		printk(KERN_ERR "kgd8250: Cannot reconfigure while KGDB is "
+				"connected.\n");
+		return -EBUSY;
+	}
+
+	if (kgdb8250_addr)
+		kgdb8250_cleanup();
+
+	err = kgdb8250_parse_config((char *)kmessage);
+
+	if (err || !late_init_passed)
+		return err;
+
+	/* Call the botton-half initialization as we are re-configuring. */
+	return kgdb8250_late_init();
+}
+
+static void kgdb8250_pre_exception_handler(void)
+{
+	if (!kgdb_connected)
+		try_module_get(THIS_MODULE);
+}
+
+static void kgdb8250_post_exception_handler(void)
+{
+	if (!kgdb_connected)
+		module_put(THIS_MODULE);
+}
+
+static struct kgdb_io kgdb8250_io_ops = {
+	.name = "kgdb8250",
+	.read_char = kgdb8250_get_debug_char,
+	.write_char = kgdb8250_put_debug_char,
+	.init = kgdb8250_early_init,
+	.pre_exception = kgdb8250_pre_exception_handler,
+	.post_exception = kgdb8250_post_exception_handler,
+};
+
+module_init(kgdb8250_late_init);
+module_exit(kgdb8250_cleanup);
+
+module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdb8250, "ttyS<n>,<baud rate>");
+
+#ifdef CONFIG_KGDB_8250
+early_param("kgdb8250", kgdb8250_parse_config);
+#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b82595c..7ef9145 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -121,7 +121,7 @@ config SERIAL_8250_CS
 
 config SERIAL_8250_NR_UARTS
 	int "Maximum number of 8250/16550 serial ports"
-	depends on SERIAL_8250
+	depends on SERIAL_8250 || KGDB_8250
 	default "4"
 	help
 	  Set this to the number of serial ports you want the driver
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 640cfe4..6ee1b36 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_KGDB_8250) += 8250_kgdb.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0f5a179..d333fc4 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -33,6 +33,7 @@
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -58,6 +59,12 @@ static struct lock_class_key port_lock_key;
 #define uart_console(port)	(0)
 #endif
 
+#ifdef CONFIG_KGDB_CONSOLE
+#define uart_kgdb(port) (port->cons && !strcmp(port->cons->name, "kgdb"))
+#else
+#define uart_kgdb(port) (0)
+#endif
+
 static void uart_change_speed(struct uart_state *state,
 					struct ktermios *old_termios);
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -1678,6 +1685,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
 			mmio ? (unsigned long long)port->mapbase
 			     : (unsigned long long) port->iobase,
 			port->irq);
+	if (port->iotype == UPIO_MEM)
+		ret += sprintf(buf+ret, " membase 0x%08lX",
+					   (unsigned long) port->membase);
 
 	if (port->type == PORT_UNKNOWN) {
 		strcat(buf, "\n");
@@ -2111,7 +2121,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 	case UPIO_TSI:
 	case UPIO_DWAPB:
 		snprintf(address, sizeof(address),
-			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
+			 "MMIO 0x%llx mem 0x%p",
+			 (unsigned long long)port->mapbase,
+			 port->membase);
 		break;
 	default:
 		strlcpy(address, "*unknown*", sizeof(address));
@@ -2175,9 +2187,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
 		/*
 		 * Power down all ports by default, except the
-		 * console if we have one.
+		 * console (real or kgdb) if we have one.
 		 */
-		if (!uart_console(port))
+		if (!uart_console(port) && !uart_kgdb(port))
 			uart_change_pm(state, 3);
 	}
 }
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 00b65c0..fc4bac7 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -58,8 +58,10 @@ struct uart_port;
 
 int serial8250_register_port(struct uart_port *);
 void serial8250_unregister_port(int line);
+void serial8250_unregister_by_port(struct uart_port *port);
 void serial8250_suspend_port(int line);
 void serial8250_resume_port(int line);
+int serial8250_get_port_def(struct uart_port *port, int line);
 
 extern int early_serial_setup(struct uart_port *port);
 
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
index e6fb7e3..3d5c2f8 100644
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -30,3 +30,24 @@ config KGDB_CONSOLE
 
 comment "KGDB I/O drivers"
 	depends on KGDB
+
+config KGDB_8250
+	tristate "8250/16550 and compatible serial support"
+	depends on KGDB
+	select SERIAL_8250
+	default y
+	help
+	  Uses a 8250/16550 compatible serial ports to communicate with the
+	  host GDB.  This is independent of the normal driver (SERIAL_8250)
+	  for this chipset.  The port is configured via kgdb8250=<config>,
+	  passed as kernel or module parameter, respectively.  The
+	  configuration comes in two flavors:
+
+	  <io|mmio>,<address>[/<regshift>],<baud rate>,<irq>
+	    or
+	  ttyS<n>,<baud rate>
+
+	  When built into the kernel, this driver allows debugging of
+	  the early boot process.  Note that, as long as the debugger is
+	  attached via this driver,  the configured serial port cannot be
+	  used by the standard 8250 driver or serial earlyprintk/earlycon.
-- 
1.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ