LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 0/8] kgdb 2.6.25 version
@ 2008-02-09 13:35 jason.wessel
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
  2008-02-09 17:38 ` [PATCH 0/8] kgdb 2.6.25 version Christoph Hellwig
  0 siblings, 2 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel

Per reqest on lkml, here are the individual kgdb patches
targeted at 2.6.25.

The kgdb tree has been collapsed review.  It includes
the kgdb core, the x86 arch, the kgdb8250 uart driver
and the kgdb console sharing driver.

Since the last time the kgdb patches were posted to LKML
several months ago, the kgdb core has undergone some
significant cleanup, as well as the kgdb I/O driver
interface.

All the kgdb hooks are initialized dynamically only when a
kgdb I/O module is configured. When not configured
kgdb will not exist in any kernel execution path.

Further comments, questions and patches are certainly
welcome.

Thanks,
Jason.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 13:35 [PATCH 0/8] kgdb 2.6.25 version jason.wessel
@ 2008-02-09 13:35 ` jason.wessel
  2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
                     ` (3 more replies)
  2008-02-09 17:38 ` [PATCH 0/8] kgdb 2.6.25 version Christoph Hellwig
  1 sibling, 4 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel

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

This patch provides all of the common code, documentation and basic
Kconfig changes, as well as the common hooks.  With out arch changes
this code does not actually do anything to the kernel.  The idea is
that each arch can add in a minimal set of hooks to make use of the
KGDB core.

The core contains the protocol handler to talk to a debugger client
such as gdb via the gdb serial protocol.  The core also contains the
needed hooks for an arch to be SMP and preempt safe.  The weak
definitions allow an arch to override a part of the core, if it the
arch impelmentation requires it.

Jason Wessel <jason.wessel@windriver.com>
 - breakup kgdb_handle_exeception
 - dyanmic registration of kgdb hooks
Jan Kiszka <jan.kiszka@web.de>
 - Reduce EXPORT_SYMBOLs, switch the rest to EXPORT_SYMBOL_GPL
 - Drop code that is (yet) unused
 - Rename variables, refactor their types (personal taste, for sure)
 - Remove "extern" for function prototypes
 - Remove MODULE_LICENSE/DESCRIPTION from kgdb core
 - Refactor Kconfig kgdb choices
Ingo Molnar <mingo@elte.hu>
 - clean up includes, eliminate duplicate ones.
 - general code cleanups and comments
Harvey Harrison <harvey.harrison@gmail.com>
 - compilation cleanups

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>

---
 Documentation/DocBook/Makefile  |    2 +-
 Documentation/DocBook/kgdb.tmpl |  163 ++++
 MAINTAINERS                     |    7 +
 include/asm-generic/kgdb.h      |  105 ++
 include/linux/clocksource.h     |    1 +
 include/linux/kgdb.h            |  268 ++++++
 include/linux/sched.h           |    1 +
 kernel/Makefile                 |    1 +
 kernel/kgdb.c                   | 2018 +++++++++++++++++++++++++++++++++++++++
 kernel/sched.c                  |    3 +-
 kernel/softlockup.c             |    7 +-
 kernel/time/clocksource.c       |   12 +
 lib/Kconfig.debug               |    2 +
 lib/Kconfig.kgdb                |   32 +
 14 files changed, 2619 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/DocBook/kgdb.tmpl
 create mode 100644 include/asm-generic/kgdb.h
 create mode 100644 include/linux/kgdb.h
 create mode 100644 kernel/kgdb.c
 create mode 100644 lib/Kconfig.kgdb

diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 6a0ad47..1721ea4 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -6,7 +6,7 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
+DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml kgdb.xml \
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml \
 	    kernel-api.xml filesystems.xml lsm.xml usb.xml \
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
new file mode 100644
index 0000000..c423411
--- /dev/null
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="kgdbInternals">
+ <bookinfo>
+  <title>KGDB Internals</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Tom</firstname>
+    <surname>Rini</surname>
+    <affiliation>
+     <address>
+      <email>trini@kernel.crashing.org</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <authorgroup>
+   <author>
+    <firstname>Amit S.</firstname>
+    <surname>Kale</surname>
+    <affiliation>
+     <address>
+      <email>amitkale@linsyssoft.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2004-2005</year>
+   <holder>MontaVista Software, Inc.</holder>
+  </copyright>
+  <copyright>
+   <year>2004</year>
+   <holder>Amit S. Kale</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+   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.
+   </para>
+
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+  <chapter id="Introduction">
+    <title>Introduction</title>
+    <para>
+    kgdb is a source level debugger for linux kernel. It is used along
+    with gdb to debug a linux kernel. Kernel developers can debug a kernel
+    similar to application programs with the use of kgdb. It makes it
+    possible to place breakpoints in kernel code, step through the code
+    and observe variables.
+    </para>
+    <para>
+    Two machines are required for using kgdb. One of these machines is a
+    development machine and the other is a test machine. The machines are
+    typically connected through a serial line, a null-modem cable which
+    connects their serial ports.  It is also possible however, to use an
+    ethernet connection between the machines.  The kernel to be debugged
+    runs on the test machine. gdb runs on the development machine. The
+    serial line or ethernet connection is used by gdb to communicate to
+    the kernel being debugged.
+    </para>
+  </chapter>
+  <chapter id="CompilingAKernel">
+    <title>Compiling a kernel</title>
+    <para>
+    To enable <symbol>CONFIG_KGDB</symbol>, look under the "Kernel debugging"
+    and then select "KGDB: kernel debugging with remote gdb".
+    </para>
+    <para>
+    Next you should choose one of more I/O drivers to interconnect debugging
+    host and debugged target.  If debugging early boot steps is required,
+    at least one driver has to be built in.  I/O driver configuration takes
+    place via kernel or module parameters, see following chapter.
+    </para>
+    <para>
+    While KGDB is connect with the host, it can dump console messages over
+    this link.  This is specifically useful for collecting critical kernel
+    messages while only a single serial port is available.  Enable
+    <symbol>CONFIG_KGDB_CONSOLE</symbol> to activate this feature.
+    </para>
+  </chapter>
+  <chapter id="BootingTheKernel">
+    <title>Booting the kernel</title>
+    <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
+    <constant>/sys/module/&lt;driver&gt;/parameter/&lt;option&gt;</constant>.
+    The driver can be unconfigured by passing an empty string.  You cannot
+    change the configuration while the debugger is attached.  In that case
+    issue the required <constant>detach</constant> command via gdb first.
+    </para>
+  </chapter>
+  <chapter id="ConnectingGDB">
+  <title>Connecting gdb</title>
+    <para>
+    If you have used any of the methods to have KGDB stop and create
+    an initial breakpoint described in the previous chapter, kgdb prints
+    the message "Waiting for connection from remote gdb..." on the console
+    and waits for connection from gdb. At this point you connect gdb to kgdb.
+    </para>
+    <para>
+    Example (serial):
+    </para>
+    <programlisting>
+    % gdb ./vmlinux
+    (gdb) set remotebaud 115200
+    (gdb) target remote /dev/ttyS0
+    </programlisting>
+    <para>
+    Example (ethernet):
+    </para>
+    <programlisting>
+    % gdb ./vmlinux
+    (gdb) target remote udp:192.168.2.2:6443
+    </programlisting>
+    <para>
+    Once connected, you can debug a kernel the way you would debug an
+    application program.
+    </para>
+  </chapter>
+  <chapter id="CommonBackEndReq">
+    <title>The common backend (required)</title>
+      <para>
+      There are a few flags which must be set on every architecture in
+      their &lt;asm/kgdb.h&gt; file.  These are:
+      <itemizedlist>
+        <listitem>
+	  <para>
+	  NUMREGBYTES: The size in bytes of all of the registers, so
+	  that we can ensure they will all fit into a packet.
+	  </para>
+	  <para>
+	  BUFMAX: The size in bytes of the buffer GDB will read into.
+	  This must be larger than NUMREGBYTES.
+	  </para>
+	  <para>
+	  CACHE_FLUSH_IS_SAFE: Set to one if it is always safe to call
+	  flush_cache_range or flush_icache_range.  On some architectures,
+	  these functions may not be safe to call on SMP since we keep other
+	  CPUs in a holding pattern.
+	  </para>
+	</listitem>
+      </itemizedlist>
+      </para>
+      <para>
+      There are also the following functions for the common backend,
+      found in kernel/kgdb.c, that must be supplied by the
+      architecture-specific backend.  No weak version of these is provided.
+      </para>
+!Iinclude/linux/kgdb.h
+  </chapter>
+</book>
diff --git a/MAINTAINERS b/MAINTAINERS
index 0d6f511..71d20e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2311,6 +2311,13 @@ L:	linux-kernel@vger.kernel.org
 L:	kexec@lists.infradead.org
 S:	Maintained
 
+KGDB
+P:	Jason Wessel
+M:	jason.wessel@windriver.com
+W:	http://sourceforge.net/projects/kgdb
+L:	kgdb-bugreport@lists.sourceforge.net
+S:	Maintained
+
 KPROBES
 P:	Prasanna S Panchamukhi
 M:	prasanna@in.ibm.com
diff --git a/include/asm-generic/kgdb.h b/include/asm-generic/kgdb.h
new file mode 100644
index 0000000..24e0b6c
--- /dev/null
+++ b/include/asm-generic/kgdb.h
@@ -0,0 +1,105 @@
+/*
+ * include/asm-generic/kgdb.h
+ *
+ * This provides the assembly level information so that KGDB can provide
+ * a GDB that has been patched with enough information to know to stop
+ * trying to unwind the function.
+ *
+ * Author: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * 2006 (c) Embedded Alley Solutions, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_GENERIC_KGDB_H__
+#define __ASM_GENERIC_KGDB_H__
+
+struct pt_regs;
+
+#ifdef CONFIG_X86
+/**
+ *	kgdb_skipexception - Bail of of KGDB when we've been triggered.
+ *	@exception: Exception vector number
+ *	@regs: Current &struct pt_regs.
+ *
+ *	On some architectures we need to skip a breakpoint exception when
+ *	it occurs after a breakpoint has been removed.
+ */
+int kgdb_skipexception(int exception, struct pt_regs *regs);
+#else
+static inline int kgdb_skipexception(int exception, struct pt_regs *regs)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_X86)
+/**
+ *	kgdb_post_master_code - Save error vector/code numbers.
+ *	@regs: Original pt_regs.
+ *	@e_vector: Original error vector.
+ *	@err_code: Original error code.
+ *
+ *	This is needed on architectures which support SMP and KGDB.
+ *	This function is called after all the slave cpus have been put
+ *	to a know spin state and the master CPU has control over KGDB.
+ */
+extern void kgdb_post_master_code(struct pt_regs *regs, int e_vector,
+				  int err_code);
+
+/**
+ *	kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb.
+ *	@regs: Current &struct pt_regs.
+ *
+ *	This function will be called if the particular architecture must
+ *	disable hardware debugging while it is processing gdb packets or
+ *	handling exception.
+ */
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+#else
+#define kgdb_disable_hw_debug(regs)		do { } while (0)
+#define kgdb_post_master_code(regs, v, c)	do { } while (0)
+#endif
+
+#ifdef CONFIG_KGDB_ARCH_HAS_SHADOW_INFO
+/**
+ *	kgdb_shadowinfo - Get shadowed information on @threadid.
+ *	@regs: The &struct pt_regs of the current process.
+ *	@buffer: A buffer of %BUFMAX size.
+ *	@threadid: The thread id of the shadowed process to get information on.
+ */
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
+			    unsigned threadid);
+
+/**
+ *	kgdb_get_shadow_thread - Get the shadowed &task_struct of @threadid.
+ *	@regs: The &struct pt_regs of the current thread.
+ *	@threadid: The thread id of the shadowed process to get information on.
+ *
+ *	RETURN:
+ *	This returns a pointer to the &struct task_struct of the shadowed
+ *	thread, @threadid.
+ */
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+						  int threadid);
+
+/**
+ *	kgdb_shadow_regs - Return the shadowed registers of @threadid.
+ *	@regs: The &struct pt_regs of the current thread.
+ *	@threadid: The thread id we want the &struct pt_regs for.
+ *
+ *	RETURN:
+ *	The a pointer to the &struct pt_regs of the shadowed thread @threadid.
+ */
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+#else
+#define kgdb_shadowinfo(regs, buf, threadid)		do { } while (0)
+#define kgdb_get_shadow_thread(regs, threadid)		NULL
+#define kgdb_shadow_regs(regs, threadid)		NULL
+#endif
+
+#endif				/* __ASM_GENERIC_KGDB_H__ */
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 85778a4..3509447 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -216,6 +216,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
 /* used to install a new clocksource */
 extern int clocksource_register(struct clocksource*);
 extern void clocksource_unregister(struct clocksource*);
+extern void clocksource_touch_watchdog(void);
 extern struct clocksource* clocksource_get_next(void);
 extern void clocksource_change_rating(struct clocksource *cs, int rating);
 extern void clocksource_resume(void);
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
new file mode 100644
index 0000000..7abe5bd
--- /dev/null
+++ b/include/linux/kgdb.h
@@ -0,0 +1,268 @@
+/*
+ * include/linux/kgdb.h
+ *
+ * This provides the hooks and functions that KGDB needs to share between
+ * the core, I/O and arch-specific portions.
+ *
+ * Author: Amit Kale <amitkale@linsyssoft.com> and
+ *         Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc.
+ * 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.
+ */
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+#include <asm/atomic.h>
+
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#include <linux/serial_8250.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+struct tasklet_struct;
+struct pt_regs;
+struct task_struct;
+struct uart_port;
+
+/* To enter the debugger explicitly. */
+void breakpoint(void);
+
+extern int kgdb_connected;
+
+extern atomic_t			kgdb_setting_breakpoint;
+extern atomic_t			cpu_doing_single_step;
+
+extern struct task_struct	*kgdb_usethread;
+extern struct task_struct	*kgdb_contthread;
+
+enum kgdb_bptype {
+	BP_BREAKPOINT = 0,
+	BP_HARDWARE_BREAKPOINT,
+	BP_WRITE_WATCHPOINT,
+	BP_READ_WATCHPOINT,
+	BP_ACCESS_WATCHPOINT
+};
+
+enum kgdb_bpstate {
+	BP_UNDEFINED = 0,
+	BP_REMOVED,
+	BP_SET,
+	BP_ACTIVE
+};
+
+struct kgdb_bkpt {
+	unsigned long		bpt_addr;
+	unsigned char		saved_instr[BREAK_INSTR_SIZE];
+	enum kgdb_bptype	type;
+	enum kgdb_bpstate	state;
+};
+
+/* The maximum number of KGDB I/O modules that can be loaded */
+#define KGDB_MAX_IO_HANDLERS	3
+
+#ifndef KGDB_MAX_BREAKPOINTS
+# define KGDB_MAX_BREAKPOINTS	1000
+#endif
+
+#define KGDB_HW_BREAKPOINT	1
+
+/*
+ * Functions each KGDB-supporting architecture must provide:
+ */
+
+/**
+ *	kgdb_arch_init - Perform any architecture specific initalization.
+ *
+ *	This function will handle the initalization of any architecture
+ *	specific hooks.
+ */
+int kgdb_arch_init(void);
+
+/**
+ *	kgdb_arch_uninit - Perform any architecture specific uninitalization.
+ *
+ *	This function will handle the uninitalization of any architecture
+ *	specific hooks, for dynamic registration and unregistration.
+ */
+void kgdb_arch_uninit(void);
+
+/**
+ *	pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
+ *	@gdb_regs: A pointer to hold the registers in the order GDB wants.
+ *	@regs: The &struct pt_regs of the current process.
+ *
+ *	Convert the pt_regs in @regs into the format for registers that
+ *	GDB expects, stored in @gdb_regs.
+ */
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+
+/**
+ *	sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs
+ *	@gdb_regs: A pointer to hold the registers in the order GDB wants.
+ *	@p: The &struct task_struct of the desired process.
+ *
+ *	Convert the register values of the sleeping process in @p to
+ *	the format that GDB expects.
+ *	This function is called when kgdb does not have access to the
+ *	&struct pt_regs and therefore it should fill the gdb registers
+ *	@gdb_regs with what has	been saved in &struct thread_struct
+ *	thread field during switch_to.
+ */
+void
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p);
+
+/**
+ *	gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs.
+ *	@gdb_regs: A pointer to hold the registers we've received from GDB.
+ *	@regs: A pointer to a &struct pt_regs to hold these values in.
+ *
+ *	Convert the GDB regs in @gdb_regs into the pt_regs, and store them
+ *	in @regs.
+ */
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+
+/**
+ *	kgdb_arch_handle_exception - Handle architecture specific GDB packets.
+ *	@vector: The error vector of the exception that happened.
+ *	@signo: The signal number of the exception that happened.
+ *	@err_code: The error code of the exception that happened.
+ *	@remcom_in_buffer: The buffer of the packet we have read.
+ *	@remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into.
+ *	@regs: The &struct pt_regs of the current process.
+ *
+ *	This function MUST handle the 'c' and 's' command packets,
+ *	as well packets to set / remove a hardware breakpoint, if used.
+ *	If there are additional packets which the hardware needs to handle,
+ *	they are handled here.  The code should return -1 if it wants to
+ *	process more packets, and a %0 or %1 if it wants to exit from the
+ *	kgdb hook.
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+			       char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *regs);
+
+/**
+ *	kgdb_roundup_cpus - Get other CPUs into a holding pattern
+ *	@flags: Current IRQ state
+ *
+ *	On SMP systems, we need to get the attention of the other CPUs
+ *	and get them be in a known state.  This should do what is needed
+ *	to get the other CPUs to call kgdb_wait(). Note that on some arches,
+ *	the NMI approach is not used for rounding up all the CPUs. For example,
+ *	in case of MIPS, smp_call_function() is used to roundup CPUs. In
+ *	this case, we have to make sure that interrupts are enabled before
+ *	calling smp_call_function(). The argument to this function is
+ *	the flags that will be used when restoring the interrupts. There is
+ *	local_irq_save() call before kgdb_roundup_cpus().
+ *
+ *	On non-SMP systems, this is not called.
+ */
+void kgdb_roundup_cpus(unsigned long flags);
+
+/* Optional functions. */
+int kgdb_validate_break_address(unsigned long addr);
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
+
+/**
+ * struct kgdb_arch - Describe architecture specific values.
+ * @gdb_bpt_instr: The instruction to trigger a breakpoint.
+ * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT.
+ * @shadowth: A value of %1 indicates we shadow information on processes.
+ * @set_breakpoint: Allow an architecture to specify how to set a software
+ * breakpoint.
+ * @remove_breakpoint: Allow an architecture to specify how to remove a
+ * software breakpoint.
+ * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware
+ * breakpoint.
+ * @remove_hw_breakpoint: Allow an architecture to specify how to remove a
+ * hardware breakpoint.
+ * @remove_all_hw_break: Allow an architecture to specify how to remove all
+ * hardware breakpoints.
+ * @correct_hw_break: Allow an architecture to specify how to correct the
+ * hardware debug registers.
+ *
+ * The @shadowth flag is an option to shadow information not retrievable by
+ * gdb otherwise.  This is deprecated in favor of a binutils which supports
+ * CFI macros.
+ */
+struct kgdb_arch {
+	unsigned char		gdb_bpt_instr[BREAK_INSTR_SIZE];
+	unsigned long		flags;
+	unsigned		shadowth;
+
+	int	(*set_breakpoint)(unsigned long, char *);
+	int	(*remove_breakpoint)(unsigned long, char *);
+	int	(*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
+	int	(*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
+	void	(*remove_all_hw_break)(void);
+	void	(*correct_hw_break)(void);
+};
+
+/**
+ * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB.
+ * @name: Name of the I/O driver.
+ * @read_char: Pointer to a function that will return one char.
+ * @write_char: Pointer to a function that will write one char.
+ * @flush: Pointer to a function that will flush any pending writes.
+ * @init: Pointer to a function that will initialize the device.
+ * @late_init: Pointer to a function that will do any setup that has
+ * other dependencies.
+ * @pre_exception: Pointer to a function that will do any prep work for
+ * the I/O driver.
+ * @post_exception: Pointer to a function that will do any cleanup work
+ * for the I/O driver.
+ *
+ * The @init and @late_init function pointers allow for an I/O driver
+ * such as a serial driver to fully initialize the port with @init and
+ * be called very early, yet safely call request_irq() later in the boot
+ * sequence.
+ *
+ * @init is allowed to return a non-0 return value to indicate failure.
+ * If this is called early on, then KGDB will try again when it would call
+ * @late_init.  If it has failed later in boot as well, the user will be
+ * notified.
+ */
+struct kgdb_io {
+	const char	*name;
+	int		(*read_char) (void);
+	void		(*write_char) (u8);
+	void		(*flush) (void);
+	int		(*init) (void);
+	void		(*pre_exception) (void);
+	void		(*post_exception) (void);
+};
+
+extern struct kgdb_arch		arch_kgdb_ops;
+
+int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
+void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
+
+int kgdb_hex2long(char **ptr, long *long_val);
+char *kgdb_mem2hex(char *mem, char *buf, int count);
+char *kgdb_hex2mem(char *buf, char *mem, int count);
+
+int kgdb_isremovedbreak(unsigned long addr);
+
+int kgdb_handle_exception(int ex_vector, int signo, int err_code,
+			  struct pt_regs *regs);
+int kgdb_nmihook(int cpu, void *regs);
+
+extern int		debugger_step;
+extern atomic_t		debugger_active;
+
+static inline int kgdb_active(void)
+{
+	return (atomic_read(&debugger_active) != 0);
+}
+
+#else /* !CONFIG_KGDB */
+#define kgdb_active()		0
+#endif /* !CONFIG_KGDB */
+
+#endif /* _KGDB_H_ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 00e1441..7507f8e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -297,6 +297,7 @@ extern unsigned long  softlockup_thresh;
 extern unsigned long sysctl_hung_task_check_count;
 extern unsigned long sysctl_hung_task_timeout_secs;
 extern unsigned long sysctl_hung_task_warnings;
+extern struct atomic_notifier_head softlock_chain;
 #else
 static inline void softlockup_tick(void)
 {
diff --git a/kernel/Makefile b/kernel/Makefile
index 6c584c5..05c8003 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_KGDB) += kgdb.o
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
new file mode 100644
index 0000000..3f06d09
--- /dev/null
+++ b/kernel/kgdb.c
@@ -0,0 +1,2018 @@
+/*
+ * kernel/kgdb.c
+ *
+ * Maintainer: Jason Wessel <jason.wessel@windriver.com>
+ *
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002-2004 Timesys Corporation
+ * Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com>
+ * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org>
+ * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd.
+ * Copyright (C) 2005-2008 Wind River Systems, Inc.
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Contributors at various stages not listed above:
+ *  Jan Kiszka <jan.kiszka@web.de>
+ *  Jason Wessel <jason.wessel@windriver.com>
+ *  George Anzinger <george@mvista.com>
+ *  Anurekh Saxena (anurekh.saxena@timesys.com)
+ *  Lake Stevens Instrument Division (Glenn Engel)
+ *  Jim Kingdon, Cygnus Support.
+ *
+ * Original KGDB stub: David Grothe <dave@gcom.com>,
+ * Tigran Aivazian <tigran@sco.com>
+ *
+ * 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/pid_namespace.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/console.h>
+#include <linux/threads.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+
+#include <asm/cacheflush.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+static int kgdb_break_asap;
+
+struct kgdb_state {
+	int			all_cpus_synced;
+	int			ex_vector;
+	int			signo;
+	int			err_code;
+	int			cpu;
+	int			pass_exception;
+	long			threadid;
+	long			kgdb_usethreadid;
+	struct pt_regs		*linux_regs;
+};
+
+struct debuggerinfo_struct {
+	void			*debuggerinfo;
+	struct task_struct	*task;
+} kgdb_info[NR_CPUS];
+
+/* Is a host GDB connected to us? */
+int				kgdb_connected;
+EXPORT_SYMBOL_GPL(kgdb_connected);
+
+/* All the KGDB handlers are installed */
+int				kgdb_io_module_registered;
+
+/* Guard for recursive entry */
+static int			exception_level;
+
+static struct kgdb_io		*kgdb_io_ops;
+static DEFINE_SPINLOCK(kgdb_registration_lock);
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS] = {
+	[0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED }
+};
+
+/*
+ * KGDB locking is really nasty at places - but we really can only
+ * do sane debugging if all processors are in a controlled state.
+ *
+ * So we go through painful cycles of wait and see, with every
+ * CPU having a lock:
+ */
+
+extern int pid_max;
+/* How many times to count all of the waiting CPUs */
+#define ROUNDUP_WAIT		640000	/* Arbitrary, increase if needed. */
+#define BUF_THREAD_ID_SIZE	16
+
+static spinlock_t		slave_cpu_locks[NR_CPUS] = {
+	[0 ... NR_CPUS-1] = __SPIN_LOCK_UNLOCKED(slave_cpu_locks)
+};
+static atomic_t			cpu_in_debugger[NR_CPUS];
+atomic_t			kgdb_setting_breakpoint;
+
+struct task_struct		*kgdb_usethread;
+struct task_struct		*kgdb_contthread;
+
+int				debugger_step;
+static atomic_t			kgdb_sync = ATOMIC_INIT(-1);
+atomic_t			debugger_active;
+
+/* Our I/O buffers. */
+static char			remcom_in_buffer[BUFMAX];
+static char			remcom_out_buffer[BUFMAX];
+
+/* Storage for the registers, in GDB format. */
+static unsigned long		gdb_regs[(NUMREGBYTES +
+					sizeof(unsigned long) - 1) /
+					sizeof(unsigned long)];
+
+/* to keep track of the CPU which is doing the single stepping*/
+atomic_t			cpu_doing_single_step = ATOMIC_INIT(-1);
+
+static int
+kgdb_notify_reboot(struct notifier_block *this, unsigned long code, void *x);
+
+/* reboot notifier block */
+static struct notifier_block kgdb_reboot_notifier = {
+	.notifier_call		= kgdb_notify_reboot,
+	.next			= NULL,
+	.priority		= INT_MAX,
+};
+
+/*
+ * Finally, some KGDB code :-)
+ */
+
+static int kgdb_mem_cpy(void *dst, void *src, int count)
+{
+	int leftover;
+
+	pagefault_disable();
+	leftover = __copy_from_user_inatomic(dst, src, count);
+	pagefault_enable();
+
+	if (leftover)
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * Weak aliases for breakpoint management,
+ * can be overriden by architectures when needed:
+ */
+int __weak kgdb_validate_break_address(unsigned long addr)
+{
+	char tmp_variable[BREAK_INSTR_SIZE];
+
+	if (!kgdb_mem_cpy(tmp_variable, (void *)addr, BREAK_INSTR_SIZE))
+		return 0;
+	return -1;
+}
+
+int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+	if (kgdb_mem_cpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE))
+		return -1;
+
+	if (kgdb_mem_cpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr,
+						BREAK_INSTR_SIZE))
+		return -1;
+	return 0;
+}
+
+int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+	if (kgdb_mem_cpy((void *)addr, bundle, BREAK_INSTR_SIZE))
+		return -1;
+	return 0;
+}
+
+unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs)
+{
+	return instruction_pointer(regs);
+}
+
+/*
+ * GDB remote protocol parser:
+ */
+
+static const char	hexchars[] = "0123456789abcdef";
+
+static int hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return ch - 'a' + 10;
+	if ((ch >= '0') && (ch <= '9'))
+		return ch - '0';
+	if ((ch >= 'A') && (ch <= 'F'))
+		return ch - 'A' + 10;
+	return -1;
+}
+
+/* scan for the sequence $<data>#<checksum> */
+static void get_packet(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int count;
+	char ch;
+
+	do {
+		/*
+		 * Spin and wait around for the start character, ignore all
+		 * other characters:
+		 */
+		while ((ch = (kgdb_io_ops->read_char())) != '$')
+			/* nothing */;
+
+		kgdb_connected = 1;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/*
+		 * now, read until a # or end of buffer is found:
+		 */
+		while (count < (BUFMAX - 1)) {
+			ch = kgdb_io_ops->read_char();
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(kgdb_io_ops->read_char()) << 4;
+			xmitcsum += hex(kgdb_io_ops->read_char());
+
+			if (checksum != xmitcsum)
+				/* failed checksum */
+				kgdb_io_ops->write_char('-');
+			else
+				/* successful transfer */
+				kgdb_io_ops->write_char('+');
+			if (kgdb_io_ops->flush)
+				kgdb_io_ops->flush();
+		}
+	} while (checksum != xmitcsum);
+}
+
+/*
+ * Send the packet in buffer.
+ * Check for gdb connection if asked for.
+ */
+static void put_packet(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*
+	 * $<packet info>#<checksum>.
+	 */
+	while (1) {
+		kgdb_io_ops->write_char('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count])) {
+			kgdb_io_ops->write_char(ch);
+			checksum += ch;
+			count++;
+		}
+
+		kgdb_io_ops->write_char('#');
+		kgdb_io_ops->write_char(hexchars[checksum >> 4]);
+		kgdb_io_ops->write_char(hexchars[checksum % 16]);
+		if (kgdb_io_ops->flush)
+			kgdb_io_ops->flush();
+
+		/* Now see what we get in reply. */
+		ch = kgdb_io_ops->read_char();
+
+		if (ch == 3)
+			ch = kgdb_io_ops->read_char();
+
+		/* If we get an ACK, we are done. */
+		if (ch == '+')
+			return;
+
+		/*
+		 * If we get the start of another packet, this means
+		 * that GDB is attempting to reconnect.  We will NAK
+		 * the packet being sent, and stop trying to send this
+		 * packet.
+		 */
+		if (ch == '$') {
+			kgdb_io_ops->write_char('-');
+			if (kgdb_io_ops->flush)
+				kgdb_io_ops->flush();
+			return;
+		}
+	}
+}
+
+/*
+ * Fault-tolerant memory accessor wrappers. Performance is a secondary
+ * concern, the primary concern is not to crash the debugger (or the
+ * debuggee):
+ */
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null). May return an error.
+ */
+char *kgdb_mem2hex(char *mem, char *buf, int count)
+{
+	/*
+	 * Accessing some registers in a single load instruction is
+	 * required to avoid bad side effects for some I/O registers.
+	 */
+	if ((count == 2) && (((long)mem & 1) == 0)) {
+		u16 tmp_s;
+
+		if (kgdb_mem_cpy(&tmp_s, mem, count))
+			return ERR_PTR(-EINVAL);
+
+		mem += 2;
+#ifdef __BIG_ENDIAN
+		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
+		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
+		*buf++ = hexchars[tmp_s & 0xf];
+#else
+		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
+		*buf++ = hexchars[tmp_s & 0xf];
+		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
+#endif
+	} else if ((count == 4) && (((long)mem & 3) == 0)) {
+		u32 tmp_l;
+		if (kgdb_mem_cpy(&tmp_l, mem, count))
+			return ERR_PTR(-EINVAL);
+
+		mem += 4;
+#ifdef __BIG_ENDIAN
+		*buf++ = hexchars[(tmp_l >> 28) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 24) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 20) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 16) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 8) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 4) & 0xf];
+		*buf++ = hexchars[tmp_l & 0xf];
+#else
+		*buf++ = hexchars[(tmp_l >> 4) & 0xf];
+		*buf++ = hexchars[tmp_l & 0xf];
+		*buf++ = hexchars[(tmp_l >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 8) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 20) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 16) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 28) & 0xf];
+		*buf++ = hexchars[(tmp_l >> 24) & 0xf];
+#endif
+#ifdef CONFIG_64BIT
+	} else if ((count == 8) && (((long)mem & 7) == 0)) {
+		u64 tmp_ll;
+		if (kgdb_mem_cpy(&tmp_ll, mem, count))
+			return ERR_PTR(-EINVAL);
+
+		mem += 8;
+#ifdef __BIG_ENDIAN
+		*buf++ = hexchars[(tmp_ll >> 60) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 56) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 52) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 48) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 44) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 40) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 36) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 32) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 28) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 24) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 20) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 16) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 8) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 4) & 0xf];
+		*buf++ = hexchars[tmp_ll & 0xf];
+#else
+		*buf++ = hexchars[(tmp_ll >> 4) & 0xf];
+		*buf++ = hexchars[tmp_ll & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 12) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 8) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 20) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 16) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 28) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 24) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 36) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 32) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 44) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 40) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 52) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 48) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 60) & 0xf];
+		*buf++ = hexchars[(tmp_ll >> 56) & 0xf];
+#endif
+#endif
+	} else {
+		while (count-- > 0) {
+			unsigned char ch;
+
+			if (kgdb_mem_cpy(&ch, mem, 1))
+				return ERR_PTR(-EINVAL);
+			mem++;
+			*buf++ = hexchars[ch >> 4];
+			*buf++ = hexchars[ch & 0xf];
+		}
+	}
+
+	*buf = 0;
+
+	return buf;
+}
+
+/*
+ * Copy the binary array pointed to by buf into mem.  Fix $, #, and
+ * 0x7d escaped with 0x7d.  Return a pointer to the character after
+ * the last byte written.
+ */
+static char *kgdb_ebin2mem(char *buf, char *mem, int count)
+{
+	for (; count > 0; count--, buf++) {
+		if (*buf == 0x7d) {
+			char c = *buf ^ 0x20;
+			if (kgdb_mem_cpy(mem, &c, 1))
+				return ERR_PTR(-EINVAL);
+			buf++;
+		} else
+			if (kgdb_mem_cpy(mem, buf, 1))
+				return ERR_PTR(-EINVAL);
+		mem++;
+	}
+
+	return mem;
+}
+
+/*
+ * Convert the hex array pointed to by buf into binary to be placed in mem.
+ * Return a pointer to the character AFTER the last byte written.
+ * May return an error.
+ */
+char *kgdb_hex2mem(char *buf, char *mem, int count)
+{
+	if ((count == 2) && (((long)mem & 1) == 0)) {
+		u16 tmp_s = 0;
+
+#ifdef __BIG_ENDIAN
+		tmp_s |= hex(*buf++) << 12;
+		tmp_s |= hex(*buf++) << 8;
+		tmp_s |= hex(*buf++) << 4;
+		tmp_s |= hex(*buf++);
+#else
+		tmp_s |= hex(*buf++) << 4;
+		tmp_s |= hex(*buf++);
+		tmp_s |= hex(*buf++) << 12;
+		tmp_s |= hex(*buf++) << 8;
+#endif
+		if (kgdb_mem_cpy(mem, &tmp_s, count) == -EFAULT)
+			return ERR_PTR(-EINVAL);
+		mem += 2;
+	} else if ((count == 4) && (((long)mem & 3) == 0)) {
+		u32 tmp_l = 0;
+
+#ifdef __BIG_ENDIAN
+		tmp_l |= hex(*buf++) << 28;
+		tmp_l |= hex(*buf++) << 24;
+		tmp_l |= hex(*buf++) << 20;
+		tmp_l |= hex(*buf++) << 16;
+		tmp_l |= hex(*buf++) << 12;
+		tmp_l |= hex(*buf++) << 8;
+		tmp_l |= hex(*buf++) << 4;
+		tmp_l |= hex(*buf++);
+#else
+		tmp_l |= hex(*buf++) << 4;
+		tmp_l |= hex(*buf++);
+		tmp_l |= hex(*buf++) << 12;
+		tmp_l |= hex(*buf++) << 8;
+		tmp_l |= hex(*buf++) << 20;
+		tmp_l |= hex(*buf++) << 16;
+		tmp_l |= hex(*buf++) << 28;
+		tmp_l |= hex(*buf++) << 24;
+#endif
+		if (kgdb_mem_cpy(mem, &tmp_l, count) == -EFAULT)
+			return ERR_PTR(-EINVAL);
+		mem += 4;
+	} else {
+		int i;
+
+		for (i = 0; i < count; i++) {
+			unsigned char ch = hex(*buf++) << 4;
+
+			ch |= hex(*buf++);
+			if (kgdb_mem_cpy(mem, &ch, 1) == -EFAULT)
+				return ERR_PTR(-EINVAL);
+			mem++;
+		}
+	}
+
+	return mem;
+}
+
+/*
+ * While we find nice hex chars, build a long_val.
+ * Return number of chars processed.
+ */
+int kgdb_hex2long(char **ptr, long *long_val)
+{
+	int hex_val;
+	int num = 0;
+
+	*long_val = 0;
+
+	while (**ptr) {
+		hex_val = hex(**ptr);
+		if (hex_val >= 0) {
+			*long_val = (*long_val << 4) | hex_val;
+			num++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return num;
+}
+
+/* Write memory due to an 'M' or 'X' packet. */
+static char *write_mem_msg(int binary)
+{
+	char *ptr = &remcom_in_buffer[1];
+	unsigned long addr;
+	unsigned long length;
+
+	if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' &&
+	    kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') {
+		if (binary)
+			ptr = kgdb_ebin2mem(ptr, (char *)addr, length);
+		else
+			ptr = kgdb_hex2mem(ptr, (char *)addr, length);
+		if (IS_ERR(ptr))
+			return ptr;
+		if (CACHE_FLUSH_IS_SAFE)
+			flush_icache_range(addr, addr + length + 1);
+		return NULL;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static inline char *pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+
+	return pkt;
+}
+
+static inline void error_packet(char *pkt, int error)
+{
+	error = -error;
+	pkt[0] = 'E';
+	pkt[1] = hexchars[(error / 10)];
+	pkt[2] = hexchars[(error % 10)];
+	pkt[3] = '\0';
+}
+
+/*
+ * Black magic portion #2. Thread ID accessors.
+ */
+
+static char *pack_threadid(char *pkt, unsigned char *id)
+{
+	char *limit;
+
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *id++);
+
+	return pkt;
+}
+
+void int_to_threadref(unsigned char *id, int value)
+{
+	unsigned char *scan;
+	int i = 4;
+
+	scan = (unsigned char *)id;
+	while (i--)
+		*scan++ = 0;
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+
+static struct task_struct *getthread(struct pt_regs *regs, int tid)
+{
+	if (init_pid_ns.last_pid == 0)
+		return current;
+
+	if (num_online_cpus() && (tid >= pid_max + num_online_cpus() +
+							arch_kgdb_ops.shadowth))
+		return NULL;
+
+	if (arch_kgdb_ops.shadowth && (tid >= pid_max + num_online_cpus())) {
+		return kgdb_get_shadow_thread(regs, tid - pid_max -
+					      num_online_cpus());
+	}
+
+	if (tid >= pid_max)
+		return idle_task(tid - pid_max);
+
+	if (!tid)
+		return NULL;
+
+	/*
+	 * find_task_by_pid() does not take the tasklist lock anymore
+	 * but is nicely RCU locked - hence is a pretty resilient
+	 * thing to use:
+	 */
+	return find_task_by_pid(tid);
+}
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+static int kgdb_softlock_reset[NR_CPUS];
+static unsigned long kgdb_softlock_time[NR_CPUS];
+static int
+kgdb_softlock_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	/* Ultimately this can be improved, for now just check for the
+	 * condition where the touch stamp has not changed and stop the
+	 * notify because it means the original touch failed because the
+	 * HW had not yet registered a tick at the time of the resume.
+	 */
+
+	int cpu = raw_smp_processor_id();
+	unsigned long val = *(unsigned long *)ptr;
+
+	if (!kgdb_softlock_reset[cpu])
+		return NOTIFY_DONE;
+
+	if (!kgdb_softlock_time[cpu]) {
+		kgdb_softlock_time[cpu] = val;
+		return NOTIFY_STOP;
+	}
+
+	if (kgdb_softlock_time[cpu] == val)
+		return NOTIFY_STOP;
+
+	kgdb_softlock_reset[cpu] = 0;
+	return NOTIFY_STOP;
+}
+static struct notifier_block kgdb_softlock_notifier = {
+	.notifier_call	= kgdb_softlock_notify,
+};
+static void kgdb_softlock_touch(int cpu)
+{
+	kgdb_softlock_time[cpu] = 0;
+	kgdb_softlock_reset[cpu] = 1;
+	touch_softlockup_watchdog();
+}
+#else
+static inline void kgdb_softlock_touch(int cpu)
+{
+}
+#endif
+
+/*
+ * CPU debug state control:
+ */
+
+#ifdef CONFIG_SMP
+static void kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int cpu;
+
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	kgdb_info[cpu].debuggerinfo = regs;
+	kgdb_info[cpu].task = current;
+	atomic_set(&cpu_in_debugger[cpu], 1);
+
+	/*
+	 * The master CPU must be active to enter here, but this is
+	 * gaurd in case the master CPU had not been selected if
+	 * this was an entry via nmi.
+	 */
+	while (!kgdb_active())
+		cpu_relax();
+
+	/* Wait till master CPU goes completely into the debugger. */
+	while (!atomic_read(&cpu_in_debugger[atomic_read(&debugger_active) - 1])) {
+		int i = 10;	/* an arbitrary number. Be nice. A bit. */
+
+		while (--i)
+			cpu_relax();
+	}
+
+	/* Wait till master CPU is done with debugging */
+	spin_lock(&slave_cpu_locks[cpu]);
+
+	kgdb_info[cpu].debuggerinfo = NULL;
+	kgdb_info[cpu].task = NULL;
+
+	/* fix up hardware debug registers on local cpu */
+	if (arch_kgdb_ops.correct_hw_break)
+		arch_kgdb_ops.correct_hw_break();
+
+	/* Signal the master CPU that we are done: */
+	atomic_set(&cpu_in_debugger[cpu], 0);
+	spin_unlock(&slave_cpu_locks[cpu]);
+	clocksource_touch_watchdog();
+	kgdb_softlock_touch(cpu);
+	local_irq_restore(flags);
+}
+#endif
+
+/*
+ * SW breakpoint management:
+ */
+int kgdb_activate_sw_breakpoints(void)
+{
+	unsigned long addr;
+	int error = 0;
+	int i;
+
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state != BP_SET)
+			continue;
+
+		addr = kgdb_break[i].bpt_addr;
+		error = kgdb_arch_set_breakpoint(addr,
+				kgdb_break[i].saved_instr);
+		if (error)
+			return error;
+
+		if (CACHE_FLUSH_IS_SAFE) {
+			if (current->mm && addr < TASK_SIZE) {
+				flush_cache_range(current->mm->mmap_cache,
+						addr, addr + BREAK_INSTR_SIZE);
+			} else {
+				flush_icache_range(addr, addr +
+						BREAK_INSTR_SIZE);
+			}
+		}
+		kgdb_break[i].state = BP_ACTIVE;
+	}
+	return 0;
+}
+
+static int kgdb_set_sw_break(unsigned long addr)
+{
+	int error = kgdb_validate_break_address(addr);
+	int breakno = -1;
+	int i;
+
+	if (error < 0)
+		return error;
+
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == BP_SET) &&
+					(kgdb_break[i].bpt_addr == addr))
+			return -EEXIST;
+	}
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state == BP_REMOVED &&
+					kgdb_break[i].bpt_addr == addr) {
+			breakno = i;
+			break;
+		}
+	}
+
+	if (breakno == -1) {
+		for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+			if (kgdb_break[i].state == BP_UNDEFINED) {
+				breakno = i;
+				break;
+			}
+		}
+	}
+
+	if (breakno == -1)
+		return -E2BIG;
+
+	kgdb_break[breakno].state = BP_SET;
+	kgdb_break[breakno].type = BP_BREAKPOINT;
+	kgdb_break[breakno].bpt_addr = addr;
+
+	return 0;
+}
+
+int kgdb_deactivate_sw_breakpoints(void)
+{
+	unsigned long addr;
+	int error = 0;
+	int i;
+
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state != BP_ACTIVE)
+			continue;
+		addr = kgdb_break[i].bpt_addr;
+		error = kgdb_arch_remove_breakpoint(addr,
+					kgdb_break[i].saved_instr);
+		if (error)
+			return error;
+
+		if (CACHE_FLUSH_IS_SAFE && current->mm &&
+				addr < TASK_SIZE) {
+			flush_cache_range(current->mm->mmap_cache,
+					addr, addr + BREAK_INSTR_SIZE);
+		} else if (CACHE_FLUSH_IS_SAFE) {
+			flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+		}
+		kgdb_break[i].state = BP_SET;
+	}
+	return 0;
+}
+
+static int kgdb_remove_sw_break(unsigned long addr)
+{
+	int i;
+
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == BP_SET) &&
+				(kgdb_break[i].bpt_addr == addr)) {
+			kgdb_break[i].state = BP_REMOVED;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int kgdb_isremovedbreak(unsigned long addr)
+{
+	int i;
+
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == BP_REMOVED) &&
+					(kgdb_break[i].bpt_addr == addr))
+			return 1;
+	}
+	return 0;
+}
+
+int remove_all_break(void)
+{
+	unsigned long addr;
+	int error;
+	int i;
+
+	/* Clear memory breakpoints. */
+	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state != BP_SET)
+			continue;
+		addr = kgdb_break[i].bpt_addr;
+		error = kgdb_arch_remove_breakpoint(addr,
+				kgdb_break[i].saved_instr);
+		if (error)
+			return error;
+		kgdb_break[i].state = BP_REMOVED;
+	}
+
+	/* Clear hardware breakpoints. */
+	if (arch_kgdb_ops.remove_all_hw_break)
+		arch_kgdb_ops.remove_all_hw_break();
+
+	return 0;
+}
+
+static inline int shadow_pid(int realpid)
+{
+	if (realpid)
+		return realpid;
+
+	return pid_max + raw_smp_processor_id();
+}
+
+static char gdbmsgbuf[BUFMAX + 1];
+
+static void kgdb_msg_write(const char *s, int len)
+{
+	char *bufptr;
+	int wcount;
+	int i;
+
+	/* 'O'utput */
+	gdbmsgbuf[0] = 'O';
+
+	/* Fill and send buffers... */
+	while (len > 0) {
+		bufptr = gdbmsgbuf + 1;
+
+		/* Calculate how many this time */
+		if ((len << 1) > (BUFMAX - 2))
+			wcount = (BUFMAX - 2) >> 1;
+		else
+			wcount = len;
+
+		/* Pack in hex chars */
+		for (i = 0; i < wcount; i++)
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		*bufptr = '\0';
+
+		/* Move up */
+		s += wcount;
+		len -= wcount;
+
+		/* Write packet */
+		put_packet(gdbmsgbuf);
+	}
+}
+
+/*
+ * Return true if there is a valid kgdb I/O module.  Also if no
+ * debugger is attached a message can be printed to the console about
+ * waiting for the debugger to attach.
+ *
+ * The print_wait argument is only to be true when called from inside
+ * the core kgdb_handle_exception, because it will wait for the
+ * debugger to attach.
+ */
+int kgdb_io_ready(int print_wait)
+{
+	if (!kgdb_io_ops)
+		return 0;
+	if (kgdb_connected)
+		return 1;
+	if (atomic_read(&kgdb_setting_breakpoint))
+		return 1;
+	if (print_wait)
+		printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
+	return 1;
+}
+
+/*
+ * All the functions that start with gdb_cmd are the various
+ * operations to implement the handlers for the gdbserial protocol
+ * where KGDB is communicating with an external debugger
+ */
+
+/* Handle the '?' status packets */
+static void gdb_cmd_status(struct kgdb_state *ks)
+{
+	/*
+	 * We know that this packet is only sent
+	 * during initial connect.  So to be safe,
+	 * we clear out our breakpoints now in case
+	 * GDB is reconnecting.
+	 */
+	remove_all_break();
+
+	/*
+	 * Also, if we haven't been able to roundup all
+	 * CPUs, send an 'O' packet informing the user
+	 * as much.  Only need to do this once.
+	 */
+	if (!ks->all_cpus_synced)
+		kgdb_msg_write("Not all CPUs have been synced for KGDB\n", 39);
+
+	remcom_out_buffer[0] = 'S';
+	remcom_out_buffer[1] = hexchars[ks->signo >> 4];
+	remcom_out_buffer[2] = hexchars[ks->signo % 16];
+}
+
+/* Handle the 'g' get registers request */
+static void gdb_cmd_getregs(struct kgdb_state *ks)
+{
+	struct pt_regs *shadowregs;
+	struct task_struct *thread;
+	void *local_debuggerinfo;
+	int i;
+
+	thread = kgdb_usethread;
+	if (!thread) {
+		thread = kgdb_info[ks->cpu].task;
+		local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;
+	} else {
+		local_debuggerinfo = NULL;
+		for (i = 0; i < NR_CPUS; i++) {
+			/*
+			 * Try to find the task on some other
+			 * or possibly this node if we do not
+			 * find the matching task then we try
+			 * to approximate the results.
+			 */
+			if (thread == kgdb_info[i].task)
+				local_debuggerinfo = kgdb_info[i].debuggerinfo;
+		}
+	}
+
+	/*
+	 * All threads that don't have debuggerinfo should be
+	 * in __schedule() sleeping, since all other CPUs
+	 * are in kgdb_wait, and thus have debuggerinfo.
+	 */
+	if (arch_kgdb_ops.shadowth &&
+			ks->kgdb_usethreadid >= pid_max + num_online_cpus()) {
+
+		shadowregs = kgdb_shadow_regs(ks->linux_regs,
+					  ks->kgdb_usethreadid -
+					  pid_max -
+					  num_online_cpus());
+		if (!shadowregs) {
+			error_packet(remcom_out_buffer, -EINVAL);
+			return;
+		}
+		pt_regs_to_gdb_regs(gdb_regs, shadowregs);
+	} else {
+		if (local_debuggerinfo) {
+			pt_regs_to_gdb_regs(gdb_regs, local_debuggerinfo);
+		} else {
+			/*
+			 * Pull stuff saved during switch_to; nothing
+			 * else is accessible (or even particularly
+			 * relevant).
+			 *
+			 * This should be enough for a stack trace.
+			 */
+			sleeping_thread_to_gdb_regs(gdb_regs, thread);
+		}
+	}
+	kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES);
+}
+
+/* Handle the 'G' set registers request */
+static void gdb_cmd_setregs(struct kgdb_state *ks)
+{
+	kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES);
+
+	if (kgdb_usethread && kgdb_usethread != current) {
+		error_packet(remcom_out_buffer, -EINVAL);
+	} else {
+		gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs);
+		strcpy(remcom_out_buffer, "OK");
+	}
+}
+
+/* Handle the 'm' memory read bytes */
+static void gdb_cmd_memread(struct kgdb_state *ks)
+{
+	char *ptr = &remcom_in_buffer[1];
+	unsigned long length;
+	unsigned long addr;
+
+	if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+					kgdb_hex2long(&ptr, &length) > 0) {
+
+		ptr = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);
+		if (IS_ERR(ptr))
+			error_packet(remcom_out_buffer, PTR_ERR(ptr));
+	} else {
+		error_packet(remcom_out_buffer, -EINVAL);
+	}
+}
+
+/* Handle the 'M' memory write bytes */
+static void gdb_cmd_memwrite(struct kgdb_state *ks)
+{
+	char *ptr = write_mem_msg(0);
+
+	if (IS_ERR(ptr))
+		error_packet(remcom_out_buffer, PTR_ERR(ptr));
+	else
+		strcpy(remcom_out_buffer, "OK");
+}
+
+/* Handle the 'X' memory binary write bytes */
+static void gdb_cmd_binwrite(struct kgdb_state *ks)
+{
+	char *ptr = write_mem_msg(1);
+
+	if (IS_ERR(ptr))
+		error_packet(remcom_out_buffer, PTR_ERR(ptr));
+	else
+		strcpy(remcom_out_buffer, "OK");
+}
+
+/* Handle the 'D' or 'k', detach or kill packets */
+static void gdb_cmd_detachkill(struct kgdb_state *ks)
+{
+	int error;
+
+	/* The detach case */
+	if (remcom_in_buffer[0] == 'D') {
+		error = remove_all_break();
+		if (error < 0) {
+			error_packet(remcom_out_buffer, error);
+		} else {
+			strcpy(remcom_out_buffer, "OK");
+			kgdb_connected = 0;
+		}
+		put_packet(remcom_out_buffer);
+	} else {
+		/*
+		 * Assume the kill case, with no exit code checking,
+		 * trying to force detach the debugger:
+		 */
+		remove_all_break();
+		kgdb_connected = 0;
+	}
+}
+
+/* Handle the 'R' reboot packets */
+static int gdb_cmd_reboot(struct kgdb_state *ks)
+{
+	/* For now, only honor R0 */
+	if (strcmp(remcom_in_buffer, "R0") == 0) {
+		printk(KERN_CRIT "Executing reboot\n");
+		strcpy(remcom_out_buffer, "OK");
+		put_packet(remcom_out_buffer);
+		emergency_sync();
+
+		/*
+		 * Execution should not return from
+		 * machine_restart()
+		 */
+		machine_restart(NULL);
+		kgdb_connected = 0;
+
+		return 1;
+	}
+	return 0;
+}
+
+/* Handle the 'q' query packets */
+static void gdb_cmd_query(struct kgdb_state *ks)
+{
+	int numshadowth = num_online_cpus() + arch_kgdb_ops.shadowth;
+	struct task_struct *thread;
+	unsigned char thref[8];
+	char *ptr;
+	int i;
+
+	switch (remcom_in_buffer[1]) {
+	case 's':
+	case 'f':
+		if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) {
+			error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		}
+
+		/*
+		 * If we have not yet completed in
+		 * pidhash_init() there isn't much we
+		 * can give back.
+		 */
+		if (init_pid_ns.last_pid == 0) {
+			if (remcom_in_buffer[1] == 'f')
+				strcpy(remcom_out_buffer, "m0000000000000001");
+			break;
+		}
+
+		if (remcom_in_buffer[1] == 'f')
+			ks->threadid = 1;
+
+		remcom_out_buffer[0] = 'm';
+		ptr = remcom_out_buffer + 1;
+
+		for (i = 0; i < 17 && ks->threadid < pid_max + numshadowth;
+							ks->threadid++) {
+
+			thread = getthread(ks->linux_regs, ks->threadid);
+			if (thread) {
+				int_to_threadref(thref, ks->threadid);
+				pack_threadid(ptr, thref);
+				ptr += 16;
+				*(ptr++) = ',';
+				i++;
+			}
+		}
+		*(--ptr) = '\0';
+		break;
+
+	case 'C':
+		/* Current thread id */
+		strcpy(remcom_out_buffer, "QC");
+		ks->threadid = shadow_pid(current->pid);
+		int_to_threadref(thref, ks->threadid);
+		pack_threadid(remcom_out_buffer + 2, thref);
+		break;
+	case 'T':
+		if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) {
+			error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		}
+		ks->threadid = 0;
+		ptr = remcom_in_buffer + 17;
+		kgdb_hex2long(&ptr, &ks->threadid);
+		if (!getthread(ks->linux_regs, ks->threadid)) {
+			error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		}
+		if (ks->threadid < pid_max) {
+			kgdb_mem2hex(getthread(ks->linux_regs,
+					ks->threadid)->comm,
+					remcom_out_buffer, 16);
+		} else {
+			if (ks->threadid >= pid_max + num_online_cpus()) {
+				kgdb_shadowinfo(ks->linux_regs,
+					remcom_out_buffer,
+					ks->threadid - pid_max -
+					num_online_cpus());
+			} else {
+				static char tmpstr[23 + BUF_THREAD_ID_SIZE];
+				sprintf(tmpstr, "Shadow task %d for pid 0",
+						(int)(ks->threadid - pid_max));
+				kgdb_mem2hex(tmpstr, remcom_out_buffer,
+							 strlen(tmpstr));
+			}
+		}
+		break;
+	}
+}
+
+/* Handle the 'H' task query packets */
+static void gdb_cmd_task(struct kgdb_state *ks)
+{
+	struct task_struct *thread;
+	char *ptr;
+
+	switch (remcom_in_buffer[1]) {
+	case 'g':
+		ptr = &remcom_in_buffer[2];
+		kgdb_hex2long(&ptr, &ks->threadid);
+		thread = getthread(ks->linux_regs, ks->threadid);
+		if (!thread && ks->threadid > 0) {
+			error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		}
+		kgdb_usethread = thread;
+		ks->kgdb_usethreadid = ks->threadid;
+		strcpy(remcom_out_buffer, "OK");
+		break;
+	case 'c':
+		ptr = &remcom_in_buffer[2];
+		kgdb_hex2long(&ptr, &ks->threadid);
+		if (!ks->threadid) {
+			kgdb_contthread = NULL;
+		} else {
+			thread = getthread(ks->linux_regs, ks->threadid);
+			if (!thread && ks->threadid > 0) {
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+			kgdb_contthread = thread;
+		}
+		strcpy(remcom_out_buffer, "OK");
+		break;
+	}
+}
+
+/* Handle the 'T' thread query packets */
+static void gdb_cmd_thread(struct kgdb_state *ks)
+{
+	char *ptr = &remcom_in_buffer[1];
+	struct task_struct *thread;
+
+	kgdb_hex2long(&ptr, &ks->threadid);
+	thread = getthread(ks->linux_regs, ks->threadid);
+	if (thread)
+		strcpy(remcom_out_buffer, "OK");
+	else
+		error_packet(remcom_out_buffer, -EINVAL);
+}
+
+/* Handle the 'z' or 'Z' breakpoint remove or set packets */
+static void gdb_cmd_break(struct kgdb_state *ks)
+{
+	/*
+	 * Since GDB-5.3, it's been drafted that '0' is a software
+	 * breakpoint, '1' is a hardware breakpoint, so let's do that.
+	 */
+	char *bpt_type = &remcom_in_buffer[1];
+	char *ptr = &remcom_in_buffer[2];
+	unsigned long addr;
+	unsigned long length;
+	int error = 0;
+
+	if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') {
+		/* Unsupported */
+		if (*bpt_type > '4')
+			return;
+	} else {
+		if (*bpt_type != '0' && *bpt_type != '1')
+			/* Unsupported. */
+			return;
+	}
+
+	/*
+	 * Test if this is a hardware breakpoint, and
+	 * if we support it:
+	 */
+	if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT))
+		/* Unsupported. */
+		return;
+
+	if (*(ptr++) != ',') {
+		error_packet(remcom_out_buffer, -EINVAL);
+		return;
+	} else {
+		if (kgdb_hex2long(&ptr, &addr)) {
+			if (*(ptr++) != ',' ||
+				!kgdb_hex2long(&ptr, &length)) {
+				error_packet(remcom_out_buffer, -EINVAL);
+				return;
+			}
+		} else {
+			error_packet(remcom_out_buffer, -EINVAL);
+			return;
+		}
+	}
+
+	if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')
+		error = kgdb_set_sw_break(addr);
+	else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
+		error = kgdb_remove_sw_break(addr);
+	else if (remcom_in_buffer[0] == 'Z')
+		error = arch_kgdb_ops.set_hw_breakpoint(addr,
+			(int)length, *bpt_type);
+	else if (remcom_in_buffer[0] == 'z')
+		error = arch_kgdb_ops.remove_hw_breakpoint(addr,
+			(int) length, *bpt_type);
+
+	if (error == 0)
+		strcpy(remcom_out_buffer, "OK");
+	else
+		error_packet(remcom_out_buffer, error);
+}
+
+/* Handle the 'C' signal / exception passing packets */
+static int gdb_cmd_exception_pass(struct kgdb_state *ks)
+{
+	/* C09 == pass exception
+	 * C15 == detach kgdb, pass exception
+	 */
+	if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') {
+
+		ks->pass_exception = 1;
+		remcom_in_buffer[0] = 'c';
+
+	} else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') {
+
+		ks->pass_exception = 1;
+		remcom_in_buffer[0] = 'D';
+		remove_all_break();
+		kgdb_connected = 0;
+		return 1;
+
+	} else {
+		error_packet(remcom_out_buffer, -EINVAL);
+		return 0;
+	}
+
+	/* Indicate fall through */
+	return -1;
+}
+
+/*
+ * This function performs all gdbserial command procesing
+ */
+static int gdb_serial_stub(struct kgdb_state *ks)
+{
+	int error = 0;
+	int tmp;
+
+	/* Clear the out buffer. */
+	memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+	if (kgdb_connected) {
+		unsigned char thref[8];
+		char *ptr;
+
+		/*
+		 * Warn debugger if the CPUs are not synced with an 'O'
+		 * packet:
+		 */
+		if (!ks->all_cpus_synced) {
+			kgdb_msg_write("Not all CPUs have been synced for "
+			       "KGDB\n", 39);
+		}
+		/* Reply to host that an exception has occurred */
+		ptr = remcom_out_buffer;
+		*ptr++ = 'T';
+		*ptr++ = hexchars[(ks->signo >> 4) % 16];
+		*ptr++ = hexchars[ks->signo % 16];
+		ptr += strlen(strcpy(ptr, "thread:"));
+		int_to_threadref(thref, shadow_pid(current->pid));
+		ptr = pack_threadid(ptr, thref);
+		*ptr++ = ';';
+		put_packet(remcom_out_buffer);
+	}
+
+	kgdb_usethread = kgdb_info[ks->cpu].task;
+	ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
+	ks->pass_exception = 0;
+
+	while (1) {
+		error = 0;
+
+		/* Clear the out buffer. */
+		memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+		get_packet(remcom_in_buffer);
+
+		switch (remcom_in_buffer[0]) {
+		case '?': /* gdbserial status */
+			gdb_cmd_status(ks);
+			break;
+		case 'g': /* return the value of the CPU registers */
+			gdb_cmd_getregs(ks);
+			break;
+		case 'G': /* set the value of the CPU registers - return OK */
+			gdb_cmd_setregs(ks);
+			break;
+		case 'm': /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+			gdb_cmd_memread(ks);
+			break;
+		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */
+			gdb_cmd_memwrite(ks);
+			break;
+		case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */
+			gdb_cmd_binwrite(ks);
+			break;
+			/* kill or detach. KGDB should treat this like a
+			 * continue.
+			 */
+		case 'D': /* Debugger detach */
+		case 'k': /* Debugger detach via kill */
+			gdb_cmd_detachkill(ks);
+			goto default_handle;
+		case 'R': /* Reboot */
+			if (gdb_cmd_reboot(ks))
+				goto default_handle;
+			break;
+		case 'q': /* query command */
+			gdb_cmd_query(ks);
+			break;
+		case 'H': /* task related */
+			gdb_cmd_task(ks);
+			break;
+		case 'T': /* Query thread status */
+			gdb_cmd_thread(ks);
+			break;
+		case 'z': /* Break point remove */
+		case 'Z': /* Break point set */
+			gdb_cmd_break(ks);
+			break;
+		case 'C': /* Exception passing */
+			tmp = gdb_cmd_exception_pass(ks);
+			if (tmp > 0)
+				goto default_handle;
+			if (tmp == 0)
+				break;
+			/* Fall through on tmp < 0 */
+		case 'c': /* Continue packet */
+		case 's': /* Single step packet */
+			if (kgdb_contthread && kgdb_contthread != current) {
+				/* Can't switch threads in kgdb */
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+			kgdb_activate_sw_breakpoints();
+			/* Fall through to default processing */
+		default:
+default_handle:
+			error = kgdb_arch_handle_exception(ks->ex_vector,
+						ks->signo,
+						ks->err_code,
+						remcom_in_buffer,
+						remcom_out_buffer,
+						ks->linux_regs);
+			/*
+			 * Leave cmd processing on error, detach,
+			 * kill, continue, or single step.
+			 */
+			if (error >= 0 || remcom_in_buffer[0] == 'D' ||
+			    remcom_in_buffer[0] == 'k') {
+				error = 0;
+				goto kgdb_exit;
+			}
+
+		}
+
+		/* reply to the request */
+		put_packet(remcom_out_buffer);
+	}
+
+kgdb_exit:
+	if (ks->pass_exception)
+		error = 1;
+	return error;
+}
+
+static int kgdb_reenter_check(struct kgdb_state *ks)
+{
+	unsigned long addr;
+
+	if (atomic_read(&debugger_active) != raw_smp_processor_id() + 1)
+		return 0;
+
+	/* Panic on recursive debugger calls: */
+	exception_level++;
+	addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs);
+	kgdb_deactivate_sw_breakpoints();
+
+	/*
+	 * If the break point removed ok at the place exception
+	 * occurred, try to recover and print a warning to the end
+	 * user because the user planted a breakpoint in a place that
+	 * KGDB needs in order to function.
+	 */
+	if (kgdb_remove_sw_break(addr) == 0) {
+		exception_level = 0;
+		kgdb_skipexception(ks->ex_vector, ks->linux_regs);
+		kgdb_activate_sw_breakpoints();
+		printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed\n");
+		WARN_ON(1);
+		return 1;
+	}
+	remove_all_break();
+	kgdb_skipexception(ks->ex_vector, ks->linux_regs);
+
+	if (exception_level > 1) {
+		dump_stack();
+		panic("Recursive entry to debugger");
+	}
+
+	printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n");
+	dump_stack();
+	panic("Recursive entry to debugger");
+
+	return 1;
+}
+
+/*
+ * kgdb_handle_exception() - main entry point from a kernel exception
+ *
+ * Locking hierarchy:
+ *	interface locks, if any (begin_session)
+ *	kgdb lock (debugger_active)
+ *
+ * Note that since we can be in here prior to our cpumask being filled
+ * out, we err on the side of caution and loop over NR_CPUS instead
+ * of a for_each_online_cpu.
+ */
+int
+kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
+{
+	struct kgdb_state kgdb_var;
+	struct kgdb_state *ks = &kgdb_var;
+	unsigned long flags;
+	int error = 0;
+	int i, cpu;
+
+	ks->cpu			= raw_smp_processor_id();
+	ks->all_cpus_synced	= 0;
+	ks->ex_vector		= evector;
+	ks->signo		= signo;
+	ks->ex_vector		= evector;
+	ks->err_code		= ecode;
+	ks->kgdb_usethreadid	= 0;
+	ks->linux_regs		= regs;
+
+	if (kgdb_reenter_check(ks))
+		return 0; /* Ouch, double exception ! */
+
+acquirelock:
+	/*
+	 * Interrupts will be restored by the 'trap return' code, except when
+	 * single stepping.
+	 */
+	local_irq_save(flags);
+
+	cpu = raw_smp_processor_id();
+
+	/*
+	 * Being the process of declaring a master debug processor, the
+	 * goal is to have only one single processor set debugger_active
+	 * to the number of the cpu + 1.  The atomic variable kgdb_sync is
+	 * used to control the selection.
+	 */
+	while (1) {
+		i = 25;	/* an arbitrary number */
+		if (atomic_read(&kgdb_sync) < 0 &&
+			atomic_inc_and_test(&kgdb_sync)) {
+			atomic_set(&debugger_active, cpu + 1);
+			break;
+		}
+
+		while (--i)
+			cpu_relax();
+
+		if (atomic_read(&cpu_doing_single_step) != -1 &&
+				atomic_read(&cpu_doing_single_step) != cpu)
+			udelay(1);
+	}
+
+	/*
+	 * Do not start the debugger connection on this CPU if the last
+	 * instance of the exception handler wanted to come into the
+	 * debugger on a different CPU via a single step
+	 */
+	if (atomic_read(&cpu_doing_single_step) != -1 &&
+	    atomic_read(&cpu_doing_single_step) != cpu) {
+
+		atomic_set(&debugger_active, 0);
+		atomic_set(&kgdb_sync, -1);
+		clocksource_touch_watchdog();
+		kgdb_softlock_touch(cpu);
+		local_irq_restore(flags);
+
+		goto acquirelock;
+	}
+
+	if (!kgdb_io_ready(1)) {
+		error = 1;
+		goto kgdb_restore; /* No I/O connection, so resume the system */
+	}
+
+	/*
+	 * Don't enter if we have hit a removed breakpoint.
+	 */
+	if (kgdb_skipexception(ks->ex_vector, ks->linux_regs))
+		goto kgdb_restore;
+
+	/* Call the I/O driver's pre_exception routine */
+	if (kgdb_io_ops->pre_exception)
+		kgdb_io_ops->pre_exception();
+
+	kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs;
+	kgdb_info[ks->cpu].task = current;
+
+	kgdb_disable_hw_debug(ks->linux_regs);
+
+	/*
+	 * Get the slave CPU lock which will hold all the non-master
+	 * CPU in a spin state while the debugger is active
+	 */
+	if (!debugger_step || !kgdb_contthread) {
+		for (i = 0; i < NR_CPUS; i++)
+			spin_lock(&slave_cpu_locks[i]);
+	}
+
+#ifdef CONFIG_SMP
+	/* Signal the other CPUs to enter kgdb_wait() */
+	if (!debugger_step || !kgdb_contthread)
+		kgdb_roundup_cpus(flags);
+#endif
+
+	/*
+	 * spin_lock code is good enough as a barrier so we don't
+	 * need one here:
+	 */
+	atomic_set(&cpu_in_debugger[ks->cpu], 1);
+
+	/*
+	 * Wait a reasonable time for the other CPUs to be notified and
+	 * be waiting for us.  Very early on this could be imperfect
+	 * as num_online_cpus() could be 0.
+	 */
+	for (i = 0; i < ROUNDUP_WAIT; i++) {
+		int num = 0;
+		int n;
+
+		for (n = 0; n < NR_CPUS; n++) {
+			if (atomic_read(&cpu_in_debugger[n]))
+				num++;
+		}
+		if (num >= num_online_cpus()) {
+			ks->all_cpus_synced = 1;
+			break;
+		}
+	}
+
+	/* Master processor is completely in the debugger */
+	kgdb_post_master_code(ks->linux_regs, ks->ex_vector, ks->err_code);
+	kgdb_deactivate_sw_breakpoints();
+	debugger_step = 0;
+	kgdb_contthread = NULL;
+	exception_level = 0;
+
+	/* Talk to debugger with gdbserial protocol */
+	error = gdb_serial_stub(ks);
+
+	/* Call the I/O driver's post_exception routine */
+	if (kgdb_io_ops->post_exception)
+		kgdb_io_ops->post_exception();
+
+	kgdb_info[ks->cpu].debuggerinfo = NULL;
+	kgdb_info[ks->cpu].task = NULL;
+	atomic_set(&cpu_in_debugger[ks->cpu], 0);
+
+	if (!debugger_step || !kgdb_contthread) {
+		for (i = NR_CPUS-1; i >= 0; i--)
+			spin_unlock(&slave_cpu_locks[i]);
+		/*
+		 * Wait till all the CPUs have quit
+		 * from the debugger.
+		 */
+		for (i = 0; i < NR_CPUS; i++) {
+			while (atomic_read(&cpu_in_debugger[i])) {
+				int j = 10;	/* an arbitrary number */
+
+				while (--j)
+					cpu_relax();
+			}
+		}
+	}
+
+#ifdef CONFIG_SMP
+	/*
+	 * This delay has a real purpose.  The problem is that if you
+	 * are single-stepping, you are sending an NMI to all the
+	 * other CPUs to stop them.  Interrupts come in, but don't get
+	 * handled.  Then you let them go just long enough to get into
+	 * their interrupt routines and use up some stack. You stop them
+	 * again, and then do the same thing.  After a while you blow
+	 * the stack on the other CPUs. This delay gives some time for
+	 * interrupts to be cleared out on the other CPUs.
+	 */
+	if (debugger_step)
+		mdelay(2);
+#endif
+kgdb_restore:
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+	atomic_set(&kgdb_sync, -1);
+	clocksource_touch_watchdog();
+	kgdb_softlock_touch(ks->cpu);
+	local_irq_restore(flags);
+
+	return error;
+}
+
+/*
+ * GDB places a breakpoint at this function to know dynamically
+ * loaded objects. It's not defined static so that only one instance with this
+ * name exists in the kernel.
+ */
+
+int module_event(struct notifier_block *self, unsigned long val, void *data)
+{
+	return 0;
+}
+
+static struct notifier_block kgdb_module_load_nb = {
+	.notifier_call	= module_event,
+};
+
+int kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+	if (!atomic_read(&cpu_in_debugger[cpu]) &&
+		atomic_read(&debugger_active) != (cpu + 1)) {
+		kgdb_wait((struct pt_regs *)regs);
+		return 0;
+	}
+#endif
+	return 1;
+}
+
+/*
+ * This is called when a panic happens.  All we need to do is
+ * breakpoint().
+ */
+static int
+kgdb_panic_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	if (kgdb_active()) {
+		printk(KERN_ERR "KGDB: Cannot handle panic while"
+				"debugger active\n");
+		dump_stack();
+		return NOTIFY_DONE;
+	}
+	breakpoint();
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kgdb_panic_notifier = {
+	.notifier_call	= kgdb_panic_notify,
+};
+
+#ifdef CONFIG_KGDB_CONSOLE
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+	unsigned long flags;
+
+	/* If we're debugging, or KGDB has not connected, don't try
+	 * and print. */
+	if (!kgdb_connected || kgdb_active())
+		return;
+
+	local_irq_save(flags);
+	kgdb_msg_write(s, count);
+	local_irq_restore(flags);
+}
+
+static struct console kgdbcons = {
+	.name		= "kgdb",
+	.write		= kgdb_console_write,
+	.flags		= CON_PRINTBUFFER | CON_ENABLED,
+	.index		= -1,
+};
+#endif
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_handle_gdb(int key, struct tty_struct *tty)
+{
+	if (!kgdb_io_ops) {
+		printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
+		return;
+	}
+	if (!kgdb_connected)
+		printk(KERN_CRIT "Entering KGDB\n");
+
+	breakpoint();
+}
+
+static struct sysrq_key_op sysrq_gdb_op = {
+	.handler	= sysrq_handle_gdb,
+	.help_msg	= "Gdb",
+	.action_msg	= "GDB",
+};
+#endif
+
+static void kgdb_register_hooks(void)
+{
+	if (!kgdb_io_module_registered) {
+		kgdb_io_module_registered = 1;
+		kgdb_arch_init();
+		atomic_notifier_chain_register(&panic_notifier_list,
+					&kgdb_panic_notifier);
+		register_module_notifier(&kgdb_module_load_nb);
+		register_reboot_notifier(&kgdb_reboot_notifier);
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+		atomic_notifier_chain_register(&softlock_chain,
+					&kgdb_softlock_notifier);
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+		register_sysrq_key('g', &sysrq_gdb_op);
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+		/* Initialize the console registration */
+		register_console(&kgdbcons);
+#endif
+	}
+}
+
+static void kgdb_unregister_hooks(void)
+{
+	/*
+	 * When this routine is called KGDB should unregister from the
+	 * panic handler and clean up, making sure it is not handling any
+	 * break exceptions at the time.
+	 */
+	if (kgdb_io_module_registered) {
+		kgdb_io_module_registered = 0;
+		kgdb_arch_uninit();
+		atomic_notifier_chain_unregister(&panic_notifier_list,
+					  &kgdb_panic_notifier);
+		unregister_module_notifier(&kgdb_module_load_nb);
+		unregister_reboot_notifier(&kgdb_reboot_notifier);
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+		atomic_notifier_chain_unregister(&softlock_chain,
+					&kgdb_softlock_notifier);
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+		unregister_sysrq_key('g', &sysrq_gdb_op);
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+		/* Initialize the console registration */
+		unregister_console(&kgdbcons);
+#endif
+	}
+}
+
+static void kgdb_initial_breakpoint(void)
+{
+	kgdb_break_asap = 0;
+
+	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
+	breakpoint();
+}
+
+int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops)
+{
+	int err;
+
+	spin_lock(&kgdb_registration_lock);
+
+	if (kgdb_io_ops) {
+		spin_unlock(&kgdb_registration_lock);
+
+		printk(KERN_ERR "kgdb: Another I/O driver is already "
+				"registered with KGDB.\n");
+		return -EBUSY;
+	}
+
+	if (new_kgdb_io_ops->init) {
+		err = new_kgdb_io_ops->init();
+		if (err) {
+			spin_unlock(&kgdb_registration_lock);
+			return err;
+		}
+	}
+
+	kgdb_io_ops = new_kgdb_io_ops;
+
+	spin_unlock(&kgdb_registration_lock);
+
+	printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
+	       new_kgdb_io_ops->name);
+
+	/* Arm KGDB now. */
+	kgdb_register_hooks();
+
+	if (kgdb_break_asap)
+		kgdb_initial_breakpoint();
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kgdb_register_io_module);
+
+void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops)
+{
+	BUG_ON(kgdb_connected);
+
+	/*
+	 * KGDB is no longer able to communicate out, so
+	 * unregister our hooks and reset state.
+	 */
+	kgdb_unregister_hooks();
+
+	spin_lock(&kgdb_registration_lock);
+
+	WARN_ON(kgdb_io_ops != old_kgdb_io_ops);
+	kgdb_io_ops = NULL;
+
+	spin_unlock(&kgdb_registration_lock);
+
+	printk(KERN_INFO "kgdb: Unregistered I/O driver %s, debugger "
+		"disabled.\n", old_kgdb_io_ops->name);
+}
+EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
+
+/*
+ * This function will generate a breakpoint exception.  It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+void breakpoint(void)
+{
+	atomic_set(&kgdb_setting_breakpoint, 1);
+	wmb(); /* Sync point before breakpoint */
+	BREAKPOINT();
+	wmb(); /* Sync point after breakpoint */
+	atomic_set(&kgdb_setting_breakpoint, 0);
+}
+EXPORT_SYMBOL_GPL(breakpoint);
+
+static int
+kgdb_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+	unsigned long flags;
+
+	/*
+	 * If we're debugging, or KGDB has not connected, don't try
+	 * and print:
+	 */
+	if (!kgdb_connected || kgdb_active())
+		return 0;
+
+	if (code == SYS_RESTART || code == SYS_HALT || code == SYS_POWER_OFF) {
+		local_irq_save(flags);
+		put_packet("X00");
+		kgdb_connected = 0;
+		local_irq_restore(flags);
+	}
+	return NOTIFY_DONE;
+}
+
+static int __init opt_kgdb_wait(char *str)
+{
+	kgdb_break_asap = 1;
+
+	if (kgdb_io_module_registered)
+		kgdb_initial_breakpoint();
+
+	return 0;
+}
+
+early_param("kgdbwait", opt_kgdb_wait);
diff --git a/kernel/sched.c b/kernel/sched.c
index 3eedd52..093b803 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -61,6 +61,7 @@
 #include <linux/times.h>
 #include <linux/tsacct_kern.h>
 #include <linux/kprobes.h>
+#include <linux/kgdb.h>
 #include <linux/delayacct.h>
 #include <linux/reciprocal_div.h>
 #include <linux/unistd.h>
@@ -7263,7 +7264,7 @@ void __might_sleep(char *file, int line)
 #ifdef in_atomic
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
-	if ((in_atomic() || irqs_disabled()) &&
+	if ((in_atomic() || irqs_disabled()) && !kgdb_active() &&
 	    system_state == SYSTEM_RUNNING && !oops_in_progress) {
 		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
 			return;
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 7c2da88..d9658c0 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -15,6 +15,7 @@
 #include <linux/kthread.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq_regs.h>
 
@@ -24,6 +25,8 @@ static DEFINE_PER_CPU(unsigned long, touch_timestamp);
 static DEFINE_PER_CPU(unsigned long, print_timestamp);
 static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
 
+ATOMIC_NOTIFIER_HEAD(softlock_chain);
+
 static int __read_mostly did_panic;
 unsigned long __read_mostly softlockup_thresh = 60;
 
@@ -52,7 +55,6 @@ static unsigned long get_timestamp(int this_cpu)
 void touch_softlockup_watchdog(void)
 {
 	int this_cpu = raw_smp_processor_id();
-
 	__raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
@@ -109,6 +111,9 @@ void softlockup_tick(void)
 	if (now <= (touch_timestamp + softlockup_thresh))
 		return;
 
+	if (atomic_notifier_call_chain(&softlock_chain, 0, &touch_timestamp) == NOTIFY_STOP)
+		return;
+
 	per_cpu(print_timestamp, this_cpu) = touch_timestamp;
 
 	spin_lock(&print_lock);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 548c436..ace23d3 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -228,6 +228,18 @@ void clocksource_resume(void)
 }
 
 /**
+ * clocksource_touch_watchdog - Update watchdog
+ *
+ * Update the watchdog after exception contexts such as kgdb so as not
+ * to incorrectly trip the watchdog.
+ *
+ */
+void clocksource_touch_watchdog(void)
+{
+	clocksource_resume_watchdog();
+}
+
+/**
  * clocksource_get_next - Returns the selected clocksource
  *
  */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ce0bb26..9824ff6 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -632,3 +632,5 @@ config PROVIDE_OHCI1394_DMA_INIT
 	  See Documentation/debugging-via-ohci1394.txt for more information.
 
 source "samples/Kconfig"
+
+source "lib/Kconfig.kgdb"
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
new file mode 100644
index 0000000..afa61bb
--- /dev/null
+++ b/lib/Kconfig.kgdb
@@ -0,0 +1,32 @@
+
+menuconfig KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	select KGDB_ARCH_HAS_SHADOW_INFO if X86_64
+	select DEBUG_INFO
+	select FRAME_POINTER
+	depends on DEBUG_KERNEL && ADD_A_KGDB_ARCH
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb.  Documentation of kernel debugger is available
+	  at http://kgdb.sourceforge.net as well as in DocBook form
+	  in Documentation/DocBook/.  If unsure, say N.
+
+config KGDB_ARCH_HAS_SHADOW_INFO
+	bool
+	depends on KGDB
+
+config KGDB_CONSOLE
+	bool "Console messages through gdb"
+	depends on KGDB
+	help
+	  If you say Y here, console messages will appear through gdb.
+	  Other consoles such as tty or ttyS will continue to work as usual.
+	  Note that if you use this in conjunction with KGDBOE, if the
+	  ethernet driver runs into an error condition during use with KGDB,
+	  it is possible to hit an infinite recursion, causing the kernel
+	  to crash, and typically reboot.  For this reason, it is preferable
+	  to use NETCONSOLE in conjunction with KGDBOE instead of
+	  KGDB_CONSOLE.
+
+comment "KGDB I/O drivers"
+	depends on KGDB
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/8] pid, kgdb: add pid_max prototype
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
@ 2008-02-09 13:35   ` jason.wessel
  2008-02-09 13:35     ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB jason.wessel
  2008-02-09 17:10     ` [PATCH 2/8] pid, kgdb: add pid_max prototype Christoph Hellwig
  2008-02-09 14:27   ` [PATCH 1/8] kgdb: core API and gdb protocol handler Jan Kiszka
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Thomas Gleixner, Jason Wessel

From: Ingo Molnar <mingo@elte.hu>

add pid_max prototype - now used by sysctl and kgdb as well.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 include/linux/pid.h |    2 ++
 kernel/kgdb.c       |    2 +-
 kernel/sysctl.c     |    2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index f84d532..e066d3d 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -86,6 +86,8 @@ extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
 
 extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
 
+extern int pid_max;
+
 /*
  * attach_pid() and detach_pid() must be called with the tasklist_lock
  * write-held.
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 3f06d09..2986bd2 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -45,6 +45,7 @@
 #include <linux/sysrq.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
+#include <linux/pid.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
 
@@ -101,7 +102,6 @@ struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS] = {
  * CPU having a lock:
  */
 
-extern int pid_max;
 /* How many times to count all of the waiting CPUs */
 #define ROUNDUP_WAIT		640000	/* Arbitrary, increase if needed. */
 #define BUF_THREAD_ID_SIZE	16
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d41ef6b..97a152c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kobject.h>
+#include <linux/pid.h>
 #include <linux/net.h>
 #include <linux/sysrq.h>
 #include <linux/highuid.h>
@@ -71,7 +72,6 @@ extern int max_threads;
 extern int core_uses_pid;
 extern int suid_dumpable;
 extern char core_pattern[];
-extern int pid_max;
 extern int min_free_kbytes;
 extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB
  2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
@ 2008-02-09 13:35     ` jason.wessel
  2008-02-09 13:35       ` [PATCH 4/8] kgdb: COPTIMIZE flag jason.wessel
  2008-02-09 17:15       ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB Christoph Hellwig
  2008-02-09 17:10     ` [PATCH 2/8] pid, kgdb: add pid_max prototype Christoph Hellwig
  1 sibling, 2 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel, Ingo Molnar, Thomas Gleixner

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

With more information in the kernel, gdb can be modified in such a way
as to automatically read the kernel module section information and
allow for easy kernel module debugging.

In gdb the solib-search-path must contain the location of any module
to be debugged.  When a module is loaded GDB acts like a shared
library has been loaded and will collect the information about the
memory location so the kernel module can be debugged or inspected.

Even when not using kgdb+gdb, it is quite useful for a
debugger+ICE/jtag to have the module section information.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/module.h |    9 ++++++---
 kernel/module.c        |   34 ++++++++++++++++++++++------------
 2 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index ac28e87..87b0301 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -342,13 +342,16 @@ struct module
 	unsigned long num_symtab;
 	char *strtab;
 
-	/* Section attributes */
-	struct module_sect_attrs *sect_attrs;
-
 	/* Notes attributes */
 	struct module_notes_attrs *notes_attrs;
 #endif
 
+#if defined(CONFIG_KALLSYMS) || defined(CONFIG_KGDB)
+	/* Section attributes */
+	struct module_sect_attrs *sect_attrs;
+#endif
+
+
 	/* Per-cpu data. */
 	void *percpu;
 
diff --git a/kernel/module.c b/kernel/module.c
index 4202da9..4a94d1a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -602,6 +602,9 @@ static void module_unload_free(struct module *mod)
 			}
 		}
 	}
+	blocking_notifier_call_chain(&module_notify_list,
+				MODULE_STATE_GOING,
+				mod);
 }
 
 #ifdef CONFIG_MODULE_FORCE_UNLOAD
@@ -992,6 +995,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
  * /sys/module/foo/sections stuff
  * J. Corbet <corbet@lwn.net>
  */
+#if defined(CONFIG_KALLSYMS) || defined(CONFIG_KGDB)
 #ifdef CONFIG_KALLSYMS
 static ssize_t module_sect_show(struct module_attribute *mattr,
 				struct module *mod, char *buf)
@@ -1000,6 +1004,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
 		container_of(mattr, struct module_sect_attr, mattr);
 	return sprintf(buf, "0x%lx\n", sattr->address);
 }
+#endif /* CONFIG_KALLSYMS */
 
 static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
 {
@@ -1046,7 +1051,9 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
 		if (sattr->name == NULL)
 			goto out;
 		sect_attrs->nsections++;
+#ifdef CONFIG_KALLSYMS
 		sattr->mattr.show = module_sect_show;
+#endif
 		sattr->mattr.store = NULL;
 		sattr->mattr.attr.name = sattr->name;
 		sattr->mattr.attr.mode = S_IRUGO;
@@ -1074,7 +1081,20 @@ static void remove_sect_attrs(struct module *mod)
 		mod->sect_attrs = NULL;
 	}
 }
+#else /* ! (CONFIG_KALLSYMS || CONFIG_KGDB) */
 
+static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
+		char *sectstrings, Elf_Shdr *sechdrs)
+{
+}
+
+static inline void remove_sect_attrs(struct module *mod)
+{
+}
+
+#endif /* CONFIG_KALLSYMS || CONFIG_KGDB */
+
+#ifdef CONFIG_KALLSYMS
 /*
  * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
  */
@@ -1168,18 +1188,7 @@ static void remove_notes_attrs(struct module *mod)
 	if (mod->notes_attrs)
 		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
 }
-
 #else
-
-static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
-		char *sectstrings, Elf_Shdr *sechdrs)
-{
-}
-
-static inline void remove_sect_attrs(struct module *mod)
-{
-}
-
 static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
 				   char *sectstrings, Elf_Shdr *sechdrs)
 {
@@ -1188,7 +1197,8 @@ static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
 static inline void remove_notes_attrs(struct module *mod)
 {
 }
-#endif /* CONFIG_KALLSYMS */
+#endif
+
 
 #ifdef CONFIG_SYSFS
 int module_add_modinfo_attrs(struct module *mod)
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/8] kgdb: COPTIMIZE flag
  2008-02-09 13:35     ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB jason.wessel
@ 2008-02-09 13:35       ` jason.wessel
  2008-02-09 13:35         ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support jason.wessel
  2008-02-09 17:16         ` [PATCH 4/8] kgdb: COPTIMIZE flag Christoph Hellwig
  2008-02-09 17:15       ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB Christoph Hellwig
  1 sibling, 2 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel, Ingo Molnar, Thomas Gleixner

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

This patch adds in the ability to unoptimize a single kernel module to
make source stepping more linear and not optimize out variables that
the developer might like to inspect.  It used with adding
COPTIMIZE=-O0 to the build line when doing something like a single
kernel module only build.  Or you could use it to override the default
optimization level entirely.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 Makefile |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 89f2d8b..65aa7f8 100644
--- a/Makefile
+++ b/Makefile
@@ -502,10 +502,14 @@ endif # $(dot-config)
 all: vmlinux
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS	+= -Os
+COPTIMIZE	+= -Os
 else
-KBUILD_CFLAGS	+= -O2
+COPTIMIZE	+= -O2
 endif
+# COPTIMIZE may be overridden on the make command line with
+# 	make ... COPTIMIZE=""
+# The resulting object may be easier to debug with KGDB
+KBUILD_CFLAGS	+= $(COPTIMIZE)
 
 include $(srctree)/arch/$(SRCARCH)/Makefile
 
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support
  2008-02-09 13:35       ` [PATCH 4/8] kgdb: COPTIMIZE flag jason.wessel
@ 2008-02-09 13:35         ` jason.wessel
  2008-02-09 13:35           ` [PATCH 6/8] kgdb, sysrq_bugfix jason.wessel
  2008-02-09 14:33           ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support Jan Kiszka
  2008-02-09 17:16         ` [PATCH 4/8] kgdb: COPTIMIZE flag Christoph Hellwig
  1 sibling, 2 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel, Jan Kiszka, Ingo Molnar, Thomas Gleixner

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

On the i386 arch, in order to support early debugginer with kgdb when
used with kgdb via rs232 some traps must be initialized sooner rather
than later, but it is safe to always do this. The arch i386 now calls
parse_early_param() to explicitly look at anything marked
early_param().  KGDB also adds an additional IPI die hook to catch NMI
as well as IPI and to disinguish between the two. To achieve better
back trace results from the debugger some labels were added to the
switch_to macros.

This patch also add primative hardware breakpoint support from KGDB in
the kernel only context for the x86_64 and i386 arch.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/kernel/Makefile   |    1 +
 arch/x86/kernel/kgdb.c     |  533 ++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/setup_32.c |    2 +
 arch/x86/kernel/setup_64.c |    4 +
 arch/x86/kernel/traps_32.c |   14 +-
 arch/x86/kernel/traps_64.c |   17 ++-
 include/asm-x86/kgdb.h     |   79 +++++++
 include/asm-x86/system.h   |    3 +
 lib/Kconfig.kgdb           |    2 +-
 9 files changed, 648 insertions(+), 7 deletions(-)
 create mode 100644 arch/x86/kernel/kgdb.c
 create mode 100644 include/asm-x86/kgdb.h

diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 21dc1a0..3784bab 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_MODULES)		+= module_$(BITS).o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat_32.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
+obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_VM86)		+= vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
new file mode 100644
index 0000000..ac3624f
--- /dev/null
+++ b/arch/x86/kernel/kgdb.c
@@ -0,0 +1,533 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Amit S. Kale <amitkale@linsyssoft.com>
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002 Andi Kleen, SuSE Labs
+ * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd.
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ * Copyright (C) 2007-2008 Jason Wessel, Wind River Systems, Inc.
+ */
+/****************************************************************************
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  Updated by:	     Tom Rini <trini@kernel.crashing.org>
+ *  Updated by:	     Jason Wessel <jason.wessel@windriver.com>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by
+ *  David Grothe <dave@gcom.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  X86_64 changes from Andi Kleen's patch merged by Jim Houston
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <linux/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <linux/kdebug.h>
+#include <asm/apicdef.h>
+#ifdef CONFIG_X86_32
+#include <mach_ipi.h>
+#else /* !CONFIG_X86_32 */
+#include <asm/mach_apic.h>
+#endif /* !CONFIG_X86_32 */
+
+/* Put the error code here just in case the user cares.  */
+static int gdb_x86errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+static int gdb_x86vector = -1;
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_AX] = regs->ax;
+	gdb_regs[_BX] = regs->bx;
+	gdb_regs[_CX] = regs->cx;
+	gdb_regs[_DX] = regs->dx;
+	gdb_regs[_SI] = regs->si;
+	gdb_regs[_DI] = regs->di;
+	gdb_regs[_BP] = regs->bp;
+	gdb_regs[_PS] = regs->flags;
+	gdb_regs[_PC] = regs->ip;
+#ifdef CONFIG_X86_32
+	gdb_regs[_DS] = regs->ds;
+	gdb_regs[_ES] = regs->es;
+	gdb_regs[_CS] = regs->cs;
+	gdb_regs[_SP] = (int)(&regs->sp);
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+#else /* ! CONFIG_X86_32 */
+	gdb_regs[_R8] = regs->r8;
+	gdb_regs[_R9] = regs->r9;
+	gdb_regs[_R10] = regs->r10;
+	gdb_regs[_R11] = regs->r11;
+	gdb_regs[_R12] = regs->r12;
+	gdb_regs[_R13] = regs->r13;
+	gdb_regs[_R14] = regs->r14;
+	gdb_regs[_R15] = regs->r15;
+	gdb_regs[_SP] = regs->sp;
+#endif /* ! CONFIG_X86_32 */
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	gdb_regs[_AX] = 0;
+	gdb_regs[_BX] = 0;
+	gdb_regs[_CX] = 0;
+	gdb_regs[_DX] = 0;
+	gdb_regs[_SI] = 0;
+	gdb_regs[_DI] = 0;
+	gdb_regs[_BP] = *(unsigned long *)p->thread.sp;
+#ifdef CONFIG_X86_32
+	gdb_regs[_DS] = __KERNEL_DS;
+	gdb_regs[_ES] = __KERNEL_DS;
+	gdb_regs[_PS] = 0;
+	gdb_regs[_CS] = __KERNEL_CS;
+	gdb_regs[_PC] = p->thread.ip;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+#else /* ! CONFIG_X86_32 */
+	gdb_regs[_PS] = *(unsigned long *)(p->thread.sp + 8);
+	gdb_regs[_PC] = (unsigned long)&thread_return;
+	gdb_regs[_R8] = 0;
+	gdb_regs[_R9] = 0;
+	gdb_regs[_R10] = 0;
+	gdb_regs[_R11] = 0;
+	gdb_regs[_R12] = 0;
+	gdb_regs[_R13] = 0;
+	gdb_regs[_R14] = 0;
+	gdb_regs[_R15] = 0;
+#endif /* ! CONFIG_X86_32 */
+	gdb_regs[_SP] = p->thread.sp;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->ax = gdb_regs[_AX];
+	regs->bx = gdb_regs[_BX];
+	regs->cx = gdb_regs[_CX];
+	regs->dx = gdb_regs[_DX];
+	regs->si = gdb_regs[_SI];
+	regs->di = gdb_regs[_DI];
+	regs->bp = gdb_regs[_BP];
+	regs->flags = gdb_regs[_PS];
+	regs->ip = gdb_regs[_PC];
+#ifdef CONFIG_X86_32
+	regs->ds = gdb_regs[_DS];
+	regs->es = gdb_regs[_ES];
+	regs->cs = gdb_regs[_CS];
+#else /* ! CONFIG_X86_32 */
+	regs->r8 = gdb_regs[_R8];
+	regs->r9 = gdb_regs[_R9];
+	regs->r10 = gdb_regs[_R10];
+	regs->r11 = gdb_regs[_R11];
+	regs->r12 = gdb_regs[_R12];
+	regs->r13 = gdb_regs[_R13];
+	regs->r14 = gdb_regs[_R14];
+	regs->r15 = gdb_regs[_R15];
+#endif /* ! CONFIG_X86_32 */
+}
+
+static struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = {
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+};
+
+static void kgdb_correct_hw_break(void)
+{
+	int breakno;
+	int breakbit;
+	int correctit = 0;
+	unsigned long dr7;
+
+	get_debugreg(dr7, 7);
+	for (breakno = 0; breakno < 4; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= ((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) <<
+			       ((breakno << 2) + 16);
+			switch (breakno) {
+			case 0:
+				set_debugreg(breakinfo[0].addr, 0);
+				break;
+
+			case 1:
+				set_debugreg(breakinfo[1].addr, 1);
+				break;
+
+			case 2:
+				set_debugreg(breakinfo[2].addr, 2);
+				break;
+
+			case 3:
+				set_debugreg(breakinfo[3].addr, 3);
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit)
+		set_debugreg(dr7, 7);
+}
+
+static int kgdb_remove_hw_break(unsigned long addr, int len,
+				enum kgdb_bptype bptype)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		if (breakinfo[i].addr == addr && breakinfo[i].enabled)
+			break;
+	if (i == 4)
+		return -1;
+
+	breakinfo[i].enabled = 0;
+	return 0;
+}
+
+static void kgdb_remove_all_hw_break(void)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
+}
+
+static int kgdb_set_hw_break(unsigned long addr, int len,
+			     enum kgdb_bptype bptype)
+{
+	int i;
+	unsigned type;
+
+	for (i = 0; i < 4; i++)
+		if (!breakinfo[i].enabled)
+			break;
+	if (i == 4)
+		return -1;
+
+	switch (bptype) {
+	case BP_HARDWARE_BREAKPOINT:
+		type = 0;
+		len  = 1;
+		break;
+	case BP_WRITE_WATCHPOINT:
+		type = 1;
+		break;
+	case BP_ACCESS_WATCHPOINT:
+		type = 3;
+		break;
+	default:
+		return -1;
+	}
+
+	if (len == 1 || len == 2 || len == 4)
+		breakinfo[i].len  = len - 1;
+	else
+		return -1;
+
+	breakinfo[i].enabled = 1;
+	breakinfo[i].addr = addr;
+	breakinfo[i].type = type;
+	return 0;
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+	/* Disable hardware debugging while we are in kgdb */
+	set_debugreg(0UL, 7);
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_x86vector = e_vector;
+	gdb_x86errcode = err_code;
+}
+
+#ifdef CONFIG_SMP
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+			       char *remcomInBuffer, char *remcomOutBuffer,
+			       struct pt_regs *linux_regs)
+{
+	unsigned long addr;
+	char *ptr;
+	int newPC;
+	unsigned long dr6;
+
+	switch (remcomInBuffer[0]) {
+	case 'c':
+	case 's':
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcomInBuffer[1];
+		if (kgdb_hex2long(&ptr, &addr))
+			linux_regs->ip = addr;
+		newPC = linux_regs->ip;
+
+		/* clear the trace bit */
+		linux_regs->flags &= ~TF_MASK;
+		atomic_set(&cpu_doing_single_step, -1);
+
+		/* set the trace bit if we're stepping */
+		if (remcomInBuffer[0] == 's') {
+			linux_regs->flags |= TF_MASK;
+			debugger_step = 1;
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   raw_smp_processor_id());
+
+		}
+
+		get_debugreg(dr6, 6);
+		if (!(dr6 & 0x4000)) {
+			int breakno;
+
+			for (breakno = 0; breakno < 4; breakno++) {
+				if (dr6 & (1 << breakno) &&
+				    breakinfo[breakno].type == 0) {
+					/* Set restore flag */
+					linux_regs->flags |= X86_EFLAGS_RF;
+					break;
+				}
+			}
+		}
+		set_debugreg(0UL, 6);
+		kgdb_correct_hw_break();
+
+		return 0;
+	}
+	/* this means that we do not want to exit from the handler */
+	return -1;
+}
+
+#ifndef CONFIG_X86_32
+static struct pt_regs *in_interrupt_stack(unsigned long rsp, int cpu)
+{
+	struct pt_regs *regs = NULL;
+	unsigned long end = (unsigned long)cpu_pda(cpu)->irqstackptr;
+
+	if (rsp <= end && rsp >= end - IRQSTACKSIZE + 8)
+		regs = *(((struct pt_regs **)end) - 1);
+
+	return regs;
+}
+
+static struct pt_regs *in_exception_stack(unsigned long rsp, int cpu)
+{
+	struct tss_struct *init_tss = &__get_cpu_var(init_tss);
+	struct pt_regs *regs;
+	int i;
+
+	for (i = 0; i < N_EXCEPTION_STACKS; i++)
+		if (rsp >= init_tss[cpu].x86_tss.ist[i] &&
+		    rsp <= init_tss[cpu].x86_tss.ist[i] + EXCEPTION_STKSZ) {
+			regs = (void *) init_tss[cpu].x86_tss.ist[i] +\
+				EXCEPTION_STKSZ;
+			return regs - 1;
+		}
+
+	return NULL;
+}
+
+void kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid)
+{
+	static char intr_desc[] = "Stack at interrupt entrypoint";
+	static char exc_desc[] = "Stack at exception entrypoint";
+	struct pt_regs *stregs;
+	int cpu = raw_smp_processor_id();
+	stregs = in_interrupt_stack(regs->sp, cpu);
+	if (stregs)
+		kgdb_mem2hex(intr_desc, buffer, strlen(intr_desc));
+	else {
+		stregs = in_exception_stack(regs->sp, cpu);
+		if (stregs)
+			kgdb_mem2hex(exc_desc, buffer, strlen(exc_desc));
+	}
+}
+
+struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+	struct pt_regs *stregs;
+	int cpu = raw_smp_processor_id();
+
+	stregs = in_interrupt_stack(regs->sp, cpu);
+	if (stregs)
+		return current;
+	else {
+		stregs = in_exception_stack(regs->sp, cpu);
+		if (stregs)
+			return current;
+	}
+
+	return NULL;
+}
+
+struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	struct pt_regs *stregs;
+	int cpu = raw_smp_processor_id();
+
+	stregs = in_interrupt_stack(regs->sp, cpu);
+	if (stregs)
+		return stregs;
+	else {
+		stregs = in_exception_stack(regs->sp, cpu);
+		if (stregs)
+			return stregs;
+	}
+
+	return NULL;
+}
+#endif /* ! CONFIG_X86_32 */
+
+static inline int single_step_cont(struct pt_regs *regs,
+			struct die_args *args)
+{
+	/* single step exception from kernel space to user space so
+	 * eat the exception and continue the process
+	 */
+	printk(KERN_ERR "KGDB: trap/step from kernel to user space,"
+			" resuming...\n");
+	kgdb_arch_handle_exception(args->trapnr, args->signr,
+			args->err, "c", "", regs);
+
+	return NOTIFY_STOP;
+}
+
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd,
+		       void *ptr)
+{
+	struct die_args *args = ptr;
+	struct pt_regs *regs = args->regs;
+
+	switch (cmd) {
+	case DIE_NMI:
+		if (kgdb_active()) {
+			/* KGDB CPU roundup */
+			kgdb_nmihook(raw_smp_processor_id(), regs);
+			return NOTIFY_STOP;
+		}
+		return NOTIFY_DONE;
+	case DIE_NMI_IPI:
+		if (kgdb_active()) {
+			/* KGDB CPU roundup */
+			if (kgdb_nmihook(raw_smp_processor_id(), regs))
+				return NOTIFY_DONE;
+			return NOTIFY_STOP;
+		}
+		return NOTIFY_DONE;
+	case DIE_NMIWATCHDOG:
+		if (kgdb_active()) {
+			/* KGDB CPU roundup */
+			kgdb_nmihook(raw_smp_processor_id(), regs);
+			return NOTIFY_STOP;
+		}
+		/* Enter debugger */
+		break;
+	case DIE_DEBUG:
+		if (atomic_read(&cpu_doing_single_step) ==
+			raw_smp_processor_id() &&
+			user_mode(regs))
+			return single_step_cont(regs, args);
+		/* fall through */
+	default:
+		if (user_mode(regs))
+			return NOTIFY_DONE;
+	}
+
+	if (kgdb_handle_exception(args->trapnr, args->signr,
+		args->err, regs))
+		return NOTIFY_DONE;
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0x7fffffff,	/* we need to be notified first */
+};
+
+int kgdb_arch_init(void)
+{
+	register_die_notifier(&kgdb_notifier);
+	return 0;
+}
+
+void kgdb_arch_uninit(void)
+{
+	unregister_die_notifier(&kgdb_notifier);
+}
+
+/*
+ * Skip an int3 exception when it occurs after a breakpoint has been
+ * removed. Backtrack eip by 1 since the int3 would have caused it to
+ * increment by 1.
+ */
+
+int kgdb_skipexception(int exception, struct pt_regs *regs)
+{
+	if (exception == 3 && kgdb_isremovedbreak(regs->ip - 1)) {
+		regs->ip -= 1;
+		return 1;
+	}
+	return 0;
+}
+
+unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
+{
+	if (exception == 3)
+		return instruction_pointer(regs) - 1;
+	return instruction_pointer(regs);
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
+#ifndef CONFIG_X86_32
+	.shadowth = 1,
+#endif /* ! CONFIG_X86_32 */
+	.set_hw_breakpoint = kgdb_set_hw_break,
+	.remove_hw_breakpoint = kgdb_remove_hw_break,
+	.remove_all_hw_break = kgdb_remove_all_hw_break,
+	.correct_hw_break = kgdb_correct_hw_break,
+};
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index d1d8c34..e909d39 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -184,6 +184,7 @@ EXPORT_SYMBOL(ist_info);
 #endif
 
 extern void early_cpu_init(void);
+extern void early_trap_init(void);
 extern int root_mountflags;
 
 unsigned long saved_videomode;
@@ -700,6 +701,7 @@ void __init setup_arch(char **cmdline_p)
 	memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
 	pre_setup_arch_hook();
 	early_cpu_init();
+	early_trap_init();
 	early_ioremap_init();
 
 #ifdef CONFIG_EFI
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index c0d8208..ecebc5f 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -91,6 +91,8 @@ unsigned long saved_video_mode;
 
 int force_mwait __cpuinitdata;
 
+void early_trap_init(void);
+
 /*
  * Early DMI memory
  */
@@ -270,6 +272,8 @@ void __init setup_arch(char **cmdline_p)
 {
 	unsigned i;
 
+	early_trap_init();
+
 	printk(KERN_INFO "Command line: %s\n", boot_command_line);
 
 	ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index b22c01e..47ca425 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -919,6 +919,7 @@ void __kprobes do_debug(struct pt_regs * regs, long error_code)
 	 */
 clear_dr7:
 	set_debugreg(0, 7);
+	notify_die(DIE_DEBUG, "debug2", regs, condition, error_code, SIGTRAP);
 	return;
 
 debug_vm86:
@@ -1136,6 +1137,14 @@ asmlinkage void math_emulate(long arg)
 
 #endif /* CONFIG_MATH_EMULATION */
 
+/* Set of traps needed for early debugging. */
+void __init early_trap_init(void)
+{
+	set_intr_gate(1, &debug);
+	set_system_intr_gate(3, &int3); /* int3 can be called from all */
+	set_intr_gate(14, &page_fault);
+	load_idt(&idt_descr);
+}
 
 void __init trap_init(void)
 {
@@ -1154,10 +1163,8 @@ void __init trap_init(void)
 #endif
 
 	set_trap_gate(0,&divide_error);
-	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
-	set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
-	set_system_gate(4,&overflow);
+	set_system_gate(4, &overflow); /* int4/5 can be called from all */
 	set_trap_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
 	set_trap_gate(7,&device_not_available);
@@ -1167,7 +1174,6 @@ void __init trap_init(void)
 	set_trap_gate(11,&segment_not_present);
 	set_trap_gate(12,&stack_segment);
 	set_trap_gate(13,&general_protection);
-	set_intr_gate(14,&page_fault);
 	set_trap_gate(15,&spurious_interrupt_bug);
 	set_trap_gate(16,&coprocessor_error);
 	set_trap_gate(17,&alignment_check);
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index efc66df..00baf0d 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -600,8 +600,13 @@ void die(const char * str, struct pt_regs * regs, long err)
 
 void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 {
-	unsigned long flags = oops_begin();
+	unsigned long flags;
+
+	if (notify_die(DIE_NMIWATCHDOG, "nmi", regs, 0, 2, SIGINT)
+			== NOTIFY_STOP)
+		return;
 
+	flags = oops_begin();
 	/*
 	 * We are in trouble anyway, lets at least try
 	 * to get a message out.
@@ -1124,6 +1129,15 @@ asmlinkage void math_state_restore(void)
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
+/* Set of traps needed for early debugging. */
+void __init early_trap_init(void)
+{
+	set_intr_gate(1, &debug);
+	set_intr_gate(3, &int3);
+	set_intr_gate(14, &page_fault);
+	load_idt((const struct desc_ptr *)&idt_descr);
+}
+
 void __init trap_init(void)
 {
 	set_intr_gate(0,&divide_error);
@@ -1140,7 +1154,6 @@ void __init trap_init(void)
 	set_intr_gate(11,&segment_not_present);
 	set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
 	set_intr_gate(13,&general_protection);
-	set_intr_gate(14,&page_fault);
 	set_intr_gate(15,&spurious_interrupt_bug);
 	set_intr_gate(16,&coprocessor_error);
 	set_intr_gate(17,&alignment_check);
diff --git a/include/asm-x86/kgdb.h b/include/asm-x86/kgdb.h
new file mode 100644
index 0000000..c2803a8
--- /dev/null
+++ b/include/asm-x86/kgdb.h
@@ -0,0 +1,79 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ * Copyright (C) 2008 Wind River Systems, Inc.
+ */
+
+#include <asm-generic/kgdb.h>
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound
+ * buffers at least NUMREGBYTES*2 are needed for register packets
+ * Longer buffer is needed to list all threads
+ */
+#define BUFMAX			1024
+
+/*
+ *  Note that this register image is in a different order than
+ *  the register image that Linux produces at interrupt time.
+ *
+ *  Linux's register image is defined by struct pt_regs in ptrace.h.
+ *  Just why GDB uses a different order is a historical mystery.
+ */
+#ifdef CONFIG_X86_32
+enum regnames { _AX,	/* 0 */
+	_CX,	/* 1 */
+	_DX,	/* 2 */
+	_BX,	/* 3 */
+	_SP,	/* 4 */
+	_BP,	/* 5 */
+	_SI,	/* 6 */
+	_DI,	/* 7 */
+	_PC,	/* 8 also known as eip */
+	_PS,	/* 9 also known as eflags */
+	_CS,	/* 10 */
+	_SS,	/* 11 */
+	_DS,	/* 12 */
+	_ES,	/* 13 */
+	_FS,	/* 14 */
+	_GS		/* 15 */
+};
+#else /* ! CONFIG_X86_32 */
+enum regnames { _AX,	/* 0 */
+	_DX,	/* 1 */
+	_CX,	/* 2 */
+	_BX,	/* 3 */
+	_SI,	/* 4 */
+	_DI,	/* 5 */
+	_BP,	/* 6 */
+	_SP,	/* 7 */
+	_R8,	/* 8 */
+	_R9,	/* 9 */
+	_R10,	/* 10 */
+	_R11,	/* 11 */
+	_R12,	/* 12 */
+	_R13,	/* 13 */
+	_R14,	/* 14 */
+	_R15,	/* 15 */
+	_PC,	/* 16 */
+	_PS		/* 17 */
+};
+#endif /* CONFIG_X86_32 */
+
+/* Number of bytes for gdb registers */
+#ifdef CONFIG_X86_32
+#define NUMREGBYTES		64
+#else /* ! CONFIG_X86_32 */
+#define NUMREGBYTES		((_PS+1)*8)
+#endif /* CONFIG_X86_32 */
+
+#ifndef __ASSEMBLY__
+#define BREAKPOINT()		asm("   int $3");
+#define BREAK_INSTR_SIZE	1
+#define CACHE_FLUSH_IS_SAFE	1
+#endif				/* !__ASSEMBLY__ */
+#endif				/* _ASM_KGDB_H_ */
+#endif				/* __KERNEL__ */
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h
index 9cff02f..33851cb 100644
--- a/include/asm-x86/system.h
+++ b/include/asm-x86/system.h
@@ -61,6 +61,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	, "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
 	  "r12", "r13", "r14", "r15"
 
+extern void thread_return(void);
 /* Save restore flags to clear handle leaking NT */
 #define switch_to(prev, next, last) \
 	asm volatile(SAVE_CONTEXT						    \
@@ -75,6 +76,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	     "movq %%rax,%%rdi\n\t" 					  \
 	     "jc   ret_from_fork\n\t"					  \
 	     RESTORE_CONTEXT						  \
+	     "\n.globl __switch_to_end\n\t"			\
+	     "__switch_to_end:\n\t"				\
 	     : "=a" (last)					  	  \
 	     : [next] "S" (next), [prev] "D" (prev),			  \
 	       [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
index afa61bb..e6fb7e3 100644
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -4,7 +4,7 @@ menuconfig KGDB
 	select KGDB_ARCH_HAS_SHADOW_INFO if X86_64
 	select DEBUG_INFO
 	select FRAME_POINTER
-	depends on DEBUG_KERNEL && ADD_A_KGDB_ARCH
+	depends on DEBUG_KERNEL && (X86)
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb.  Documentation of kernel debugger is available
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 6/8] kgdb, sysrq_bugfix
  2008-02-09 13:35         ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support jason.wessel
@ 2008-02-09 13:35           ` jason.wessel
  2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
  2008-02-09 14:33           ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support Jan Kiszka
  1 sibling, 1 reply; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel, Tom Rini, Ingo Molnar, Thomas Gleixner

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

It is possible that when SysRq-G is triggered via the keyboard that we
will miss the "up" event and once KGDB lets the kernel go another
SysRq will be required to clear this, without this change.

Signed-off-by: Tom Rini <trini@kernel.crashing.org>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/char/keyboard.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 4dbd342..b79812e 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1190,6 +1190,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 		sysrq_down = 0;
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], tty);
+		sysrq_down = 0;		/* In case we miss the 'up' event. */
 		return;
 	}
 #endif
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 13:35           ` [PATCH 6/8] kgdb, sysrq_bugfix jason.wessel
@ 2008-02-09 13:35             ` jason.wessel
  2008-02-09 13:35               ` [PATCH 8/8] kgdb: kgdboc 8250 I/O module jason.wessel
                                 ` (3 more replies)
  0 siblings, 4 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jason Wessel, linux-serial, Jan Kiszka, Ingo Molnar, Thomas Gleixner

From: Jason Wessel <jason.wessel@windriver.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@vger.kernel.org
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.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@emsyssoft.com>, David Grothe <dave@gcom.com>,
+ * Scott Foehner <sfoehner@engr.sgi.com>, George Anzinger <george@mvista.com>,
+ * Robert Walsh <rjwalsh@durables.org>, wangdi <wangdi@clusterfs.com>,
+ * San Mehat, Tom Rini <trini@mvista.com>,
+ * Jason Wessel <jason.wessel@windriver.com>
+ *
+ * Refactoring and cleanup for initial merge:
+ * 2008 (c) Jan Kiszka <jan.kiszka@web.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


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 8/8] kgdb: kgdboc 8250 I/O module
  2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
@ 2008-02-09 13:35               ` jason.wessel
  2008-02-09 14:53               ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver Jan Kiszka
                                 ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: jason.wessel @ 2008-02-09 13:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jason Wessel, Jan Kiszka, Ingo Molnar, Thomas Gleixner

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

Add a SERIAL_POLL API to the serial core for use with kgdboc (KGDB
over the console), the gdb serial adapter which can multiplex with a
console port.

The kgdboc module can be extended later to support all sorts of
different console types provided that there are hooks in the console
driver to allow for polled mode access while the system is halted.

If you build kgdboc into the kernel you could expect to use the
following kernel boot arguments assuming your console is ttyS0:
"kgdbwait kgdboc=ttyS0"

In case you do try this and don't end up attaching gdb to the console,
you will want to type the debugger detach command manually (NOTE: it
will not echo because the console is in polled debug mode).

$D#44+

kgdboc can also be loaded at runtime as a kernel module.  The easiest
way to use kgdboc is to use it with a proxy that splits the traffic to
gdb and to your favorite terminal application.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 Documentation/DocBook/kgdb.tmpl     |    7 ++
 Documentation/kernel-parameters.txt |    5 +
 drivers/char/tty_io.c               |    8 ++
 drivers/serial/8250.c               |   61 ++++++++++++
 drivers/serial/Kconfig              |    3 +
 drivers/serial/Makefile             |    1 +
 drivers/serial/kgdboc.c             |  182 +++++++++++++++++++++++++++++++++++
 drivers/serial/serial_core.c        |   71 +++++++++++++-
 include/linux/serial_core.h         |    4 +
 include/linux/tty_driver.h          |   11 ++
 lib/Kconfig.kgdb                    |    9 ++
 11 files changed, 361 insertions(+), 1 deletions(-)
 create mode 100644 drivers/serial/kgdboc.c

diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 111a2a0..b334b44 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -136,6 +136,13 @@
     <constant>kgdb8250=ttyS0,115200</constant>
     </para>
     <para>
+    To configure the <symbol>CONFIG_KGDBOC</symbol> driver, just pass in
+    <constant>kgdboc=&lt;tty-device&gt;</constant>.  It will try to connect
+    to gdb over the given serial console.  Note that KGDBOC does not support
+    interrupting the target via the gdb remote protocol.  Instead you will
+    need to issue sysrq-g via the console or locally on the target.
+    </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/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a4fc7fc..fa9c774 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -930,6 +930,11 @@ and is between 256 and 4096 characters. It is defined in the file
 	kstack=N	[X86-32,X86-64] Print N words from the kernel stack
 			in oops dumps.
 
+	kgdboc=		[HW] gdbserial console driver to multiple gdb serial and
+			the console.  Requires the uart driver that supports
+			CONFIG_SERIAL_POLL
+			Format: <serial_device>[,baud]
+
 	l2cr=		[PPC]
 
 	lapic		[X86-32,APIC] Enable the local APIC even if BIOS
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 613ec81..e169008 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -129,6 +129,9 @@ EXPORT_SYMBOL(tty_std_termios);
    into this file */
 
 LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
+#ifdef CONFIG_SERIAL_POLL
+EXPORT_SYMBOL_GPL(tty_drivers);
+#endif
 
 /* Mutex to protect creating and releasing a tty. This is shared with
    vt.c for deeply disgusting hack reasons */
@@ -3850,6 +3853,11 @@ void tty_set_operations(struct tty_driver *driver,
 	driver->write_proc = op->write_proc;
 	driver->tiocmget = op->tiocmget;
 	driver->tiocmset = op->tiocmset;
+#ifdef CONFIG_SERIAL_POLL
+	driver->poll_init = op->poll_init;
+	driver->poll_get_char = op->poll_get_char;
+	driver->poll_put_char = op->poll_put_char;
+#endif
 }
 
 
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 2b37370..f8eebaa 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1740,6 +1740,63 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
 	}
 }
 
+#ifdef CONFIG_SERIAL_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial8250_get_poll_char(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned char lsr = serial_inp(up, UART_LSR);
+
+	while (!(lsr & UART_LSR_DR))
+		lsr = serial_inp(up, UART_LSR);
+
+	return serial_inp(up, UART_RX);
+}
+
+
+static void serial8250_put_poll_char(struct uart_port *port,
+			 unsigned char c)
+{
+	unsigned int ier;
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+	/*
+	 *	First save the IER then disable the interrupts
+	 */
+	ier = serial_in(up, UART_IER);
+#ifdef UART_CAP_UUE
+	if (up->capabilities & UART_CAP_UUE)
+#else
+	if (up->port.type == PORT_XSCALE)
+#endif
+		serial_out(up, UART_IER, UART_IER_UUE);
+	else
+		serial_out(up, UART_IER, 0);
+
+	wait_for_xmitr(up, BOTH_EMPTY);
+	/*
+	 *	Send the character out.
+	 *	If a LF, also do CR...
+	 */
+	serial_out(up, UART_TX, c);
+	if (c == 10) {
+		wait_for_xmitr(up, BOTH_EMPTY);
+		serial_out(up, UART_TX, 13);
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the IER
+	 */
+	wait_for_xmitr(up, BOTH_EMPTY);
+	serial_out(up, UART_IER, ier);
+}
+
+#endif /* CONFIG_SERIAL_POLL */
+
 static int serial8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -2386,6 +2443,10 @@ static struct uart_ops serial8250_pops = {
 	.request_port	= serial8250_request_port,
 	.config_port	= serial8250_config_port,
 	.verify_port	= serial8250_verify_port,
+#ifdef CONFIG_SERIAL_POLL
+	.poll_get_char = serial8250_get_poll_char,
+	.poll_put_char = serial8250_put_poll_char,
+#endif
 };
 
 static struct uart_8250_port serial8250_ports[UART_NR];
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 7ef9145..f5b691a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -961,6 +961,9 @@ config SERIAL_CORE
 config SERIAL_CORE_CONSOLE
 	bool
 
+config SERIAL_POLL
+	bool
+
 config SERIAL_68328
 	bool "68328 serial support"
 	depends on M68328 || M68EZ328 || M68VZ328
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 6ee1b36..82778d7 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -66,5 +66,6 @@ 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_KGDBOC) += kgdboc.o
 obj-$(CONFIG_KGDB_8250) += 8250_kgdb.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
new file mode 100644
index 0000000..7848fca
--- /dev/null
+++ b/drivers/serial/kgdboc.c
@@ -0,0 +1,182 @@
+/*
+ * drivers/serial/kgdboc.c
+ *
+ * Based on the same principle as kgdboe using the NETPOLL api, this
+ * driver uses a serial polling api to implement a gdb serial inteface
+ * which is multiplexed on a console port.
+ *
+ * Maintainer: Jason Wessel <jason.wessel@windriver.com>
+ *
+ * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
+ *
+ * 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/kgdb.h>
+#include <linux/tty.h>
+#include <linux/ctype.h>
+
+#define MAX_KGDBOC_CONFIG_STR 40
+
+static struct kgdb_io kgdboc_io_ops;
+
+/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
+static int configured = -1;
+
+MODULE_DESCRIPTION("KGDB Console TTY Driver");
+MODULE_LICENSE("GPL");
+static char config[MAX_KGDBOC_CONFIG_STR];
+static struct kparam_string kps = {
+	.string = config,
+	.maxlen = MAX_KGDBOC_CONFIG_STR,
+};
+
+static struct tty_driver *kgdb_tty_driver;
+static int kgdb_tty_line;
+
+static int kgdboc_option_setup(char *opt)
+{
+	if (strlen(opt) > MAX_KGDBOC_CONFIG_STR) {
+		printk(KERN_ERR "kgdboc: config string too long\n");
+		return -ENOSPC;
+	}
+	strcpy(config, opt);
+	return 0;
+}
+__setup("kgdboc=", kgdboc_option_setup);
+
+static int configure_kgdboc(void)
+{
+	struct tty_driver *p;
+	int err;
+	char *str;
+	int tty_line = 0;
+
+	err = kgdboc_option_setup(config);
+	if (err || !strlen(config) || isspace(config[0]))
+		goto noconfig;
+
+	err = -ENODEV;
+
+	/* Search through the tty devices to look for a match */
+	/* FIXME: API violation, at least missing lock protection */
+	list_for_each_entry(p, &tty_drivers, tty_drivers) {
+		if (p->type != TTY_DRIVER_TYPE_SERIAL ||
+		    strncmp(config, p->name, strlen(p->name)) != 0)
+			continue;
+		str = config + strlen(p->name);
+		tty_line = simple_strtoul(str, &str, 10);
+		if (*str == ',')
+			str++;
+		if (*str == '\0')
+			str = 0;
+
+		if (tty_line >= 0 && tty_line <= p->num &&
+			p->poll_init && !p->poll_init(p, tty_line, str)) {
+			kgdb_tty_driver = p;
+			kgdb_tty_line = tty_line;
+			err = 0;
+			break;
+		}
+	}
+	if (err)
+		goto noconfig;
+
+	err = kgdb_register_io_module(&kgdboc_io_ops);
+	if (err)
+		goto noconfig;
+
+	configured = 1;
+	return 0;
+
+noconfig:
+	config[0] = 0;
+	configured = 0;
+	return err;
+
+}
+
+static int init_kgdboc(void)
+{
+	/* Already configured? */
+	if (configured == 1)
+		return 0;
+
+	return configure_kgdboc();
+}
+
+static void cleanup_kgdboc(void)
+{
+	if (configured == 1)
+		kgdb_unregister_io_module(&kgdboc_io_ops);
+}
+
+static int kgdboc_get_char(void)
+{
+	return kgdb_tty_driver->poll_get_char(kgdb_tty_driver,
+			kgdb_tty_line);
+}
+
+static void kgdboc_put_char(u8 chr)
+{
+	kgdb_tty_driver->poll_put_char(kgdb_tty_driver,
+			kgdb_tty_line, chr);
+}
+
+static int param_set_kgdboc_var(const char *kmessage,
+		struct kernel_param *kp)
+{
+	if (strlen(kmessage) >= MAX_KGDBOC_CONFIG_STR) {
+		printk(KERN_ERR "kgdboc: config string too long\n");
+		return -ENOSPC;
+	}
+
+	/* Only copy in the string if the init function has not run yet */
+	if (configured < 0) {
+		strcpy(config, kmessage);
+		return 0;
+	}
+
+	if (kgdb_connected) {
+		printk(KERN_ERR "kgdboc: Cannot reconfigure while KGDB is "
+				"connected.\n");
+		return -EBUSY;
+	}
+
+	strcpy(config, kmessage);
+
+	if (configured == 1)
+		cleanup_kgdboc();
+
+	/* Go and configure with the new params. */
+	return configure_kgdboc();
+}
+
+static void kgdboc_pre_exp_handler(void)
+{
+	/* Increment the module count when the debugger is active */
+	if (!kgdb_connected)
+		try_module_get(THIS_MODULE);
+}
+
+static void kgdboc_post_exp_handler(void)
+{
+	/* decrement the module count when the debugger detaches */
+	if (!kgdb_connected)
+		module_put(THIS_MODULE);
+}
+
+static struct kgdb_io kgdboc_io_ops = {
+	.name = "kgdboc",
+	.read_char = kgdboc_get_char,
+	.write_char = kgdboc_put_char,
+	.pre_exception = kgdboc_pre_exp_handler,
+	.post_exception = kgdboc_post_exp_handler,
+};
+
+module_init(init_kgdboc);
+module_exit(cleanup_kgdboc);
+module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index d333fc4..fdcbd42 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1837,7 +1837,11 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
  *	options.  The format of the string is <baud><parity><bits><flow>,
  *	eg: 115200n8r
  */
+#ifdef CONFIG_SERIAL_POLL
+void
+#else
 void __init
+#endif
 uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
 {
 	char *s = options;
@@ -1882,7 +1886,11 @@ static const struct baud_rates baud_rates[] = {
  *	@bits: number of data bits
  *	@flow: flow control character - 'r' (rts)
  */
+#ifdef CONFIG_SERIAL_POLL
+int
+#else
 int __init
+#endif
 uart_set_options(struct uart_port *port, struct console *co,
 		 int baud, int parity, int bits, int flow)
 {
@@ -1934,7 +1942,8 @@ uart_set_options(struct uart_port *port, struct console *co,
 	port->mctrl |= TIOCM_DTR;
 
 	port->ops->set_termios(port, &termios, &dummy);
-	co->cflag = termios.c_cflag;
+	if (co)
+		co->cflag = termios.c_cflag;
 
 	return 0;
 }
@@ -2194,6 +2203,61 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 	}
 }
 
+#ifdef CONFIG_SERIAL_POLL
+static int uart_poll_init(struct tty_driver *driver,
+		int line, char *options)
+{
+	struct uart_driver *drv = driver->driver_state;
+	struct uart_state *state = drv->state + line;
+	struct uart_port *port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (!state || !state->port)
+		return -1;
+
+	port = state->port;
+	if (!(port->ops->poll_get_char &&
+		  port->ops->poll_put_char))
+		return -1;
+
+	if (options) {
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+		return(uart_set_options(port, 0, baud, parity, bits, flow));
+	}
+
+	return 0;
+}
+static int uart_poll_get_char(struct tty_driver *driver, int line)
+{
+	struct uart_driver *drv = driver->driver_state;
+	struct uart_state *state = drv->state + line;
+	struct uart_port *port;
+
+	if (!state || !state->port)
+		return -1;
+
+	port = state->port;
+	return port->ops->poll_get_char(port);
+}
+
+static void uart_poll_put_char(struct tty_driver *driver,
+		int line, char ch)
+{
+	struct uart_driver *drv = driver->driver_state;
+	struct uart_state *state = drv->state + line;
+	struct uart_port *port;
+
+	if (!state || !state->port)
+		return;
+
+	port = state->port;
+	port->ops->poll_put_char(port, ch);
+}
+#endif
+
 static const struct tty_operations uart_ops = {
 	.open		= uart_open,
 	.close		= uart_close,
@@ -2218,6 +2282,11 @@ static const struct tty_operations uart_ops = {
 #endif
 	.tiocmget	= uart_tiocmget,
 	.tiocmset	= uart_tiocmset,
+#ifdef CONFIG_SERIAL_POLL
+	.poll_init	= uart_poll_init,
+	.poll_get_char	= uart_poll_get_char,
+	.poll_put_char	= uart_poll_put_char,
+#endif
 };
 
 /**
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 1a0b6cf..6e70866 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -211,6 +211,10 @@ struct uart_ops {
 	void		(*config_port)(struct uart_port *, int);
 	int		(*verify_port)(struct uart_port *, struct serial_struct *);
 	int		(*ioctl)(struct uart_port *, unsigned int, unsigned long);
+#ifdef CONFIG_SERIAL_POLL
+	void	(*poll_put_char)(struct uart_port *, unsigned char);
+	int		(*poll_get_char)(struct uart_port *);
+#endif
 };
 
 #define UART_CONFIG_TYPE	(1 << 0)
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 85c95cd..e4e590d 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -125,6 +125,7 @@
 #include <linux/cdev.h>
 
 struct tty_struct;
+struct tty_driver;
 
 struct tty_operations {
 	int  (*open)(struct tty_struct * tty, struct file * filp);
@@ -157,6 +158,11 @@ struct tty_operations {
 	int (*tiocmget)(struct tty_struct *tty, struct file *file);
 	int (*tiocmset)(struct tty_struct *tty, struct file *file,
 			unsigned int set, unsigned int clear);
+#ifdef CONFIG_SERIAL_POLL
+	int (*poll_init)(struct tty_driver *driver, int line, char *options);
+	int (*poll_get_char)(struct tty_driver *driver, int line);
+	void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
+#endif
 };
 
 struct tty_driver {
@@ -220,6 +226,11 @@ struct tty_driver {
 	int (*tiocmget)(struct tty_struct *tty, struct file *file);
 	int (*tiocmset)(struct tty_struct *tty, struct file *file,
 			unsigned int set, unsigned int clear);
+#ifdef CONFIG_SERIAL_POLL
+	int (*poll_init)(struct tty_driver *driver, int line, char *options);
+	int (*poll_get_char)(struct tty_driver *driver, int line);
+	void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
+#endif
 
 	struct list_head tty_drivers;
 };
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
index 3d5c2f8..d81b502 100644
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -51,3 +51,12 @@ config KGDB_8250
 	  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.
+
+config KGDBOC
+	tristate "Shared serial console and kgdb port"
+	depends on KGDB
+	select SERIAL_POLL
+	select MAGIC_SYSRQ
+	help
+	  Share a serial console with kgdb.  The sysrq-g must be used
+	  to break in initially.
-- 
1.5.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
  2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
@ 2008-02-09 14:27   ` Jan Kiszka
  2008-02-09 15:29   ` Sam Ravnborg
  2008-02-09 17:27   ` Christoph Hellwig
  3 siblings, 0 replies; 24+ messages in thread
From: Jan Kiszka @ 2008-02-09 14:27 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2584 bytes --]

jason.wessel@windriver.com wrote:
> --- /dev/null
> +++ b/include/asm-generic/kgdb.h
> @@ -0,0 +1,105 @@
> +/*
> + * include/asm-generic/kgdb.h
> + *
> + * This provides the assembly level information so that KGDB can provide
> + * a GDB that has been patched with enough information to know to stop
> + * trying to unwind the function.
> + *
> + * Author: Tom Rini <trini@kernel.crashing.org>
> + *
> + * 2005 (c) MontaVista Software, Inc.
> + * 2006 (c) Embedded Alley Solutions, Inc.
> + *
> + * 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.
> + */
> +
> +#ifndef __ASM_GENERIC_KGDB_H__
> +#define __ASM_GENERIC_KGDB_H__
> +
> +struct pt_regs;
> +
> +#ifdef CONFIG_X86

Hmm, I just realized that I didn't really looked at the arch interface
in details yet. Now it appears a bit inconsistent to me in its way to
tell "this arch supports that". Something in include/asm-generic that
starts with #ifdef CONFIG_X86 looks ugly, to begin with.

...
> +#ifdef CONFIG_KGDB_ARCH_HAS_SHADOW_INFO

Then we have this KGDB_ARCH_HAS thing here, the second way to control
arch-dependent stuff.

...
> --- /dev/null
> +++ b/include/linux/kgdb.h
...
> +struct kgdb_arch {
> +	unsigned char		gdb_bpt_instr[BREAK_INSTR_SIZE];
> +	unsigned long		flags;
> +	unsigned		shadowth;
> +
> +	int	(*set_breakpoint)(unsigned long, char *);
> +	int	(*remove_breakpoint)(unsigned long, char *);
> +	int	(*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
> +	int	(*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
> +	void	(*remove_all_hw_break)(void);
> +	void	(*correct_hw_break)(void);
> +};

And this is the third way. Can we consolidate this?

...
> --- /dev/null
> +++ b/kernel/kgdb.c
...
> +/*
> + * Convert the memory pointed to by mem into hex, placing result in buf.
> + * Return a pointer to the last char put in buf (null). May return an error.
> + */
> +char *kgdb_mem2hex(char *mem, char *buf, int count)

As Linus remarked, still pointer-based return values while only the
error code is used by the callers (there are more of such cases in the
core).

...
> --- a/kernel/softlockup.c
> +++ b/kernel/softlockup.c
...
> @@ -52,7 +55,6 @@ static unsigned long get_timestamp(int this_cpu)
>  void touch_softlockup_watchdog(void)
>  {
>  	int this_cpu = raw_smp_processor_id();
> -

Probably some relic from older changes which should be killed.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 254 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support
  2008-02-09 13:35         ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support jason.wessel
  2008-02-09 13:35           ` [PATCH 6/8] kgdb, sysrq_bugfix jason.wessel
@ 2008-02-09 14:33           ` Jan Kiszka
  1 sibling, 0 replies; 24+ messages in thread
From: Jan Kiszka @ 2008-02-09 14:33 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, Jan Kiszka, Ingo Molnar, Thomas Gleixner

jason.wessel@windriver.com wrote:
> --- /dev/null
> +++ b/include/asm-x86/kgdb.h
> @@ -0,0 +1,79 @@
> +#ifdef __KERNEL__
> +#ifndef _ASM_KGDB_H_
> +#define _ASM_KGDB_H_
> +
> +/*
> + * Copyright (C) 2001-2004 Amit S. Kale
> + * Copyright (C) 2008 Wind River Systems, Inc.
> + */
> +
> +#include <asm-generic/kgdb.h>
> +
> +/*
> + * BUFMAX defines the maximum number of characters in inbound/outbound
> + * buffers at least NUMREGBYTES*2 are needed for register packets
> + * Longer buffer is needed to list all threads
> + */
> +#define BUFMAX			1024
> +
> +/*
> + *  Note that this register image is in a different order than
> + *  the register image that Linux produces at interrupt time.
> + *
> + *  Linux's register image is defined by struct pt_regs in ptrace.h.
> + *  Just why GDB uses a different order is a historical mystery.
> + */
> +#ifdef CONFIG_X86_32
> +enum regnames { _AX,	/* 0 */
> +	_CX,	/* 1 */
> +	_DX,	/* 2 */
> +	_BX,	/* 3 */
> +	_SP,	/* 4 */
> +	_BP,	/* 5 */
> +	_SI,	/* 6 */
> +	_DI,	/* 7 */
> +	_PC,	/* 8 also known as eip */
> +	_PS,	/* 9 also known as eflags */
> +	_CS,	/* 10 */
> +	_SS,	/* 11 */
> +	_DS,	/* 12 */
> +	_ES,	/* 13 */
> +	_FS,	/* 14 */
> +	_GS		/* 15 */
> +};
> +#else /* ! CONFIG_X86_32 */
> +enum regnames { _AX,	/* 0 */
> +	_DX,	/* 1 */
> +	_CX,	/* 2 */
> +	_BX,	/* 3 */
> +	_SI,	/* 4 */
> +	_DI,	/* 5 */
> +	_BP,	/* 6 */
> +	_SP,	/* 7 */
> +	_R8,	/* 8 */
> +	_R9,	/* 9 */
> +	_R10,	/* 10 */
> +	_R11,	/* 11 */
> +	_R12,	/* 12 */
> +	_R13,	/* 13 */
> +	_R14,	/* 14 */
> +	_R15,	/* 15 */
> +	_PC,	/* 16 */
> +	_PS		/* 17 */
> +};
> +#endif /* CONFIG_X86_32 */
> +
> +/* Number of bytes for gdb registers */
> +#ifdef CONFIG_X86_32
> +#define NUMREGBYTES		64
> +#else /* ! CONFIG_X86_32 */
> +#define NUMREGBYTES		((_PS+1)*8)
> +#endif /* CONFIG_X86_32 */
> +
> +#ifndef __ASSEMBLY__
> +#define BREAKPOINT()		asm("   int $3");
> +#define BREAK_INSTR_SIZE	1
> +#define CACHE_FLUSH_IS_SAFE	1
> +#endif				/* !__ASSEMBLY__ */
> +#endif				/* _ASM_KGDB_H_ */
> +#endif				/* __KERNEL__ */

Please fold into the next version:

diff --git a/include/asm-x86/kgdb.h b/include/asm-x86/kgdb.h
index c2803a8..0ba150b 100644
--- a/include/asm-x86/kgdb.h
+++ b/include/asm-x86/kgdb.h
@@ -1,4 +1,3 @@
-#ifdef __KERNEL__
 #ifndef _ASM_KGDB_H_
 #define _ASM_KGDB_H_
 
@@ -70,10 +69,7 @@ enum regnames { _AX,	/* 0 */
 #define NUMREGBYTES		((_PS+1)*8)
 #endif /* CONFIG_X86_32 */
 
-#ifndef __ASSEMBLY__
 #define BREAKPOINT()		asm("   int $3");
 #define BREAK_INSTR_SIZE	1
 #define CACHE_FLUSH_IS_SAFE	1
-#endif				/* !__ASSEMBLY__ */
-#endif				/* _ASM_KGDB_H_ */
-#endif				/* __KERNEL__ */
+#endif /* _ASM_KGDB_H_ */


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
  2008-02-09 13:35               ` [PATCH 8/8] kgdb: kgdboc 8250 I/O module jason.wessel
@ 2008-02-09 14:53               ` Jan Kiszka
  2008-02-09 18:45                 ` Jason Wessel
  2008-02-09 16:40               ` Jan Kiszka
  2008-02-10 15:26               ` Pavel Machek
  3 siblings, 1 reply; 24+ messages in thread
From: Jan Kiszka @ 2008-02-09 14:53 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, linux-serial, Ingo Molnar, Thomas Gleixner

jason.wessel@windriver.com wrote:
> From: Jason Wessel <jason.wessel@windriver.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@vger.kernel.org
> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
> Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
> Signed-off-by: Ingo Molnar <mingo@elte.hu>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.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

There are a few things I missed in my last cleanup round, please fold
them in, they reduce the changes outside kgdb. (I bet that membase
dumping was related to mmio vs. mmap configuration, right?)

--- linux-2.6-kgdb.orig/drivers/serial/Kconfig
+++ linux-2.6-kgdb/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 || KGDB_8250
+	depends on SERIAL_8250
 	default "4"
 	help
 	  Set this to the number of serial ports you want the driver
--- linux-2.6-kgdb.orig/drivers/serial/serial_core.c
+++ linux-2.6-kgdb/drivers/serial/serial_core.c
@@ -1685,9 +1685,6 @@ static int uart_line_info(char *buf, str
 			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");
@@ -2130,9 +2127,7 @@ uart_report_port(struct uart_driver *drv
 	case UPIO_TSI:
 	case UPIO_DWAPB:
 		snprintf(address, sizeof(address),
-			 "MMIO 0x%llx mem 0x%p",
-			 (unsigned long long)port->mapbase,
-			 port->membase);
+			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
 		break;
 	default:
 		strlcpy(address, "*unknown*", sizeof(address));
--- linux-2.6-kgdb.orig/include/linux/serial_8250.h
+++ linux-2.6-kgdb/include/linux/serial_8250.h
@@ -58,7 +58,6 @@ 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);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
  2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
  2008-02-09 14:27   ` [PATCH 1/8] kgdb: core API and gdb protocol handler Jan Kiszka
@ 2008-02-09 15:29   ` Sam Ravnborg
  2008-02-09 17:27   ` Christoph Hellwig
  3 siblings, 0 replies; 24+ messages in thread
From: Sam Ravnborg @ 2008-02-09 15:29 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel

Hi Jason.

> --- /dev/null
> +++ b/kernel/kgdb.c
> +
> +struct debuggerinfo_struct {
> +	void			*debuggerinfo;
> +	struct task_struct	*task;
> +} kgdb_info[NR_CPUS];
static?

> +
> +/* Is a host GDB connected to us? */
> +int				kgdb_connected;
> +EXPORT_SYMBOL_GPL(kgdb_connected);
Drop additional spaces.
Add kernel-doc comments explaining the usage.

> +/* All the KGDB handlers are installed */
> +int				kgdb_io_module_registered;
static? drop spaces.

> +
> +/* Guard for recursive entry */
> +static int			exception_level;
drop spaces. In more places below - but they are obvious.

> +struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS] = {
> +	[0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED }
> +};
static?

> +
> +extern int pid_max;

extern must be moved to a .h file.

> +atomic_t			kgdb_setting_breakpoint;
static?
Many more variables are static candidates. I will not repeat it.
Did you run this through sparse?

> +#ifdef __BIG_ENDIAN
> +		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_s & 0xf];
> +#else
> +		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_s & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
> +#endif
small helper function?

> +	} else if ((count == 4) && (((long)mem & 3) == 0)) {
> +		u32 tmp_l;
> +		if (kgdb_mem_cpy(&tmp_l, mem, count))
> +			return ERR_PTR(-EINVAL);
> +
> +		mem += 4;
> +#ifdef __BIG_ENDIAN
> +		*buf++ = hexchars[(tmp_l >> 28) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 24) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 20) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 16) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 8) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_l & 0xf];
> +#else
> +		*buf++ = hexchars[(tmp_l >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_l & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 8) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 20) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 16) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 28) & 0xf];
> +		*buf++ = hexchars[(tmp_l >> 24) & 0xf];
> +#endif
that could be used here too.
And again below.

> + * Convert the hex array pointed to by buf into binary to be placed in mem.
> + * Return a pointer to the character AFTER the last byte written.
> + * May return an error.
> + */
> +char *kgdb_hex2mem(char *buf, char *mem, int count)
> +{
> +	if ((count == 2) && (((long)mem & 1) == 0)) {
> +		u16 tmp_s = 0;
> +
> +#ifdef __BIG_ENDIAN
> +		tmp_s |= hex(*buf++) << 12;
> +		tmp_s |= hex(*buf++) << 8;
> +		tmp_s |= hex(*buf++) << 4;
> +		tmp_s |= hex(*buf++);
> +#else
> +		tmp_s |= hex(*buf++) << 4;
> +		tmp_s |= hex(*buf++);
> +		tmp_s |= hex(*buf++) << 12;
> +		tmp_s |= hex(*buf++) << 8;
> +#endif
small helper function again.

> +int kgdb_isremovedbreak(unsigned long addr)
> +{
> +	int i;
> +
> +	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
> +		if ((kgdb_break[i].state == BP_REMOVED) &&
> +					(kgdb_break[i].bpt_addr == addr))
> +			return 1;
> +	}
> +	return 0;
> +}
static?

> +
> +int remove_all_break(void)
> +{
> +	unsigned long addr;
> +	int error;
> +	int i;
> +
> +	/* Clear memory breakpoints. */
> +	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
> +		if (kgdb_break[i].state != BP_SET)
> +			continue;
> +		addr = kgdb_break[i].bpt_addr;
> +		error = kgdb_arch_remove_breakpoint(addr,
> +				kgdb_break[i].saved_instr);
> +		if (error)
> +			return error;
> +		kgdb_break[i].state = BP_REMOVED;
> +	}
> +
> +	/* Clear hardware breakpoints. */
> +	if (arch_kgdb_ops.remove_all_hw_break)
> +		arch_kgdb_ops.remove_all_hw_break();
> +
> +	return 0;
> +}
static?

> +/*
> + * Return true if there is a valid kgdb I/O module.  Also if no
> + * debugger is attached a message can be printed to the console about
> + * waiting for the debugger to attach.
> + *
> + * The print_wait argument is only to be true when called from inside
> + * the core kgdb_handle_exception, because it will wait for the
> + * debugger to attach.
> + */
> +int kgdb_io_ready(int print_wait)
> +{
> +	if (!kgdb_io_ops)
> +		return 0;
> +	if (kgdb_connected)
> +		return 1;
> +	if (atomic_read(&kgdb_setting_breakpoint))
> +		return 1;
> +	if (print_wait)
> +		printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
> +	return 1;
> +}
static?
Please review the rest of the code-base for static candidates.

> new file mode 100644
> index 0000000..afa61bb
> --- /dev/null
> +++ b/lib/Kconfig.kgdb
> @@ -0,0 +1,32 @@
> +
> +menuconfig KGDB
> +	bool "KGDB: kernel debugging with remote gdb"
> +	select KGDB_ARCH_HAS_SHADOW_INFO if X86_64
> +	select DEBUG_INFO
> +	select FRAME_POINTER
> +	depends on DEBUG_KERNEL && ADD_A_KGDB_ARCH

Replace ADD_A_...
with
HAVE_KGDB

and then let arch do:
	select HAVE_KGDB if they support KGDB

See Documentation/kbuild/kconfig-language.txt

	Sam

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
  2008-02-09 13:35               ` [PATCH 8/8] kgdb: kgdboc 8250 I/O module jason.wessel
  2008-02-09 14:53               ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver Jan Kiszka
@ 2008-02-09 16:40               ` Jan Kiszka
  2008-02-09 18:41                 ` Jason Wessel
  2008-02-10 15:26               ` Pavel Machek
  3 siblings, 1 reply; 24+ messages in thread
From: Jan Kiszka @ 2008-02-09 16:40 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, linux-serial, Ingo Molnar, Thomas Gleixner

jason.wessel@windriver.com wrote:
> @@ -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);

Jason, thinking about this hunk again, it appears broken to me. If we
needed it for 8250_kgdb, we would also need it without
CONFIG_KGDB_CONSOLE. However, powering on the UART with a special dance
after we took over with 8250_kgdb is a job that has to be done _there_,
not by this hook here. So let's drop the whole serial_core.c hunk from
this patch.

Jan

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/8] pid, kgdb: add pid_max prototype
  2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
  2008-02-09 13:35     ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB jason.wessel
@ 2008-02-09 17:10     ` Christoph Hellwig
  1 sibling, 0 replies; 24+ messages in thread
From: Christoph Hellwig @ 2008-02-09 17:10 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, Ingo Molnar, Thomas Gleixner

On Sat, Feb 09, 2008 at 07:35:08AM -0600, jason.wessel@windriver.com wrote:
> From: Ingo Molnar <mingo@elte.hu>
> 
> add pid_max prototype - now used by sysctl and kgdb as well.

extern should never be in .c files, so this should be submitted now,
even independent of kgdb.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB
  2008-02-09 13:35     ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB jason.wessel
  2008-02-09 13:35       ` [PATCH 4/8] kgdb: COPTIMIZE flag jason.wessel
@ 2008-02-09 17:15       ` Christoph Hellwig
  1 sibling, 0 replies; 24+ messages in thread
From: Christoph Hellwig @ 2008-02-09 17:15 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, Ingo Molnar, Thomas Gleixner

On Sat, Feb 09, 2008 at 07:35:09AM -0600, jason.wessel@windriver.com wrote:
> From: Jason Wessel <jason.wessel@windriver.com>
> 
> With more information in the kernel, gdb can be modified in such a way
> as to automatically read the kernel module section information and
> allow for easy kernel module debugging.
> 
> In gdb the solib-search-path must contain the location of any module
> to be debugged.  When a module is loaded GDB acts like a shared
> library has been loaded and will collect the information about the
> memory location so the kernel module can be debugged or inspected.
> 
> Even when not using kgdb+gdb, it is quite useful for a
> debugger+ICE/jtag to have the module section information.

This patches doesn't match the description and seems quite odd in
various ways:

> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -342,13 +342,16 @@ struct module
>  	unsigned long num_symtab;
>  	char *strtab;
>  
> -	/* Section attributes */
> -	struct module_sect_attrs *sect_attrs;
> -
>  	/* Notes attributes */
>  	struct module_notes_attrs *notes_attrs;
>  #endif
>  
> +#if defined(CONFIG_KALLSYMS) || defined(CONFIG_KGDB)
> +	/* Section attributes */
> +	struct module_sect_attrs *sect_attrs;
> +#endif

So here we make a member of struct module conditional.  Fine if
that saves memory for non-debug configs, but that's not
what the description mentions.  Also is there any reason why
you'd want to build KGDB without KALLSYMS?

> diff --git a/kernel/module.c b/kernel/module.c
> index 4202da9..4a94d1a 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -602,6 +602,9 @@ static void module_unload_free(struct module *mod)
>  			}
>  		}
>  	}
> +	blocking_notifier_call_chain(&module_notify_list,
> +				MODULE_STATE_GOING,
> +				mod);

this adds a notifier for a module beeing unloaded.  This could vaguely
be related to what's in the description at least..

> +#if defined(CONFIG_KALLSYMS) || defined(CONFIG_KGDB)
>  #ifdef CONFIG_KALLSYMS
>  static ssize_t module_sect_show(struct module_attribute *mattr,
>  				struct module *mod, char *buf)
> @@ -1000,6 +1004,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
>  		container_of(mattr, struct module_sect_attr, mattr);
>  	return sprintf(buf, "0x%lx\n", sattr->address);
>  }
> +#endif /* CONFIG_KALLSYMS */

Now you add a CONFIG_KALLSYMS || KGDB ifdef around an CONFIG_KALLSYMS
block that you shorten at the same time.  If you really want to allow
kgdb without kallsyms the KALLSYMS should be left for this function and
the KALLSYMS || KGDB move below it.  But with this ifdef mess I can
only repeat that you should simply make kallsysm mandatory for kgdb.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 4/8] kgdb: COPTIMIZE flag
  2008-02-09 13:35       ` [PATCH 4/8] kgdb: COPTIMIZE flag jason.wessel
  2008-02-09 13:35         ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support jason.wessel
@ 2008-02-09 17:16         ` Christoph Hellwig
  1 sibling, 0 replies; 24+ messages in thread
From: Christoph Hellwig @ 2008-02-09 17:16 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel, Ingo Molnar, Thomas Gleixner

On Sat, Feb 09, 2008 at 07:35:10AM -0600, jason.wessel@windriver.com wrote:
> From: Jason Wessel <jason.wessel@windriver.com>
> 
> This patch adds in the ability to unoptimize a single kernel module to
> make source stepping more linear and not optimize out variables that
> the developer might like to inspect.  It used with adding
> COPTIMIZE=-O0 to the build line when doing something like a single
> kernel module only build.  Or you could use it to override the default
> optimization level entirely.

This seems a bit unrelated to kgdb, but fine to me in general.  Please
run it past Sam, the kbuild maintainer.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
                     ` (2 preceding siblings ...)
  2008-02-09 15:29   ` Sam Ravnborg
@ 2008-02-09 17:27   ` Christoph Hellwig
  2008-02-09 19:46     ` Ray Lee
  3 siblings, 1 reply; 24+ messages in thread
From: Christoph Hellwig @ 2008-02-09 17:27 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel

On Sat, Feb 09, 2008 at 07:35:07AM -0600, jason.wessel@windriver.com wrote:
> index 0000000..24e0b6c
> --- /dev/null
> +++ b/include/asm-generic/kgdb.h
> @@ -0,0 +1,105 @@
> +/*
> + * include/asm-generic/kgdb.h

Please don't mention the file name in the top-of-file comments.  This
information is redundant and will easily get out of date when moving
files around or copying them.  Note that this applies to basically
any file in this patch.

> +#ifdef CONFIG_X86
> +/**
> + *	kgdb_skipexception - Bail of of KGDB when we've been triggered.
> + *	@exception: Exception vector number
> + *	@regs: Current &struct pt_regs.
> + *
> + *	On some architectures we need to skip a breakpoint exception when
> + *	it occurs after a breakpoint has been removed.
> + */
> +int kgdb_skipexception(int exception, struct pt_regs *regs);
> +#else
> +static inline int kgdb_skipexception(int exception, struct pt_regs *regs)
> +{
> +	return 0;
> +}
> +#endif
> +
> +#if defined(CONFIG_X86)

arch ifdefs don't belong into an asm-generic/ file.  Please have a
proper asm-x86/kgdb.h that defines these things.

> +/**
> + *	kgdb_post_master_code - Save error vector/code numbers.
> + *	@regs: Original pt_regs.
> + *	@e_vector: Original error vector.
> + *	@err_code: Original error code.
> + *
> + *	This is needed on architectures which support SMP and KGDB.
> + *	This function is called after all the slave cpus have been put
> + *	to a know spin state and the master CPU has control over KGDB.
> + */
> +extern void kgdb_post_master_code(struct pt_regs *regs, int e_vector,
> +				  int err_code);

Kerneldoc comments don't belong above the prototype of a function but
the function body.

> +#ifdef CONFIG_KGDB_ARCH_HAS_SHADOW_INFO
> +/**
> + *	kgdb_shadowinfo - Get shadowed information on @threadid.
> + *	@regs: The &struct pt_regs of the current process.
> + *	@buffer: A buffer of %BUFMAX size.
> + *	@threadid: The thread id of the shadowed process to get information on.
> + */
> +extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
> +			    unsigned threadid);

I don't really thing this belongs into an asm-generic header, again.
ARchitectures having shadow info should just provide this in their
own asm-foo/kgdb.h.  Or better yet just kill it for the first
submission.

> +struct debuggerinfo_struct {
> +	void			*debuggerinfo;
> +	struct task_struct	*task;
> +} kgdb_info[NR_CPUS];

shouldn't this use per-cpu data?  Or is that in some way to
fragile for a debugger?

> +/* reboot notifier block */
> +static struct notifier_block kgdb_reboot_notifier = {
> +	.notifier_call		= kgdb_notify_reboot,
> +	.next			= NULL,
> +	.priority		= INT_MAX,
> +};

No need to initialize fields to 0 or NULL in static variables.

> +{
> +	if ((ch >= 'a') && (ch <= 'f'))
> +		return ch - 'a' + 10;
> +	if ((ch >= '0') && (ch <= '9'))
> +		return ch - '0';
> +	if ((ch >= 'A') && (ch <= 'F'))
> +		return ch - 'A' + 10;

lots of superflous braces.  More of them later in this file
in the same style.

> +#ifdef __BIG_ENDIAN
> +		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_s & 0xf];
> +#else
> +		*buf++ = hexchars[(tmp_s >> 4) & 0xf];
> +		*buf++ = hexchars[tmp_s & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 12) & 0xf];
> +		*buf++ = hexchars[(tmp_s >> 8) & 0xf];
> +#endif

This is really ugly, but I don't really know a good way around it
either.

> +	if (arch_kgdb_ops.shadowth &&
> +			ks->kgdb_usethreadid >= pid_max + num_online_cpus()) {

	if (arch_kgdb_ops.shadowth &&
	    ks->kgdb_usethreadid >= pid_max + num_online_cpus()) {

similar odd indentation in a few other spots.

> +menuconfig KGDB
> +	bool "KGDB: kernel debugging with remote gdb"
> +	select KGDB_ARCH_HAS_SHADOW_INFO if X86_64

Why can't this be set in the X86_64 config?

> +	select DEBUG_INFO
> +	select FRAME_POINTER

I think these two would be better as depends on


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/8] kgdb 2.6.25 version
  2008-02-09 13:35 [PATCH 0/8] kgdb 2.6.25 version jason.wessel
  2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
@ 2008-02-09 17:38 ` Christoph Hellwig
  1 sibling, 0 replies; 24+ messages in thread
From: Christoph Hellwig @ 2008-02-09 17:38 UTC (permalink / raw)
  To: jason.wessel; +Cc: linux-kernel

On Sat, Feb 09, 2008 at 07:35:06AM -0600, jason.wessel@windriver.com wrote:
> Per reqest on lkml, here are the individual kgdb patches
> targeted at 2.6.25.
> 
> The kgdb tree has been collapsed review.  It includes
> the kgdb core, the x86 arch, the kgdb8250 uart driver
> and the kgdb console sharing driver.
> 
> Since the last time the kgdb patches were posted to LKML
> several months ago, the kgdb core has undergone some
> significant cleanup, as well as the kgdb I/O driver
> interface.
> 
> All the kgdb hooks are initialized dynamically only when a
> kgdb I/O module is configured. When not configured
> kgdb will not exist in any kernel execution path.
> 
> Further comments, questions and patches are certainly
> welcome.

I think this looks a lot nicer than all the kgdb patches I've seen
before.  Of course I'd really love to see support for ethernet using
netpoll and/or firewire eventually, but keeping things simple for
now is good.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 16:40               ` Jan Kiszka
@ 2008-02-09 18:41                 ` Jason Wessel
  0 siblings, 0 replies; 24+ messages in thread
From: Jason Wessel @ 2008-02-09 18:41 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: linux-kernel, linux-serial, Ingo Molnar, Thomas Gleixner

Jan Kiszka wrote:
> jason.wessel@windriver.com wrote:
>   
>> @@ -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);
>>     
>
> Jason, thinking about this hunk again, it appears broken to me. If we
> needed it for 8250_kgdb, we would also need it without
> CONFIG_KGDB_CONSOLE. However, powering on the UART with a special dance
> after we took over with 8250_kgdb is a job that has to be done _there_,
> not by this hook here. So let's drop the whole serial_core.c hunk from
> this patch.
>
> Jan
>   
Chunk dropped and the patches are refreshed in the git archive.

Jason.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 14:53               ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver Jan Kiszka
@ 2008-02-09 18:45                 ` Jason Wessel
  0 siblings, 0 replies; 24+ messages in thread
From: Jason Wessel @ 2008-02-09 18:45 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: linux-kernel, linux-serial, Ingo Molnar, Thomas Gleixner

Jan Kiszka wrote:
> There are a few things I missed in my last cleanup round, please fold
> them in, they reduce the changes outside kgdb. (I bet that membase
> dumping was related to mmio vs. mmap configuration, right?)
>
>   

That is correct, the right thing to do is remove the code.

I folded your patch into patch #7 and refreshed the git archive.

Thanks,
Jason.

> --- linux-2.6-kgdb.orig/drivers/serial/Kconfig
> +++ linux-2.6-kgdb/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 || KGDB_8250
> +	depends on SERIAL_8250
>  	default "4"
>  	help
>  	  Set this to the number of serial ports you want the driver
> --- linux-2.6-kgdb.orig/drivers/serial/serial_core.c
> +++ linux-2.6-kgdb/drivers/serial/serial_core.c
> @@ -1685,9 +1685,6 @@ static int uart_line_info(char *buf, str
>  			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");
> @@ -2130,9 +2127,7 @@ uart_report_port(struct uart_driver *drv
>  	case UPIO_TSI:
>  	case UPIO_DWAPB:
>  		snprintf(address, sizeof(address),
> -			 "MMIO 0x%llx mem 0x%p",
> -			 (unsigned long long)port->mapbase,
> -			 port->membase);
> +			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
>  		break;
>  	default:
>  		strlcpy(address, "*unknown*", sizeof(address));
> --- linux-2.6-kgdb.orig/include/linux/serial_8250.h
> +++ linux-2.6-kgdb/include/linux/serial_8250.h
> @@ -58,7 +58,6 @@ 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);
>   


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 17:27   ` Christoph Hellwig
@ 2008-02-09 19:46     ` Ray Lee
  2008-02-09 21:51       ` Ray Lee
  0 siblings, 1 reply; 24+ messages in thread
From: Ray Lee @ 2008-02-09 19:46 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: jason.wessel, linux-kernel

On Feb 9, 2008 9:27 AM, Christoph Hellwig <hch@infradead.org> wrote:
> On Sat, Feb 09, 2008 at 07:35:07AM -0600, jason.wessel@windriver.com wrote:
> > +#ifdef __BIG_ENDIAN
> > +             *buf++ = hexchars[(tmp_s >> 12) & 0xf];
> > +             *buf++ = hexchars[(tmp_s >> 8) & 0xf];
> > +             *buf++ = hexchars[(tmp_s >> 4) & 0xf];
> > +             *buf++ = hexchars[tmp_s & 0xf];
> > +#else
> > +             *buf++ = hexchars[(tmp_s >> 4) & 0xf];
> > +             *buf++ = hexchars[tmp_s & 0xf];
> > +             *buf++ = hexchars[(tmp_s >> 12) & 0xf];
> > +             *buf++ = hexchars[(tmp_s >> 8) & 0xf];
> > +#endif
>
> This is really ugly, but I don't really know a good way around it
> either.

void u32_to_hex(u32 val, unsigned char *buf)
{
         int i;

         for (i=7; i>=0; i--) {
                  buf[i] = hexchars[ val & 0x0f ];
                  val >>= 4;
         }
}

         u32_to_hex(tmp_s, buf);
         buf += 8;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/8] kgdb: core API and gdb protocol handler
  2008-02-09 19:46     ` Ray Lee
@ 2008-02-09 21:51       ` Ray Lee
  0 siblings, 0 replies; 24+ messages in thread
From: Ray Lee @ 2008-02-09 21:51 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: jason.wessel, linux-kernel

2008/2/9 Ray Lee <ray-lk@madrabbit.org>:
> On Feb 9, 2008 9:27 AM, Christoph Hellwig <hch@infradead.org> wrote:
> > On Sat, Feb 09, 2008 at 07:35:07AM -0600, jason.wessel@windriver.com wrote:
> > > +#ifdef __BIG_ENDIAN
> > > +             *buf++ = hexchars[(tmp_s >> 12) & 0xf];
> > > +             *buf++ = hexchars[(tmp_s >> 8) & 0xf];
> > > +             *buf++ = hexchars[(tmp_s >> 4) & 0xf];
> > > +             *buf++ = hexchars[tmp_s & 0xf];
> > > +#else
> > > +             *buf++ = hexchars[(tmp_s >> 4) & 0xf];
> > > +             *buf++ = hexchars[tmp_s & 0xf];
> > > +             *buf++ = hexchars[(tmp_s >> 12) & 0xf];
> > > +             *buf++ = hexchars[(tmp_s >> 8) & 0xf];
> > > +#endif
> >
> > This is really ugly, but I don't really know a good way around it
> > either.
>
> void u32_to_hex(u32 val, unsigned char *buf)
> {
>          int i;
>
>          for (i=7; i>=0; i--) {
>                   buf[i] = hexchars[ val & 0x0f ];
>                   val >>= 4;
>          }
> }
>
>          u32_to_hex(tmp_s, buf);
>          buf += 8;
>

Sorry, rewrote what I thought I read, not what was there. I guess
you'd want it more along the lines of

   void u32_to_hex(u32 x, unsigned char *buf)
   {
          int i;
          int val = cpu_to_be32( x );

          for (i=7; ...

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver
  2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
                                 ` (2 preceding siblings ...)
  2008-02-09 16:40               ` Jan Kiszka
@ 2008-02-10 15:26               ` Pavel Machek
  3 siblings, 0 replies; 24+ messages in thread
From: Pavel Machek @ 2008-02-10 15:26 UTC (permalink / raw)
  To: jason.wessel
  Cc: linux-kernel, linux-serial, Jan Kiszka, Ingo Molnar, Thomas Gleixner

Hi!

> 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@vger.kernel.org
> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
> Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
> Signed-off-by: Ingo Molnar <mingo@elte.hu>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.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>

I believe we already have command line options listed in different
file... and in readable format, too.


> --- /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.

Hmm, is it WindRiver or
           WinDriver? :-)


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2008-02-10 15:26 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-09 13:35 [PATCH 0/8] kgdb 2.6.25 version jason.wessel
2008-02-09 13:35 ` [PATCH 1/8] kgdb: core API and gdb protocol handler jason.wessel
2008-02-09 13:35   ` [PATCH 2/8] pid, kgdb: add pid_max prototype jason.wessel
2008-02-09 13:35     ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB jason.wessel
2008-02-09 13:35       ` [PATCH 4/8] kgdb: COPTIMIZE flag jason.wessel
2008-02-09 13:35         ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support jason.wessel
2008-02-09 13:35           ` [PATCH 6/8] kgdb, sysrq_bugfix jason.wessel
2008-02-09 13:35             ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver jason.wessel
2008-02-09 13:35               ` [PATCH 8/8] kgdb: kgdboc 8250 I/O module jason.wessel
2008-02-09 14:53               ` [PATCH][7/8] kgdb: exclusive use kgdb8250 uart I/O driver Jan Kiszka
2008-02-09 18:45                 ` Jason Wessel
2008-02-09 16:40               ` Jan Kiszka
2008-02-09 18:41                 ` Jason Wessel
2008-02-10 15:26               ` Pavel Machek
2008-02-09 14:33           ` [PATCH 5/8] kgdb, x86: Add arch specfic kgdb support Jan Kiszka
2008-02-09 17:16         ` [PATCH 4/8] kgdb: COPTIMIZE flag Christoph Hellwig
2008-02-09 17:15       ` [PATCH 3/8] kgdb, modules: Always allow module sect info for KGDB Christoph Hellwig
2008-02-09 17:10     ` [PATCH 2/8] pid, kgdb: add pid_max prototype Christoph Hellwig
2008-02-09 14:27   ` [PATCH 1/8] kgdb: core API and gdb protocol handler Jan Kiszka
2008-02-09 15:29   ` Sam Ravnborg
2008-02-09 17:27   ` Christoph Hellwig
2008-02-09 19:46     ` Ray Lee
2008-02-09 21:51       ` Ray Lee
2008-02-09 17:38 ` [PATCH 0/8] kgdb 2.6.25 version Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).