linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 01/16] Add a KGDB core
@ 2005-08-29 16:08 Tom Rini
       [not found] ` <1.2982005.trini@kernel.crashing.org>
  2005-08-30  7:33 ` [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault() George Anzinger
  0 siblings, 2 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:08 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, amitkale


Here is a different version of KGDB than found currently in Andrew Morton's
tree that Amit Kale and I (and many others) have been working on for some time
now (and submitted a while back).  I appologize for not resubmitting this
sooner, but solving some of the issues George Anzinger and others dug up
turned out to take more time than I would have liked.

Having said that, this version of KGDB is designed so that as much code as
possible is done in a core file shared by all architectures, and with I/O (ie
8250 serial, custom uart, ethernet) being common when possible and modular.
The rough splitup of this is that 95% of the interaction with KGDB is done in
files common to all implementations with a small set of architecture specific
things (setjmp/longjmp, actually formatting registers for GDB, single
stepping).

Much of how to use this version (it is slightly different from George
Anzinger's version) is written up in DocBook and viewable that way.  I've
tried to do this in as clean a way as possible (notifier when possible for
example) so that it's as minimally instrusive as possible.  But, in order to
allow for KGDB to be used very early on (some folks argue this is critical,
some argue it's not) there's a few hooks so we can know if pidhash_init has
been run, or to try and have KGDB break in as soon as possible, if it can't
right then (such as on x86_64 where stacks aren't ready for us to use just
yet).

Comments?  Thanks!

---

 linux-2.6.13-trini/Documentation/DocBook/Makefile  |    2 
 linux-2.6.13-trini/Documentation/DocBook/kgdb.tmpl |  221 ++
 linux-2.6.13-trini/MAINTAINERS                     |    9 
 linux-2.6.13-trini/include/linux/kgdb.h            |  260 ++
 linux-2.6.13-trini/kernel/Makefile                 |    1 
 linux-2.6.13-trini/kernel/kgdb.c                   | 1857 +++++++++++++++++
 linux-2.6.13-trini/kernel/pid.c                    |   11 
 linux-2.6.13-trini/kernel/sched.c                  |    4 
 linux-2.6.13-trini/lib/Kconfig.debug               |   52 
 9 files changed, 2415 insertions(+), 2 deletions(-)

diff -puN /dev/null Documentation/DocBook/kgdb.tmpl
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/Documentation/DocBook/kgdb.tmpl	2005-08-16 15:54:56.000000000 -0700
@@ -0,0 +1,221 @@
+<?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>
+    The first choice for I/O is <symbol>CONFIG_KGDB_ONLY_MODULES</symbol>.
+    This means that you will only be able to use KGDB after loading a
+    kernel module that defines how you want to be able to talk with
+    KGDB.  There are two other choices (more on some architectures) that
+    can be enabled as modules later, if not picked here.
+    </para>
+    <para>The first of these is <symbol>CONFIG_KGDB_8250_NOMODULE</symbol>.
+    This has sub-options such as <symbol>CONFIG_KGDB_SIMPLE_SERIAL</symbol>
+    which toggles choosing the serial port by ttyS number or by specifying
+    a port and IRQ number.
+    </para>
+    <para>
+    The second of these choices on most systems for I/O is
+    <symbol>CONFIG_KGDB_ETH</symbol>. This requires that the machine to be
+    debugged has an ethernet card which supports the netpoll API, such as
+    the cards supported by <symbol>CONFIG_E100</symbol>.  There are no
+    sub-options for this, but a kernel command line option is required.
+    </para>
+  </chapter>
+  <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.  If you wish to change serial port information and you
+    have enabled both <symbol>CONFIG_KGDB_8250</symbol> and
+    <symbol>CONFIG_KGDB_SIMPLE_SERIAL</symbol> then you must pass the option
+    <constant>kgdb8250=portnumber,speed</constant> or on IA64
+    <constant>kgdb8250=portnumber,speed,irq,iomembase</constant> before
+    <constant>kgdbwait</constant>.  The values for portnumber are 0-3 and
+    correspond to ttyS0 to ttyS3 respectively.  The supported speeds are
+    <constant>9600</constant>, <constant>19200</constant>,
+    <constant>38400</constant>, <constant>57600</constant>, and
+    <constant>115200</constant>.
+    </para>
+    <para>
+    To have KGDB stop the kernel and wait, with the compiled values for the
+    serial driver, pass in: <constant>kgdbwait</constant>.
+    </para>
+    <para>
+    To specify the values of the serial port at boot:
+    <constant>kgdb8250=0,115200</constant>.
+    On IA64 this could also be:
+    <constant>kgdb8250=1,115200,74,0xc0000000ff5e0000</constant>
+    And to have KGDB also stop the kernel and wait for GDB to connect, pass in
+    <constant>kgdbwait</constant> after this arguement.
+    </para>
+    <para>
+    To configure the <symbol>CONFIG_KGDB_ETH</symbol> driver, pass in
+    <constant>kgdboe=[src-port]@&lt;src-ip&gt;/[dev],[tgt-port]@&lt;tgt-ip&gt;/[tgt-macaddr]</constant>
+    where:
+    <itemizedlist>
+      <listitem><para>src-port (optional): source for UDP packets (defaults to <constant>6443</constant>)</para></listitem>
+      <listitem><para>src-ip: source IP to use (interface address)</para></listitem>
+      <listitem><para>dev (optional): network interface (<constant>eth0</constant>)</para></listitem>
+      <listitem><para>tgt-port (optional): port GDB will use (defaults to <constant>6442</constant>)</para></listitem>
+      <listitem><para>tgt-ip: IP address GDB will be connecting from</para></listitem>
+      <listitem><para>tgt-macaddr (optional): ethernet MAC address for logging agent (default is broadcast)</para></listitem>
+    </itemizedlist>
+    </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 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>
+  <chapter id="CommonBackEndOpt">
+    <title>The common backend (optional)</title>
+      <para>
+      These functions are part of the common backend, found in kernel/kgdb.c
+      and are optionally implemented.  Some functions (with _hw_ in the name)
+      end up being required on arches which use hardware breakpoints.
+      </para>
+!Ikernel/kgdb.c
+  </chapter>
+  <chapter id="DriverSpecificFunctions">
+    <title>Driver-Specific Functions</title>
+      <para>
+      Some of the I/O drivers have additional functions that can be
+      called, that are specific to the driver.  Calls from other places
+      to these functions must be wrapped in #ifdefs for the driver in
+      question.
+      </para>
+!Idrivers/serial/kgdb_8250.c
+   </chapter>
+</book>
diff -puN Documentation/DocBook/Makefile~core-lite Documentation/DocBook/Makefile
--- linux-2.6.13/Documentation/DocBook/Makefile~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/Documentation/DocBook/Makefile	2005-08-16 15:54:47.000000000 -0700
@@ -10,7 +10,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mc
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml \
 	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
-	    gadget.xml libata.xml mtdnand.xml librs.xml
+	    gadget.xml libata.xml mtdnand.xml librs.xml kgdb.xml
 
 ###
 # The build process is as follows (targets):
diff -puN /dev/null include/linux/kgdb.h
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/include/linux/kgdb.h	2005-08-16 15:54:47.000000000 -0700
@@ -0,0 +1,260 @@
+/*
+ * 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-2004 (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.
+ */
+#ifdef __KERNEL__
+#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>
+
+struct tasklet_struct;
+struct pt_regs;
+struct task_struct;
+struct uart_port;
+
+
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+extern int kgdb_connected;
+extern int kgdb_may_fault;
+extern struct tasklet_struct kgdb_tasklet_breakpoint;
+
+extern atomic_t kgdb_setting_breakpoint;
+extern atomic_t cpu_doing_single_step;
+
+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+enum kgdb_bptype {
+	bp_breakpoint = '0',
+	bp_hardware_breakpoint,
+	bp_write_watchpoint,
+	bp_read_watchpoint,
+	bp_access_watchpoint
+};
+
+enum kgdb_bpstate {
+	bp_disabled,
+	bp_enabled
+};
+
+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 MAX_KGDB_IO_HANDLERS 3
+
+#ifndef MAX_BREAKPOINTS
+#define MAX_BREAKPOINTS		16
+#endif
+
+#define KGDB_HW_BREAKPOINT	1
+
+/* Required functions. */
+/**
+ *	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.
+ */
+extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+
+/**
+ *	sleeping_regs_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.
+ */
+extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+					struct task_struct *p);
+
+/**
+ *	gdb_regs_to_regs - Convert GDB regs to ptrace regs.
+ *	@gdb_regs: A pointer to hold the registers we've recieved 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.
+ */
+extern void gdb_regs_to_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 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.
+ */
+extern int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+				      char *remcom_in_buffer,
+				      char *remcom_out_buffer,
+				      struct pt_regs *regs);
+
+#ifndef JMP_REGS_ALIGNMENT
+#define JMP_REGS_ALIGNMENT
+#endif
+
+extern unsigned long kgdb_fault_jmp_regs[];
+
+/**
+ *	kgdb_fault_setjmp - Store state in case we fault.
+ *	@curr_context: An array to store state into.
+ *
+ *	Certain functions may try and access memory, and in doing so may
+ *	cause a fault.  When this happens, we trap it, restore state to
+ *	this call, and let ourself know that something bad has happened.
+ */
+extern asmlinkage int kgdb_fault_setjmp(unsigned long *curr_context);
+
+/**
+ *	kgdb_fault_longjmp - Restore state when we have faulted.
+ *	@curr_context: The previously stored state.
+ *
+ *	When something bad does happen, this function is called to
+ *	restore the known good state, and set the return value to 1, so
+ *	we know something bad happened.
+ */
+extern asmlinkage void kgdb_fault_longjmp(unsigned long *curr_context);
+
+/* Optional functions. */
+extern int kgdb_arch_init(void);
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+extern void kgdb_post_master_code(struct pt_regs *regs, int e_vector,
+				  int err_code);
+extern void kgdb_roundup_cpus(unsigned long flags);
+extern int kgdb_set_hw_break(unsigned long addr);
+extern int kgdb_remove_hw_break(unsigned long addr);
+extern void kgdb_remove_all_hw_break(void);
+extern void kgdb_correct_hw_break(void);
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
+			    unsigned threadid);
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+						  int threadid);
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+
+/**
+ * struct kgdb_arch - Desribe 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.
+ *
+ * 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);
+};
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+/**
+ * struct kgdb_io - Desribe the interface for an I/O driver to talk with KGDB.
+ * @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 {
+	int (*read_char) (void);
+	void (*write_char) (int);
+	void (*flush) (void);
+	int (*init) (void);
+	void (*late_init) (void);
+	void (*pre_exception) (void);
+	void (*post_exception) (void);
+};
+
+extern struct kgdb_io kgdb_io_ops;
+extern struct kgdb_arch arch_kgdb_ops;
+extern int kgdb_initialized;
+
+extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
+extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
+
+extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
+extern void kgdb8250_add_platform_port(int i, struct plat_serial8250_port *serial_req);
+
+extern int kgdb_hex2long(char **ptr, long *long_val);
+extern char *kgdb_mem2hex(char *mem, char *buf, int count);
+extern char *kgdb_hex2mem(char *buf, char *mem, int count);
+extern int kgdb_get_mem(char *addr, unsigned char *buf, int count);
+extern int kgdb_set_mem(char *addr, unsigned char *buf, int count);
+extern int kgdb_handle_exception(int ex_vector, int signo, int err_code,
+				struct pt_regs *regs);
+extern void kgdb_nmihook(int cpu, void *regs);
+extern int debugger_step;
+extern atomic_t debugger_active;
+#else
+/* Stubs for when KGDB is not set. */
+static const atomic_t debugger_active = ATOMIC_INIT(0);
+#endif				/* CONFIG_KGDB */
+#endif				/* _KGDB_H_ */
+#endif				/* __KERNEL__ */
diff -puN /dev/null kernel/kgdb.c
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/kernel/kgdb.c	2005-08-16 15:54:47.000000000 -0700
@@ -0,0 +1,1857 @@
+/*
+ * 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) 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-2005 Tom Rini <trini@kernel.crashing.org>
+ * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd.
+ * Copyright (C) 2005 Wind River System, Inc.
+ *
+ * Added ability to setup kgdb I/O at runtime with a kernel module.
+ * Added ability to allow a single in-kernel I/O routine and override
+ * it with a kernel module.
+ * IE: rs232 for early kernel debug and kgdboe after the boot is completed
+ * - Jason Wessel ( jason.wessel@windriver.com )
+ *
+ * Restructured KGDB for 2.6 kernels.
+ * thread support, support for multiple processors,support for ia-32(x86)
+ * hardware debugging, Console support, handling nmi watchdog
+ * - Amit S. Kale ( amitkale@linsyssoft.com )
+ *
+ * Several enhancements by George Anzinger <george@mvista.com>
+ * Generic KGDB Support
+ * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com)
+ *
+ * Contributor:	Lake Stevens Instrument Division
+ * Written by:	Glenn Engel
+ *
+ * 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>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <linux/kgdb.h>
+#include <asm/atomic.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <asm/byteorder.h>
+
+extern int pid_max;
+extern int pidhash_init_done;
+
+/* How many times to count all of the waiting CPUs */
+#define ROUNDUP_WAIT		64000
+#define BUF_THREAD_ID_SIZE 16
+
+/*
+ * kgdb_initialized with a value of 1 indicates that kgdb is setup and is
+ * all ready to serve breakpoints and other kernel exceptions.  A value of
+ * -1 indicates that we have tried to initialize early, and need to try
+ * again later.
+ */
+int kgdb_initialized = 0;
+/* Is a host GDB connected to us? */
+int kgdb_connected;
+/* Could we be about to try and access a bad memory location? If so we
+ * also need to flag this has happend. */
+int kgdb_may_fault;
+/* All the KGDB handlers are installed */
+int kgdb_from_module_registered = 0;
+
+/* We provide a kgdb_io_ops structure that may be overriden. */
+struct kgdb_io __attribute__ ((weak)) kgdb_io_ops;
+
+static struct kgdb_io kgdb_io_ops_prev[MAX_KGDB_IO_HANDLERS];
+static int kgdb_io_handler_cnt = 0;
+
+/* Export the following symbols for use with kernel modules */
+EXPORT_SYMBOL(kgdb_io_ops);
+EXPORT_SYMBOL(kgdb_tasklet_breakpoint);
+EXPORT_SYMBOL(kgdb_connected);
+EXPORT_SYMBOL(kgdb_register_io_module);
+EXPORT_SYMBOL(kgdb_unregister_io_module);
+EXPORT_SYMBOL(debugger_active);
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS];
+
+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
+
+static const char hexchars[] = "0123456789abcdef";
+
+static spinlock_t slavecpulocks[NR_CPUS];
+static volatile int procindebug[NR_CPUS];
+atomic_t kgdb_setting_breakpoint;
+EXPORT_SYMBOL(kgdb_setting_breakpoint);
+struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+int debugger_step;
+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)];
+/* Storage of registers for handling a fault. */
+unsigned long kgdb_fault_jmp_regs[NUMCRITREGBYTES / sizeof(unsigned long)]
+ JMP_REGS_ALIGNMENT;
+
+struct debuggerinfo_struct {
+	void *debuggerinfo;
+	struct task_struct *task;
+} kgdb_info[NR_CPUS];
+
+/* to keep track of the CPU which is doing the single stepping*/
+atomic_t cpu_doing_single_step = ATOMIC_INIT(-1);
+
+/**
+ *	kgdb_arch_init - Perform any architecture specific initalization.
+ *
+ *	RETURN:
+ *	The return value is ignored.
+ *
+ *	This function will handle the initalization of any architecture
+ *	specific hooks.
+ */
+int __attribute__ ((weak))
+    kgdb_arch_init(void)
+{
+	return 0;
+}
+
+/**
+ *	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.
+ */
+void __attribute__ ((weak))
+    kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+}
+
+/**
+ *	kgdb_set_hw_break - Set a hardware breakpoint at @addr.
+ *	@addr: The address to set a hardware breakpoint at.
+ */
+int __attribute__ ((weak))
+    kgdb_set_hw_break(unsigned long addr)
+{
+	return 0;
+}
+
+/**
+ *	kgdb_remove_hw_break - Remove a hardware breakpoint at @addr.
+ *	@addr: The address to remove a hardware breakpoint from.
+ */
+int __attribute__ ((weak))
+    kgdb_remove_hw_break(unsigned long addr)
+{
+	return 0;
+}
+
+/**
+ *	kgdb_remove_all_hw_break - Clear all hardware breakpoints.
+ */
+void __attribute__ ((weak))
+    kgdb_remove_all_hw_break(void)
+{
+}
+
+/**
+ *	kgdb_correct_hw_break - Correct hardware breakpoints.
+ *
+ *	A hook to allow for changes to the hardware breakpoint, called
+ *	after a single step (s) or continue (c) packet, and once we're about
+ *	to let the kernel continue running.
+ *
+ *	This is used to set the hardware breakpoint registers for all the
+ *	slave cpus on an SMP configuration. This must be called after any
+ *	changes are made to the hardware breakpoints (such as by a single
+ *	step (s) or continue (c) packet. This is only required on
+ *	architectures that support SMP and every processor has its own set
+ *	of breakpoint registers.
+ */
+void __attribute__ ((weak))
+    kgdb_correct_hw_break(void)
+{
+}
+
+/**
+ *	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.
+ */
+
+void __attribute__ ((weak))
+    kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
+{
+}
+
+/**
+ * 	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().
+ */
+void __attribute__ ((weak))
+    kgdb_roundup_cpus(unsigned long flags)
+{
+}
+
+/**
+ *	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.
+ */
+void __attribute__ ((weak))
+    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.
+ */
+struct task_struct __attribute__ ((weak))
+    * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+/**
+ *	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.
+ */
+struct pt_regs __attribute__ ((weak))
+    * kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+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;
+	if (!kgdb_io_ops.read_char)
+		return;
+	do {
+		/* Spin and wait around for the start character, ignore all
+		 * other characters */
+		while ((ch = (kgdb_io_ops.read_char())) != '$') ;
+		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;
+
+	if (!kgdb_io_ops.write_char)
+		return;
+	/* $<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;
+		}
+	}
+}
+
+/*
+ * 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)
+{
+	kgdb_may_fault = 1;
+	if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) {
+		kgdb_may_fault = 0;
+		return ERR_PTR(-EINVAL);
+	}
+	/* 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)) {
+		unsigned short tmp_s = *(unsigned short *)mem;
+		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)) {
+		unsigned long tmp_l = *(unsigned int *)mem;
+		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)) {
+		unsigned long long tmp_ll = *(unsigned long long *)mem;
+		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 = *mem++;
+			*buf++ = hexchars[ch >> 4];
+			*buf++ = hexchars[ch & 0xf];
+		}
+	}
+	kgdb_may_fault = 0;
+	*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)
+{
+	kgdb_may_fault = 1;
+	if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) {
+		kgdb_may_fault = 0;
+		return ERR_PTR(-EINVAL);
+	}
+	for (; count > 0; count--, buf++) {
+		if (*buf == 0x7d)
+			*mem++ = *(++buf) ^ 0x20;
+		else
+			*mem++ = *buf;
+	}
+	kgdb_may_fault = 0;
+	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)
+{
+	kgdb_may_fault = 1;
+	if ((kgdb_fault_setjmp(kgdb_fault_jmp_regs)) != 0) {
+		kgdb_may_fault = 0;
+		return ERR_PTR(-EINVAL);
+	}
+	if ((count == 2) && (((long)mem & 1) == 0)) {
+		unsigned short 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
+		*(unsigned short *)mem = tmp_s;
+		mem += 2;
+	} else if ((count == 4) && (((long)mem & 3) == 0)) {
+		unsigned long 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
+		*(unsigned long *)mem = tmp_l;
+		mem += 4;
+	} else {
+		int i;
+		for (i = 0; i < count; i++) {
+			unsigned char ch = hex(*buf++) << 4;
+			ch |= hex(*buf++);
+			*mem++ = ch;
+		}
+	}
+	kgdb_may_fault = 0;
+	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, 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, 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 (CACHE_FLUSH_IS_SAFE)
+			flush_icache_range(addr, addr + length + 1);
+		if (IS_ERR(ptr))
+			return ptr;
+		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';
+}
+
+static char *pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *)id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+
+	return pkt;
+}
+
+void int_to_threadref(threadref * 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 (!pidhash_init_done)
+		return current;
+
+	if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth)
+		return NULL;
+
+	if (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;
+
+	return find_task_by_pid(tid);
+}
+
+#ifdef CONFIG_SMP
+static void kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int processor;
+
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	kgdb_info[processor].debuggerinfo = regs;
+	kgdb_info[processor].task = current;
+
+	/* Wait till master processor goes completely into the debugger.
+	 * FIXME: this looks racy */
+	while (!procindebug[atomic_read(&debugger_active) - 1]) {
+		int i = 10;	/* an arbitrary number */
+
+		while (--i)
+			cpu_relax();
+		barrier();
+	}
+
+	/* Wait till master processor is done with debugging */
+	spin_lock(&slavecpulocks[processor]);
+
+	/* This has been taken from x86 kgdb implementation and
+	 * will be needed by architectures that have SMP support
+	 */
+	kgdb_correct_hw_break();
+
+	kgdb_info[processor].debuggerinfo = NULL;
+	kgdb_info[processor].task = NULL;
+
+	/* Signal the master processor that we are done */
+	procindebug[processor] = 0;
+	spin_unlock(&slavecpulocks[processor]);
+	local_irq_restore(flags);
+}
+#endif
+
+int kgdb_get_mem(char *addr, unsigned char *buf, int count)
+{
+	while (count) {
+		if ((unsigned long)addr < TASK_SIZE)
+			return -EINVAL;
+		*buf++ = *addr++;
+		count--;
+	}
+	return 0;
+}
+
+int kgdb_set_mem(char *addr, unsigned char *buf, int count)
+{
+	while (count) {
+		if ((unsigned long)addr < TASK_SIZE)
+			return -EINVAL;
+		*addr++ = *buf++;
+		count--;
+	}
+	return 0;
+}
+
+static int kgdb_set_sw_break(unsigned long addr)
+{
+	int i, breakno = -1;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr))
+			return -EEXIST;
+
+		if (kgdb_break[i].state == bp_disabled) {
+			if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
+				breakno = i;
+		}
+	}
+	if (breakno == -1)
+		return -E2BIG;
+
+	if (kgdb_ops->set_breakpoint) {
+		if ((error = kgdb_ops->set_breakpoint(addr,
+					kgdb_break[breakno].saved_instr)) < 0)
+			return error;
+	} else {
+		if ((error = kgdb_get_mem((char *)addr,
+					  kgdb_break[breakno].saved_instr,
+					  BREAK_INSTR_SIZE)) < 0)
+			return error;
+
+		if ((error = kgdb_set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+					  BREAK_INSTR_SIZE)) < 0)
+			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[breakno].state = bp_enabled;
+	kgdb_break[breakno].type = bp_breakpoint;
+	kgdb_break[breakno].bpt_addr = addr;
+
+	return 0;
+}
+
+static int kgdb_remove_sw_break(unsigned long addr)
+{
+	int i;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			if (kgdb_ops->remove_breakpoint) {
+				if ((error = kgdb_ops->remove_breakpoint(addr,
+						kgdb_break[i].saved_instr)) < 0)
+					return error;
+			} else if ((error =
+				    kgdb_set_mem((char *)addr,
+						 kgdb_break[i].saved_instr,
+						 BREAK_INSTR_SIZE)) < 0)
+				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_disabled;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int remove_all_break(void)
+{
+	int i;
+	int error;
+
+	/* Clear memory breakpoints. */
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state == bp_enabled) {
+			unsigned long addr = kgdb_break[i].bpt_addr;
+			if ((error =
+			     kgdb_set_mem((char *)addr,
+					  kgdb_break[i].saved_instr,
+					  BREAK_INSTR_SIZE)) < 0)
+				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_disabled;
+	}
+
+	/* Clear hardware breakpoints. */
+	kgdb_remove_all_hw_break();
+
+	return 0;
+}
+
+static inline int shadow_pid(int realpid)
+{
+	if (realpid) {
+		return realpid;
+	}
+	return pid_max + smp_processor_id();
+}
+
+static char gdbmsgbuf[BUFMAX + 1];
+static void kgdb_msg_write(const char *s, int len)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+
+	/* '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);
+	}
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * 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 ex_vector, int signo, int err_code,
+			  struct pt_regs *linux_regs)
+{
+	unsigned long length, addr;
+	char *ptr;
+	unsigned long flags;
+	int i;
+	long threadid;
+	threadref thref;
+	struct task_struct *thread = NULL;
+	unsigned procid;
+	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+	long kgdb_usethreadid = 0;
+	int error = 0, all_cpus_synced = 0;
+	struct pt_regs *shadowregs;
+	int processor = smp_processor_id();
+	void *local_debuggerinfo;
+
+	/* Panic on recursive debugger calls. */
+	if (atomic_read(&debugger_active) == smp_processor_id() + 1)
+		return 0;
+
+      acquirelock:
+
+	/* Call the I/O drivers pre_exception routine if the I/O
+	 * driver defined one
+	 */
+	if (kgdb_io_ops.pre_exception)
+		kgdb_io_ops.pre_exception();
+
+	/*
+	 * Interrupts will be restored by the 'trap return' code, except when
+	 * single stepping.
+	 */
+	local_irq_save(flags);
+
+	/* Hold debugger_active */
+	procid = smp_processor_id();
+
+	while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) {
+		int i = 25;	/* an arbitrary number */
+
+		while (--i)
+			cpu_relax();
+
+		if (atomic_read(&cpu_doing_single_step) != -1 &&
+				atomic_read(&cpu_doing_single_step) != procid)
+			udelay(1);
+	}
+
+	/*
+	 * Don't enter if the last instance of the exception handler wanted to
+	 * come into the debugger again.
+	 */
+	if (atomic_read(&cpu_doing_single_step) != -1 &&
+	    atomic_read(&cpu_doing_single_step) != procid) {
+		atomic_set(&debugger_active, 0);
+		local_irq_restore(flags);
+		goto acquirelock;
+	}
+
+	kgdb_info[processor].debuggerinfo = linux_regs;
+	kgdb_info[processor].task = current;
+
+	kgdb_disable_hw_debug(linux_regs);
+
+	if (!debugger_step || !kgdb_contthread)
+		for (i = 0; i < NR_CPUS; i++)
+			spin_lock(&slavecpulocks[i]);
+
+	/* Make sure we get the other CPUs */
+	if (!debugger_step || !kgdb_contthread)
+		kgdb_roundup_cpus(flags);
+
+	/* spin_lock code is good enough as a barrier so we don't
+	 * need one here */
+	procindebug[smp_processor_id()] = 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 cpu, num = 0;
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (procindebug[cpu])
+				num++;
+		}
+		if (num >= num_online_cpus()) {
+			all_cpus_synced = 1;
+			break;
+		}
+	}
+
+	/* Clear the out buffer. */
+	memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+	/* Master processor is completely in the debugger */
+	kgdb_post_master_code(linux_regs, ex_vector, err_code);
+
+	debugger_step = 0;
+	kgdb_contthread = NULL;
+
+	if (kgdb_connected) {
+		/* If we're still unable to roundup all of the CPUs,
+		 * send an 'O' packet informing the user again. */
+		if (!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[(signo >> 4) % 16];
+		*ptr++ = hexchars[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[processor].task;
+	kgdb_usethreadid = shadow_pid(kgdb_info[processor].task->pid);
+
+	while (kgdb_io_ops.init) {
+		char *bpt_type;
+		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 '?':
+			/* We know that this packet is only sent
+			 * during initial connect.  So to be safe,
+			 * we clear out our breakpoints now incase
+			 * 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 (!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[signo >> 4];
+			remcom_out_buffer[2] = hexchars[signo % 16];
+			break;
+
+		case 'g':	/* return the value of the CPU registers */
+			thread = kgdb_usethread;
+
+			if (!thread) {
+				thread = kgdb_info[processor].task;
+				local_debuggerinfo =
+				    kgdb_info[processor].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 (kgdb_usethreadid >= pid_max + num_online_cpus()) {
+				shadowregs = kgdb_shadow_regs(linux_regs,
+							      kgdb_usethreadid -
+							      pid_max -
+							      num_online_cpus
+							      ());
+				if (!shadowregs) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs, shadowregs);
+			} else if (local_debuggerinfo)
+				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);
+			break;
+
+			/* set the value of the CPU registers - return OK */
+		case 'G':
+			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_regs(gdb_regs, linux_regs);
+				strcpy(remcom_out_buffer, "OK");
+			}
+			break;
+
+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm':
+			ptr = &remcom_in_buffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+			    kgdb_hex2long(&ptr, &length) > 0) {
+				if (IS_ERR(ptr = kgdb_mem2hex((char *)addr,
+							      remcom_out_buffer,
+							      length)))
+					error_packet(remcom_out_buffer,
+						     PTR_ERR(ptr));
+			} else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+
+			/* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */
+		case 'M':
+			if (IS_ERR(ptr = write_mem_msg(0)))
+				error_packet(remcom_out_buffer, PTR_ERR(ptr));
+			else
+				strcpy(remcom_out_buffer, "OK");
+			break;
+			/* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */
+		case 'X':
+			if (IS_ERR(ptr = write_mem_msg(1)))
+				error_packet(remcom_out_buffer, PTR_ERR(ptr));
+			else
+				strcpy(remcom_out_buffer, "OK");
+			break;
+
+			/* kill or detach. KGDB should treat this like a
+			 * continue.
+			 */
+		case 'D':
+			if ((error = remove_all_break()) < 0) {
+				error_packet(remcom_out_buffer, error);
+			} else {
+				strcpy(remcom_out_buffer, "OK");
+				kgdb_connected = 0;
+			}
+			put_packet(remcom_out_buffer);
+			goto default_handle;
+
+		case 'k':
+			/* Don't care about error from remove_all_break */
+			remove_all_break();
+			kgdb_connected = 0;
+			goto default_handle;
+
+			/* query */
+		case 'q':
+			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 (!pidhash_init_done) {
+					if (remcom_in_buffer[1] == 'f')
+						strcpy(remcom_out_buffer,
+						       "m0000000000000001");
+					break;
+				}
+
+				if (remcom_in_buffer[1] == 'f') {
+					threadid = 1;
+				}
+				remcom_out_buffer[0] = 'm';
+				ptr = remcom_out_buffer + 1;
+				for (i = 0; i < 17 && threadid < pid_max +
+				     numshadowth; threadid++) {
+					thread = getthread(linux_regs,
+							   threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(ptr, &thref);
+						ptr += 16;
+						*(ptr++) = ',';
+						i++;
+					}
+				}
+				*(--ptr) = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				strcpy(remcom_out_buffer, "QC");
+
+				threadid = shadow_pid(current->pid);
+
+				int_to_threadref(&thref, 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;
+				}
+				threadid = 0;
+				ptr = remcom_in_buffer + 17;
+				kgdb_hex2long(&ptr, &threadid);
+				if (!getthread(linux_regs, threadid)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				if (threadid < pid_max) {
+					kgdb_mem2hex(getthread(linux_regs,
+							       threadid)->comm,
+						     remcom_out_buffer, 16);
+				} else if (threadid >= pid_max +
+					   num_online_cpus()) {
+					kgdb_shadowinfo(linux_regs,
+							remcom_out_buffer,
+							threadid - pid_max -
+							num_online_cpus());
+				} else {
+					static char tmpstr[23 +
+							   BUF_THREAD_ID_SIZE];
+					sprintf(tmpstr, "Shadow task %d"
+						" for pid 0",
+						(int)(threadid - pid_max));
+					kgdb_mem2hex(tmpstr, remcom_out_buffer,
+						     strlen(tmpstr));
+				}
+				break;
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcom_in_buffer[1]) {
+			case 'g':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				thread = getthread(linux_regs, threadid);
+				if (!thread && threadid > 0) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				kgdb_usethread = thread;
+				kgdb_usethreadid = threadid;
+				strcpy(remcom_out_buffer, "OK");
+				break;
+
+			case 'c':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				if (!threadid) {
+					kgdb_contthread = NULL;
+				} else {
+					thread = getthread(linux_regs,
+							   threadid);
+					if (!thread && threadid > 0) {
+						error_packet(remcom_out_buffer,
+							     -EINVAL);
+						break;
+					}
+					kgdb_contthread = thread;
+				}
+				strcpy(remcom_out_buffer, "OK");
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcom_in_buffer[1];
+			kgdb_hex2long(&ptr, &threadid);
+			thread = getthread(linux_regs, threadid);
+			if (thread)
+				strcpy(remcom_out_buffer, "OK");
+			else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		/* Since GDB-5.3, it's been drafted that '0' is a software
+		 * breakpoint, '1' is a hardware breakpoint, so let's do
+		 * that.
+		 */
+		case 'z':
+		case 'Z':
+			bpt_type = &remcom_in_buffer[1];
+			ptr = &remcom_in_buffer[2];
+
+			if (kgdb_ops->set_hw_breakpoint && *bpt_type >= '1') {
+				/* Unsupported */
+				if (*bpt_type > '4')
+					break;
+			} else if (*bpt_type != '0' && *bpt_type != '1')
+				/* Unsupported. */
+				break;
+			/* Test if this is a hardware breakpoint, and
+			 * if we support it. */
+			if (*bpt_type == '1' &&
+			    !kgdb_ops->flags & KGDB_HW_BREAKPOINT)
+				/* Unsupported. */
+				break;
+
+			if (*(ptr++) != ',') {
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			} else if (kgdb_hex2long(&ptr, &addr)) {
+				if (*(ptr++) != ',' ||
+				    !kgdb_hex2long(&ptr, &length)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+			} else {
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+
+			if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')
+				error = kgdb_set_sw_break(addr);
+			else if (remcom_in_buffer[0] == 'Z' && *bpt_type == '1')
+				error = kgdb_set_hw_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' && *bpt_type == '1')
+				error = kgdb_remove_hw_break(addr);
+			else if (remcom_in_buffer[0] == 'Z')
+				error = kgdb_ops->set_hw_breakpoint(addr,
+								    (int)length,
+								    *bpt_type);
+			else if (remcom_in_buffer[0] == 'z')
+				error = 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);
+
+			break;
+		case 'c':
+		case 's':
+			if (kgdb_contthread && kgdb_contthread != current) {
+				/* Can't switch threads in kgdb */
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+
+			/* Followthrough to default processing */
+		default:
+		      default_handle:
+			error = kgdb_arch_handle_exception(ex_vector, signo,
+							   err_code,
+							   remcom_in_buffer,
+							   remcom_out_buffer,
+							   linux_regs);
+
+			if (error >= 0 || remcom_in_buffer[0] == 'D' ||
+			    remcom_in_buffer[0] == 'k')
+				goto kgdb_exit;
+
+		}		/* switch */
+
+		/* reply to the request */
+		put_packet(remcom_out_buffer);
+	}
+
+      kgdb_exit:
+	/* Call the I/O driver's post_exception routine if the I/O
+	 * driver defined one.
+	 */
+	if (kgdb_io_ops.post_exception)
+		kgdb_io_ops.post_exception();
+
+	kgdb_info[processor].debuggerinfo = NULL;
+	kgdb_info[processor].task = NULL;
+	procindebug[smp_processor_id()] = 0;
+
+	if (!debugger_step || !kgdb_contthread) {
+		for (i = 0; i < NR_CPUS; i++)
+			spin_unlock(&slavecpulocks[i]);
+		/* Wait till all the processors have quit
+		 * from the debugger. */
+		for (i = 0; i < NR_CPUS; i++) {
+			while (procindebug[i]) {
+				int j = 10;	/* an arbitrary number */
+
+				while (--j)
+					cpu_relax();
+				barrier();
+			}
+		}
+	}
+
+#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 processors 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 processors.  This
+	 * delay gives some time for interrupts to be cleared out on
+	 * the other processors.
+	 */
+	if (debugger_step)
+		mdelay(2);
+#endif
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+	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,
+};
+
+void kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+	if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1))
+		kgdb_wait((struct pt_regs *)regs);
+#endif
+}
+
+/*
+ * 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)
+{
+	breakpoint();
+
+	return 0;
+}
+
+static struct notifier_block kgdb_panic_notifier = {
+	.notifier_call = kgdb_panic_notify,
+};
+
+/*
+ * Initialization that needs to be done in either of our entry points.
+ */
+static void __init kgdb_internal_init(void)
+{
+	int i;
+
+	/* Initialize our spinlocks. */
+	for (i = 0; i < NR_CPUS; i++)
+		spin_lock_init(&slavecpulocks[i]);
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++)
+		kgdb_break[i].state = bp_disabled;
+
+	/* Initialize the I/O handles */
+	for (i = 0; i < MAX_KGDB_IO_HANDLERS; i++)
+		kgdb_io_ops_prev[i].init = NULL;
+
+	/* We can't do much if this fails */
+	register_module_notifier(&kgdb_module_load_nb);
+
+	kgdb_initialized = 1;
+}
+
+static void kgdb_register_for_panic(void)
+{
+	/* Register for panics(). */
+	/* The registration is done in the kgdb_register_for_panic
+	 * routine because KGDB should not try to handle a panic when
+	 * there are no kgdb_io_ops setup. It is assumed that the
+	 * kgdb_io_ops are setup at the time this method is called.
+	 */
+	if (!kgdb_from_module_registered) {
+		notifier_chain_register(&panic_notifier_list,
+					&kgdb_panic_notifier);
+		kgdb_from_module_registered = 1;
+	}
+}
+
+static void kgdb_unregister_for_panic(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_from_module_registered) {
+		kgdb_from_module_registered = 0;
+		notifier_chain_unregister(&panic_notifier_list,
+					  &kgdb_panic_notifier);
+	}
+
+	if (kgdb_connected) {
+		printk(KERN_CRIT "kgdb: ERROR the debug module unload was "
+		       "called while kgdb was conencted.  Recovery "
+		       "attempted, but further debugging may not be "
+		       "possible.\n");
+		if (remove_all_break() < 0) {
+			printk(KERN_CRIT "kgdb: recovery failed, rebooting "
+			       "is advised\n");
+		}
+		kgdb_connected = 0;
+	}
+}
+
+int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops)
+{
+
+	if (kgdb_connected) {
+		printk(KERN_ERR "kgdb: Cannot load I/O module while KGDB "
+		       "connected.\n");
+		return -EINVAL;
+	}
+
+	/* Save the old values so they can be restored */
+	if (kgdb_io_handler_cnt >= MAX_KGDB_IO_HANDLERS) {
+		printk(KERN_ERR "kgdb: No more I/O handles available.\n");
+		return -EINVAL;
+	}
+
+	/* Check to see if there is an existing driver and if so save
+	 * its values.
+	 */
+	if (kgdb_io_ops.init != NULL) {
+		memcpy(&kgdb_io_ops_prev[kgdb_io_handler_cnt],
+		       &kgdb_io_ops, sizeof(struct kgdb_io));
+		kgdb_io_handler_cnt++;
+	}
+
+	/* Initialize the io values for this module */
+	memcpy(&kgdb_io_ops, local_kgdb_io_ops, sizeof(struct kgdb_io));
+
+	/* Make the call to register kgdb if is not initialized */
+	kgdb_register_for_panic();
+
+	return 0;
+}
+
+void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops)
+{
+	int i;
+
+	/* Unregister KGDB if there were no other prior io hooks, else
+	 * restore the io hooks.
+	 */
+	if (kgdb_io_handler_cnt > 0 && kgdb_io_ops_prev[0].init != NULL) {
+		/* First check if the hook that is in use is the one being
+		 * removed */
+		if (kgdb_io_ops.init == local_kgdb_io_ops->init) {
+			/* Set 'i' to the value of where the list should be
+			 * shifed */
+			i = kgdb_io_handler_cnt - 1;
+			memcpy(&kgdb_io_ops, &kgdb_io_ops_prev[i],
+			       sizeof(struct kgdb_io));
+		} else {
+			/* Simple case to remove an entry for an I/O handler
+			 * that is not in use */
+			for (i = 0; i < kgdb_io_handler_cnt; i++) {
+				if (kgdb_io_ops_prev[i].init ==
+				    local_kgdb_io_ops->init)
+					break;
+			}
+		}
+
+		/* Shift all the entries in the handler array so it is
+		 * ordered from oldest to newest.
+		 */
+		kgdb_io_handler_cnt--;
+		for (; i < kgdb_io_handler_cnt; i++) {
+			memcpy(&kgdb_io_ops_prev[i], &kgdb_io_ops_prev[i + 1],
+			       sizeof(struct kgdb_io));
+		}
+		/* Handle the case if we are on the last element and set it
+		 * to NULL; */
+		kgdb_io_ops_prev[kgdb_io_handler_cnt].init = NULL;
+
+		if (kgdb_connected)
+			printk(KERN_ERR "kgdb: WARNING: I/O method changed "
+			       "while kgdb was connected state, "
+			       "further debugging may not be " "possible\n");
+	} else {
+		/* Unregister the KGDB hooks since this must be the
+		 * last I/O module for KGDB
+		 */
+		kgdb_unregister_for_panic();
+		memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
+	}
+}
+
+/*
+ * There are times we need to call a tasklet to cause a breakpoint
+ * as calling breakpoint() at that point might be fatal.  We have to
+ * check that the exception stack is setup, as tasklets may be scheduled
+ * prior to this.  When that happens, it is up to the architecture to
+ * schedule this when it is safe to run.
+ */
+static void kgdb_tasklet_bpt(unsigned long ing)
+{
+	if (CHECK_EXCEPTION_STACK())
+		breakpoint();
+}
+
+DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0);
+
+/*
+ * This function can be called very early, either via early_param() or
+ * an explicit breakpoint() early on.
+ */
+static void __init kgdb_early_entry(void)
+{
+	/*
+	 * Don't try and do anything until the architecture is able to
+	 * setup the exception stack.  In this case, it is up to the
+	 * architecture to hook in and look at us when they are ready.
+	 */
+	if (!CHECK_EXCEPTION_STACK()) {
+		kgdb_initialized = -1;
+		tasklet_schedule(&kgdb_tasklet_breakpoint);
+		return;
+	}
+
+	/* Let the architecture do any setup that it needs to. */
+	kgdb_arch_init();
+
+	/* Now try the I/O. */
+	/* For early entry kgdb_io_ops.init must be defined */
+	if (!kgdb_io_ops.init || kgdb_io_ops.init()) {
+		/* Try again later. */
+		kgdb_initialized = -1;
+		return;
+	}
+
+	/* Finish up. */
+	kgdb_internal_init();
+
+	/* KGDB can assume that if kgdb_io_ops.init was defined that the
+	 * panic registion should be performed at this time. This means
+	 * kgdb_io_ops.init did not come from a kernel module and was
+	 * initialized statically by a built in.
+	 */
+	if (kgdb_io_ops.init)
+		kgdb_register_for_panic();
+}
+
+/*
+ * This function will always be invoked to make sure that KGDB will grab
+ * what it needs to so that if something happens while the system is
+ * running, KGDB will get involved.  If kgdb_early_entry() has already
+ * been invoked, there is little we need to do.
+ */
+static int __init kgdb_late_entry(void)
+{
+	int need_break = 0;
+
+	/* If kgdb_initialized is -1 then we were passed kgdbwait. */
+	if (kgdb_initialized == -1)
+		need_break = 1;
+
+	/*
+	 * If we haven't tried to initialize KGDB yet, we need to call
+	 * kgdb_arch_init before moving onto the I/O.
+	 */
+	if (!kgdb_initialized)
+		kgdb_arch_init();
+
+	if (kgdb_initialized != 1) {
+		if (kgdb_io_ops.init && kgdb_io_ops.init()) {
+			/* When KGDB allows I/O via modules and the core
+			 * I/O init fails KGDB must default to defering the
+			 * I/O setup, and appropriately print an error about
+			 * it.
+			 */
+			printk(KERN_ERR "kgdb: Could not setup core I/O "
+			       "for KGDB.\n");
+			printk(KERN_INFO "kgdb: Defering I/O setup to kernel "
+			       "module.\n");
+			memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
+		} else {
+			printk(KERN_INFO "kgdb: Defering I/O setup to kernel "
+			       "module.\n");
+		}
+
+		kgdb_internal_init();
+
+		/* KGDB can assume that if kgdb_io_ops.init was defined that
+		 * panic registion should be performed at this time. This means
+		 * kgdb_io_ops.init did not come from a kernel module and was
+		 * initialized statically by a built in.
+		 */
+		if (kgdb_io_ops.init)
+			kgdb_register_for_panic();
+	}
+
+	/* Now do any late init of the I/O. */
+	if (kgdb_io_ops.late_init)
+		kgdb_io_ops.late_init();
+
+	if (need_break) {
+		printk(KERN_CRIT "kgdb: Waiting for connection from remote"
+		       " gdb...\n");
+		breakpoint();
+	}
+
+	return 0;
+}
+
+late_initcall(kgdb_late_entry);
+
+/*
+ * 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)
+{
+	if (kgdb_initialized != 1) {
+		kgdb_early_entry();
+		if (kgdb_initialized == 1)
+			printk(KERN_CRIT "Waiting for connection from remote "
+			       "gdb...\n");
+		else {
+			printk(KERN_CRIT "KGDB cannot initialize I/O yet.\n");
+			return;
+		}
+	}
+
+	atomic_set(&kgdb_setting_breakpoint, 1);
+	wmb();
+	BREAKPOINT();
+	wmb();
+	atomic_set(&kgdb_setting_breakpoint, 0);
+}
+
+EXPORT_SYMBOL(breakpoint);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs,
+			     struct tty_struct *tty)
+{
+	printk("Entering GDB stub\n");
+	breakpoint();
+}
+static struct sysrq_key_op sysrq_gdb_op = {
+	.handler = sysrq_handle_gdb,
+	.help_msg = "Gdb",
+	.action_msg = "GDB",
+};
+
+static int gdb_register_sysrq(void)
+{
+	printk("Registering GDB sysrq handler\n");
+	register_sysrq_key('g', &sysrq_gdb_op);
+	return 0;
+}
+
+module_init(gdb_register_sysrq);
+#endif
+
+#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 || atomic_read(&debugger_active) != 0)
+		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,
+};
+static int __init kgdb_console_init(void)
+{
+	register_console(&kgdbcons);
+	return 0;
+}
+
+console_initcall(kgdb_console_init);
+#endif
+
+static int __init opt_kgdb_enter(char *str)
+{
+	/* We've already done this by an explicit breakpoint() call. */
+	if (kgdb_initialized)
+		return 0;
+
+	/* Call breakpoint() which will take care of init. */
+	breakpoint();
+
+	return 0;
+}
+
+early_param("kgdbwait", opt_kgdb_enter);
diff -puN kernel/Makefile~core-lite kernel/Makefile
--- linux-2.6.13/kernel/Makefile~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/kernel/Makefile	2005-08-16 15:54:47.000000000 -0700
@@ -26,6 +26,7 @@ obj-$(CONFIG_STOP_MACHINE) += stop_machi
 obj-$(CONFIG_AUDIT) += audit.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_KGDB) += kgdb.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff -puN kernel/pid.c~core-lite kernel/pid.c
--- linux-2.6.13/kernel/pid.c~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/kernel/pid.c	2005-08-16 15:54:47.000000000 -0700
@@ -250,8 +250,13 @@ void switch_exec_pids(task_t *leader, ta
 /*
  * The pid hash table is scaled according to the amount of memory in the
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
- * more.
+ * more.  KGDB needs to know if this function has been called already,
+ * since we might have entered KGDB very early.
  */
+#ifdef CONFIG_KGDB
+int pidhash_init_done;
+#endif
+
 void __init pidhash_init(void)
 {
 	int i, j, pidhash_size;
@@ -273,6 +278,10 @@ void __init pidhash_init(void)
 		for (j = 0; j < pidhash_size; j++)
 			INIT_HLIST_HEAD(&pid_hash[i][j]);
 	}
+
+#ifdef CONFIG_KGDB
+	pidhash_init_done = 1;
+#endif
 }
 
 void __init pidmap_init(void)
diff -puN kernel/sched.c~core-lite kernel/sched.c
--- linux-2.6.13/kernel/sched.c~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/kernel/sched.c	2005-08-16 15:54:47.000000000 -0700
@@ -47,6 +47,7 @@
 #include <linux/syscalls.h>
 #include <linux/times.h>
 #include <linux/acct.h>
+#include <linux/kgdb.h>
 #include <asm/tlb.h>
 
 #include <asm/unistd.h>
@@ -5217,6 +5218,9 @@ void __might_sleep(char *file, int line)
 #if defined(in_atomic)
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
+	if (atomic_read(&debugger_active))
+		return;
+
 	if ((in_atomic() || irqs_disabled()) &&
 	    system_state == SYSTEM_RUNNING && !oops_in_progress) {
 		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
diff -puN lib/Kconfig.debug~core-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-16 15:54:47.000000000 -0700
@@ -159,3 +159,55 @@ config FRAME_POINTER
 	  If you don't debug the kernel, you can say N, but we may not be able
 	  to solve problems without frame pointers.
 
+config WANT_EXTRA_DEBUG_INFORMATION
+	bool
+	select DEBUG_INFO
+	select FRAME_POINTER if X86 && !X86_64
+	default n
+
+config KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	select WANT_EXTRA_DEBUG_INFORMATION
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb. It is strongly suggested that you enable
+	  DEBUG_INFO, and if available on your platform, FRAME_POINTER.
+	  Documentation of kernel debugger available at
+	  http://kgdb.sourceforge.net as well as in DocBook form
+	  in Documentation/DocBook/.  If unsure, say N.
+
+config KGDB_CONSOLE
+	bool "KGDB: 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 KGDB_ETH, if the
+	    ethernet driver runs into an error condition during use with KGDB
+	    it is possible to hit an infinite recusrion, causing the kernel
+	    to crash, and typically reboot.  For this reason, it is preferable
+	    to use NETCONSOLE in conjunction with KGDB_ETH instead of
+	    KGDB_CONSOLE.
+
+choice
+	prompt "Method for KGDB communication"
+	depends on KGDB
+	default KGDB_ONLY_MODULES
+	help
+	  There are a number of different ways in which you can communicate
+	  with KGDB.  The most common is via serial, with the 8250 driver
+	  (should your hardware have an 8250, or ns1655x style uart).
+	  Another option is to use the NETPOLL framework and UDP, should
+	  your ethernet card support this.  Other options may exist.
+	  You can elect to have one core I/O driver that is built into the
+	  kernel for debugging as the kernel is booting, or using only
+	  kernel modules.
+
+config KGDB_ONLY_MODULES
+	bool "KGDB: Use only kernel modules for I/O"
+	help
+	  Use only kernel modules to configure KGDB I/O after the
+	  kernel is booted.
+
+endchoice
diff -puN MAINTAINERS~core-lite MAINTAINERS
--- linux-2.6.13/MAINTAINERS~core-lite	2005-08-16 15:54:47.000000000 -0700
+++ linux-2.6.13-trini/MAINTAINERS	2005-08-16 15:54:47.000000000 -0700
@@ -1349,6 +1349,15 @@ L:	linux-kernel@vger.kernel.org
 L:	fastboot@osdl.org
 S:	Maintained
 
+KGDB
+P:	Tom Rini
+P:	Amit S. Kale
+M:	trini@kernel.crashing.org
+M:	amitkale@linsyssoft.com
+W:	http://sourceforge.net/projects/kgdb
+L:	kgdb-bugreport@lists.sourceforge.net
+S:	Maintained
+
 LANMEDIA WAN CARD DRIVER
 P:	Andrew Stanley-Jones
 M:	asj@lanmedia.com
_

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

* [patch 02/16] Add support for i386 platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
@ 2005-08-29 16:09   ` Tom Rini
  2005-08-29 19:55     ` [patch 2/3] x86_64: Run setup_per_cpu_areas and trap_init sooner Andi Kleen
  2005-08-29 16:09   ` [patch 03/16] Add support for PowerPC32 platforms to KGDB Tom Rini
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:09 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini


This adds the basic support for i386.  The only real changes outside of new
KGDB files and Makefile/related is that for support early on we must set some
traps sooner rather than later, but it is safe to always do this.  Also, to
break in as early as possible, i386 now calls parse_early_param() to
explicitly look at anything marked early_param().  We also add a few more
notify_die() calls in areas where KGDB needs to take a peek sometimes.
Finally, we add some labels to switch_to macros so that when backtracing we
can see where we really are.

---

 linux-2.6.13-trini/arch/i386/kernel/Makefile   |    1 
 linux-2.6.13-trini/arch/i386/kernel/kgdb-jmp.S |   74 +++++
 linux-2.6.13-trini/arch/i386/kernel/kgdb.c     |  301 +++++++++++++++++++++
 linux-2.6.13-trini/arch/i386/kernel/setup.c    |    3 
 linux-2.6.13-trini/arch/i386/kernel/traps.c    |   15 -
 linux-2.6.13-trini/arch/i386/mm/fault.c        |    4 
 linux-2.6.13-trini/include/asm-i386/kgdb.h     |   50 +++
 linux-2.6.13-trini/include/asm-i386/system.h   |   10 
 linux-2.6.13-trini/lib/Kconfig.debug           |    2 
 9 files changed, 452 insertions(+), 8 deletions(-)

diff -puN /dev/null arch/i386/kernel/kgdb.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/kgdb.c	2005-08-10 10:53:28.000000000 -0700
@@ -0,0 +1,301 @@
+/*
+ *
+ * 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) 2000-2001 VERITAS Software Corporation.
+ */
+/*
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  Updated by:	     Tom Rini <trini@kernel.crashing.org>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by
+ *  David Grothe <dave@gcom.com>
+ *  Additional support from Tigran Aivazian <tigran@sco.com>
+ */
+
+#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/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <asm/apicdef.h>
+#include <asm/desc.h>
+#include <asm/kdebug.h>
+
+#include "mach_ipi.h"
+
+/* Put the error code here just in case the user cares.  */
+int gdb_i386errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+int gdb_i386vector = -1;
+
+extern atomic_t cpu_doing_single_step;
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	gdb_regs[_ESP] = (int)(&regs->esp);
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}
+
+/*
+ * Extracts ebp, esp and eip values understandable by gdb from the values
+ * saved by switch_to.
+ * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
+ * prior to entering switch_to is 8 greater then the value that is saved.
+ * If switch_to changes, change following code appropriately.
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	gdb_regs[_EAX] = 0;
+	gdb_regs[_EBX] = 0;
+	gdb_regs[_ECX] = 0;
+	gdb_regs[_EDX] = 0;
+	gdb_regs[_ESI] = 0;
+	gdb_regs[_EDI] = 0;
+	gdb_regs[_EBP] = *(unsigned long *)p->thread.esp;
+	gdb_regs[_DS] = __KERNEL_DS;
+	gdb_regs[_ES] = __KERNEL_DS;
+	gdb_regs[_PS] = *(unsigned long *)(p->thread.esp + 4);
+	gdb_regs[_CS] = __KERNEL_CS;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+}
+
+static struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = {
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+	{ .enabled = 0 },
+};
+
+void kgdb_correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n":"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3):);
+	} while (0);
+	correctit = 0;
+	for (breakno = 0; breakno < 3; 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) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit)
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+	/* Disable hardware debugging while we are in kgdb */
+	asm volatile ("movl %0,%%db7": /* no output */ :"r" (0));
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_i386vector = e_vector;
+	gdb_i386errcode = err_code;
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+
+int kgdb_arch_handle_exception(int e_vector, int signo,
+			       int err_code, char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	long addr;
+	char *ptr;
+	int newPC, dr6;
+
+	switch (remcom_in_buffer[0]) {
+	case 'c':
+	case 's':
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &addr))
+			linux_regs->eip = addr;
+		newPC = linux_regs->eip;
+
+		/* clear the trace bit */
+		linux_regs->eflags &= ~TF_MASK;
+		atomic_set(&cpu_doing_single_step, -1);
+
+		/* set the trace bit if we're stepping */
+		if (remcom_in_buffer[0] == 's') {
+			linux_regs->eflags |= TF_MASK;
+			debugger_step = 1;
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+		}
+
+		asm volatile ("movl %%db6, %0\n":"=r" (dr6));
+		if (!(dr6 & 0x4000)) {
+			long breakno;
+			for (breakno = 0; breakno < 4; ++breakno) {
+				if (dr6 & (1 << breakno) &&
+				    breakinfo[breakno].type == 0) {
+					/* Set restore flag */
+					linux_regs->eflags |= X86_EFLAGS_RF;
+					break;
+				}
+			}
+		}
+		kgdb_correct_hw_break();
+		asm volatile ("movl %0, %%db6\n"::"r" (0));
+
+		return (0);
+	}			/* switch */
+	/* this means that we do not want to exit from the handler */
+	return -1;
+}
+
+/* Register KGDB with the i386die_chain so that we hook into all of the right
+ * spots. */
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd,
+		       void *ptr)
+{
+	struct die_args *args = ptr;
+	struct pt_regs *regs = args->regs;
+
+	/* Bad memory access? */
+	if (cmd == DIE_PAGE_FAULT && strcmp(args->str, "no context") == 0 &&
+	    atomic_read(&debugger_active) && kgdb_may_fault) {
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		return NOTIFY_STOP;
+	} else if (cmd == DIE_PAGE_FAULT &&
+		   strcmp(args->str, "page fault") == 0)
+		/* A normal page fault, ignore. */
+		return NOTIFY_DONE;
+	else if (cmd == DIE_NMI && atomic_read(&debugger_active)) {
+		/* CPU roundup */
+		kgdb_nmihook(smp_processor_id(), regs);
+		return NOTIFY_STOP;
+	} else if (cmd == DIE_NMI_IPI || user_mode(regs) ||
+		   (cmd == DIE_DEBUG && atomic_read(&debugger_active)))
+		/* Normal watchdog event or userspace debugging, or spurious
+		 * debug exception, ignore. */
+		return NOTIFY_DONE;
+
+	kgdb_handle_exception(args->trapnr, args->signr, args->err, regs);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+};
+
+int kgdb_arch_init(void)
+{
+	notifier_chain_register(&i386die_chain, &kgdb_notifier);
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0xcc},
+};
diff -puN /dev/null arch/i386/kernel/kgdb-jmp.S
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/kgdb-jmp.S	2005-08-08 12:18:19.000000000 -0700
@@ -0,0 +1,74 @@
+/*
+ * arch/i386/kernel/kgdb-jmp.S
+ *
+ * Save and restore system registers so that within a limited frame we
+ * may have a fault and "jump back" to a known safe location.
+ *
+ * Author: George Anzinger <george@mvista.com>
+ *
+ * Cribbed from glibc, which carries the following:
+ * Copyright (C) 1996, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2005 by MontaVista Software.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <linux/linkage.h>
+
+#define PCOFF		0
+#define LINKAGE		4		/* just the return address */
+#define PTR_SIZE	4
+#define PARMS		LINKAGE		/* no space for saved regs */
+#define JMPBUF		PARMS
+#define VAL		JMPBUF+PTR_SIZE
+
+#define JB_BX		0
+#define JB_SI		1
+#define JB_DI		2
+#define JB_BP		3
+#define JB_SP		4
+#define JB_PC		5
+
+/* This must be called prior to kgdb_fault_longjmp and
+ * kgdb_fault_longjmp must not be called outside of the context of the
+ * last call to kgdb_fault_setjmp.
+ * kgdb_fault_setjmp(int *jmp_buf[6])
+ */
+ENTRY(kgdb_fault_setjmp)
+	movl JMPBUF(%esp), %eax
+
+	/* Save registers.  */
+	movl	%ebx, (JB_BX*4)(%eax)
+	movl	%esi, (JB_SI*4)(%eax)
+	movl	%edi, (JB_DI*4)(%eax)
+	/* Save SP as it will be after we return.  */
+	leal	JMPBUF(%esp), %ecx
+	movl	%ecx, (JB_SP*4)(%eax)
+	movl	PCOFF(%esp), %ecx	/* Save PC we are returning to now.  */
+	movl	%ecx, (JB_PC*4)(%eax)
+	movl	%ebp, (JB_BP*4)(%eax)	/* Save caller's frame pointer.  */
+
+	/* Restore state so we can now try the access. */
+	movl	JMPBUF(%esp), %ecx	/* User's jmp_buf in %ecx.  */
+	/* Save the return address now.  */
+	movl	(JB_PC*4)(%ecx), %edx
+	/* Restore registers.  */
+	movl	$0, %eax
+	movl	(JB_SP*4)(%ecx), %esp
+	jmp	*%edx		/* Jump to saved PC. */
+
+/* kgdb_fault_longjmp(int *jmp_buf[6]) */
+ENTRY(kgdb_fault_longjmp)
+	movl	JMPBUF(%esp), %ecx	/* User's jmp_buf in %ecx.  */
+	/* Save the return address now.  */
+	movl	(JB_PC*4)(%ecx), %edx
+	/* Restore registers.  */
+	movl	(JB_BX*4)(%ecx), %ebx
+	movl	(JB_SI*4)(%ecx), %esi
+	movl	(JB_DI*4)(%ecx), %edi
+	movl	(JB_BP*4)(%ecx), %ebp
+	movl	$1, %eax
+	movl	(JB_SP*4)(%ecx), %esp
+	jmp	*%edx		/* Jump to saved PC. */
diff -puN arch/i386/kernel/Makefile~i386-lite arch/i386/kernel/Makefile
--- linux-2.6.13/arch/i386/kernel/Makefile~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/Makefile	2005-08-08 12:18:19.000000000 -0700
@@ -34,6 +34,7 @@ obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -puN arch/i386/kernel/setup.c~i386-lite arch/i386/kernel/setup.c
--- linux-2.6.13/arch/i386/kernel/setup.c~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/setup.c	2005-08-08 12:18:19.000000000 -0700
@@ -147,6 +147,7 @@ EXPORT_SYMBOL(ist_info);
 struct e820map e820;
 
 extern void early_cpu_init(void);
+extern void early_trap_init(void);
 extern void dmi_scan_machine(void);
 extern void generic_apic_probe(char *);
 extern int root_mountflags;
@@ -1473,6 +1474,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();
 
 	/*
 	 * FIXME: This isn't an official loader_type right
@@ -1529,6 +1531,7 @@ void __init setup_arch(char **cmdline_p)
 	data_resource.end = virt_to_phys(_edata)-1;
 
 	parse_cmdline_early(cmdline_p);
+	parse_early_param();
 
 	max_low_pfn = setup_memory();
 
diff -puN arch/i386/kernel/traps.c~i386-lite arch/i386/kernel/traps.c
--- linux-2.6.13/arch/i386/kernel/traps.c~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/traps.c	2005-08-08 12:18:19.000000000 -0700
@@ -337,7 +337,7 @@ void die(const char * str, struct pt_reg
 #endif
 		if (nl)
 			printk("\n");
-	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+		notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
 		show_registers(regs);
   	} else
 		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
@@ -568,6 +568,7 @@ static DEFINE_SPINLOCK(nmi_print_lock);
 
 void die_nmi (struct pt_regs *regs, const char *msg)
 {
+	notify_die(DIE_NMIWATCHDOG, "nmi watchdog", regs, 0, 2, SIGPWR);
 	spin_lock(&nmi_print_lock);
 	/*
 	* We are in trouble anyway, lets at least try
@@ -757,6 +758,7 @@ fastcall void do_debug(struct pt_regs * 
 	 */
 clear_dr7:
 	set_debugreg(0, 7);
+	notify_die(DIE_DEBUG, "debug2", regs, condition, error_code, SIGTRAP);
 	return;
 
 debug_vm86:
@@ -1058,6 +1060,12 @@ static void __init set_task_gate(unsigne
 	_set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
 }
 
+/* Some traps need to be set early. */
+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);
+}
 
 void __init trap_init(void)
 {
@@ -1074,10 +1082,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-5 can be called from all */
-	set_system_gate(4,&overflow);
+	set_system_gate(4,&overflow); /* int4/5 can be called from all */
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
 	set_trap_gate(7,&device_not_available);
@@ -1087,7 +1093,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 -puN arch/i386/mm/fault.c~i386-lite arch/i386/mm/fault.c
--- linux-2.6.13/arch/i386/mm/fault.c~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/mm/fault.c	2005-08-08 12:18:19.000000000 -0700
@@ -424,6 +424,10 @@ no_context:
  	if (is_prefetch(regs, address, error_code))
  		return;
 
+	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
+				SIGSEGV) == NOTIFY_STOP)
+		return;
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
diff -puN /dev/null include/asm-i386/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-i386/kgdb.h	2005-08-10 10:53:33.000000000 -0700
@@ -0,0 +1,50 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+/************************************************************************/
+/* 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
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES		64
+/* Number of bytes of registers we need to save for a setjmp/longjmp. */
+#define NUMCRITREGBYTES		24
+
+/*
+ *  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.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 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 */
+};
+
+#define BREAKPOINT()		asm("   int $3");
+#define BREAK_INSTR_SIZE	1
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
+#endif				/* _ASM_KGDB_H_ */
+#endif				/* __KERNEL__ */
diff -puN include/asm-i386/system.h~i386-lite include/asm-i386/system.h
--- linux-2.6.13/include/asm-i386/system.h~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/include/asm-i386/system.h	2005-08-08 12:18:19.000000000 -0700
@@ -12,9 +12,13 @@
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
 extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
+/* sleeping_thread_to_gdb_regs depends on this code. Correct it if you change
+ * any of the following */
 #define switch_to(prev,next,last) do {					\
 	unsigned long esi,edi;						\
-	asm volatile("pushfl\n\t"					\
+	asm volatile(".globl __switch_to_begin\n"			\
+		     "__switch_to_begin:"				\
+		     "pushfl\n\t"					\
 		     "pushl %%ebp\n\t"					\
 		     "movl %%esp,%0\n\t"	/* save ESP */		\
 		     "movl %5,%%esp\n\t"	/* restore ESP */	\
@@ -23,7 +27,9 @@ extern struct task_struct * FASTCALL(__s
 		     "jmp __switch_to\n"				\
 		     "1:\t"						\
 		     "popl %%ebp\n\t"					\
-		     "popfl"						\
+		     "popfl\n"						\
+		     ".globl __switch_to_end\n"				\
+		     "__switch_to_end:\n"				\
 		     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),	\
 		      "=a" (last),"=S" (esi),"=D" (edi)			\
 		     :"m" (next->thread.esp),"m" (next->thread.eip),	\
diff -puN lib/Kconfig.debug~i386-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~i386-lite	2005-08-08 12:18:19.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-10 10:55:09.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL
+	depends on DEBUG_KERNEL && (X86)
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
_

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

* [patch 03/16] Add support for PowerPC32 platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
  2005-08-29 16:09   ` [patch 02/16] Add support for i386 platforms to KGDB Tom Rini
@ 2005-08-29 16:09   ` Tom Rini
  2005-08-29 16:09   ` [patch 04/16] I/O driver for 8250-compatible UARTs Tom Rini
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:09 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, paulus, kato.takeharu


This adds basic KGDB support to ppc32 (classic, e500 and 4xx), and support
for kgdb8250 to a number of boards.  This was done mostly myself with some
help from Scott Hall for e500 and Frank Rowand pointed out some parts as he
did the ppc64 code, as well as Takeharu KATO <kato.takeharu@jp.fujitsu.com>
for some of the 4xx code and testing.

Index: linux-2.6.13/arch/ppc/Kconfig.debug
===================================================================
--- linux-2.6.13.orig/arch/ppc/Kconfig.debug
+++ linux-2.6.13/arch/ppc/Kconfig.debug
@@ -2,42 +2,6 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config KGDB
-	bool "Include kgdb kernel debugger"
-	depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx)
-	select DEBUG_INFO
-	help
-	  Include in-kernel hooks for kgdb, the Linux kernel source level
-	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
-	  Unless you are intending to debug the kernel, say N here.
-
-choice
-	prompt "Serial Port"
-	depends on KGDB
-	default KGDB_TTYS1
-
-config KGDB_TTYS0
-	bool "ttyS0"
-
-config KGDB_TTYS1
-	bool "ttyS1"
-
-config KGDB_TTYS2
-	bool "ttyS2"
-
-config KGDB_TTYS3
-	bool "ttyS3"
-
-endchoice
-
-config KGDB_CONSOLE
-	bool "Enable serial console thru kgdb port"
-	depends on KGDB && 8xx || CPM2
-	help
-	  If you enable this, all serial console messages will be sent
-	  over the gdb stub.
-	  If unsure, say N.
-
 config XMON
 	bool "Include xmon kernel debugger"
 	depends on DEBUG_KERNEL
Index: linux-2.6.13/arch/ppc/kernel/kgdb.c
===================================================================
--- /dev/null
+++ linux-2.6.13/arch/ppc/kernel/kgdb.c
@@ -0,0 +1,329 @@
+/*
+ * arch/ppc/kernel/kgdb.c
+ *
+ * PowerPC backend to the KGDB stub.
+ *
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
+ * Copyright (C) 2003 Timesys Corporation.
+ * 2004 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <asm/current.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+
+/*
+ * This table contains the mapping between PowerPC hardware trap types, and
+ * signals, which are primarily what GDB understands.  GDB and the kernel
+ * don't always agree on values, so we use constants taken from gdb-6.2.
+ */
+static struct hard_trap_info
+{
+	unsigned int tt;		/* Trap type code for powerpc */
+	unsigned char signo;		/* Signal that we map this trap into */
+} hard_trap_info[] = {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+	{ 0x0100, 0x02 /* SIGINT */  },		/* critical input interrupt */
+	{ 0x0200, 0x0b /* SIGSEGV */ },		/* machine check */
+	{ 0x0300, 0x0b /* SIGSEGV */ },		/* data storage */
+	{ 0x0400, 0x0a /* SIGBUS */  },		/* instruction storage */
+	{ 0x0500, 0x02 /* SIGINT */  },		/* interrupt */
+	{ 0x0600, 0x0a /* SIGBUS */  },		/* alignment */
+	{ 0x0700, 0x04 /* SIGILL */  },		/* program */
+	{ 0x0800, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0900, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0a00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0b00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0c00, 0x14 /* SIGCHLD */ },		/* syscall */
+	{ 0x0d00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0e00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0f00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x2002, 0x05 /* SIGTRAP */},		/* debug */
+#else
+	{ 0x0200, 0x0b /* SIGSEGV */ },		/* machine check */
+	{ 0x0300, 0x0b /* SIGSEGV */ },		/* address error (store) */
+	{ 0x0400, 0x0a /* SIGBUS */ },		/* instruction bus error */
+	{ 0x0500, 0x02 /* SIGINT */ },		/* interrupt */
+	{ 0x0600, 0x0a /* SIGBUS */ },		/* alingment */
+	{ 0x0700, 0x05 /* SIGTRAP */ },		/* breakpoint trap */
+	{ 0x0800, 0x08 /* SIGFPE */},		/* fpu unavail */
+	{ 0x0900, 0x0e /* SIGALRM */ },		/* decrementer */
+	{ 0x0a00, 0x04 /* SIGILL */ },		/* reserved */
+	{ 0x0b00, 0x04 /* SIGILL */ },		/* reserved */
+	{ 0x0c00, 0x14 /* SIGCHLD */ },		/* syscall */
+	{ 0x0d00, 0x05 /* SIGTRAP */ },		/* single-step/watch */
+	{ 0x0e00, 0x08 /* SIGFPE */ },		/* fp assist */
+#endif
+	{ 0x0000, 0x000 }			/* Must be last */
+};
+
+extern atomic_t cpu_doing_single_step;
+
+static int computeSignal(unsigned int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;		/* default for things we don't know about */
+}
+
+/* KGDB functions to use existing PowerPC hooks. */
+static void kgdb_debugger(struct pt_regs *regs)
+{
+	kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+}
+
+static int kgdb_breakpoint(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+
+	if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
+		regs->nip += 4;
+
+	return 1;
+}
+
+static int kgdb_singlestep(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+	return 1;
+}
+
+int kgdb_iabr_match(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+	return 1;
+}
+
+int kgdb_dabr_match(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+	return 1;
+}
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg;
+	unsigned long *ptr = gdb_regs;
+
+	memset(gdb_regs, 0, MAXREG * 4);
+
+	for (reg = 0; reg < 32; reg++)
+		*(ptr++) = regs->gpr[reg];
+
+#ifndef CONFIG_E500
+	for (reg = 0; reg < 64; reg++)
+		*(ptr++) = 0;
+#else
+	for (reg = 0; reg < 32; reg++)
+		*(ptr++) = current->thread.evr[reg];
+#endif
+
+	*(ptr++) = regs->nip;
+	*(ptr++) = regs->msr;
+	*(ptr++) = regs->ccr;
+	*(ptr++) = regs->link;
+	*(ptr++) = regs->ctr;
+	*(ptr++) = regs->xer;
+
+#ifdef CONFIG_SPE
+	/* u64 acc */
+	*(ptr++) = (current->thread.acc >> 32);
+	*(ptr++) = (current->thread.acc & 0xffffffff);
+	*(ptr++) = current->thread.spefscr;
+#endif
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
+						  STACK_FRAME_OVERHEAD);
+	int reg;
+	unsigned long *ptr = gdb_regs;
+
+	memset(gdb_regs, 0, MAXREG * 4);
+
+	/* Regs GPR0-2 */
+	for (reg = 0; reg < 3; reg++)
+		*(ptr++) = regs->gpr[reg];
+
+	/* Regs GPR3-13 are not saved */
+	for (reg = 3; reg < 14; reg++)
+		*(ptr++) = 0;
+
+	/* Regs GPR14-31 */
+	for (reg = 14; reg < 32; reg++)
+		*(ptr++) = regs->gpr[reg];
+
+#ifndef CONFIG_E500
+	for (reg = 0; reg < 64; reg++)
+		*(ptr++) = 0;
+#else
+	for (reg = 0; reg < 32; reg++)
+		*(ptr++) = current->thread.evr[reg];
+#endif
+
+	*(ptr++) = regs->nip;
+	*(ptr++) = regs->msr;
+	*(ptr++) = regs->ccr;
+	*(ptr++) = regs->link;
+	*(ptr++) = regs->ctr;
+	*(ptr++) = regs->xer;
+
+#ifdef CONFIG_SPE
+	/* u64 acc */
+	*(ptr++) = (current->thread.acc >> 32);
+	*(ptr++) = (current->thread.acc & 0xffffffff);
+	*(ptr++) = current->thread.spefscr;
+#endif
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg;
+	unsigned long *ptr = gdb_regs;
+#ifdef CONFIG_SPE
+	union {
+		u32 v32[2];
+		u64 v64;
+	} u;
+#endif
+
+	for (reg = 0; reg < 32; reg++)
+		regs->gpr[reg] = *(ptr++);
+
+#ifndef CONFIG_E500
+	for (reg = 0; reg < 64; reg++)
+		ptr++;
+#else
+	for (reg = 0; reg < 32; reg++)
+		current->thread.evr[reg] = *(ptr++);
+#endif
+
+	regs->nip = *(ptr++);
+	regs->msr = *(ptr++);
+	regs->ccr = *(ptr++);
+	regs->link = *(ptr++);
+	regs->ctr = *(ptr++);
+	regs->xer = *(ptr++);
+
+#ifdef CONFIG_SPE
+	/* u64 acc */
+	u.v32[0] = *(ptr++);
+	u.v32[1] = *(ptr++);
+	current->thread.acc = u.v64;
+	current->thread.spefscr = *(ptr++);
+#endif
+}
+
+/*
+ * Save/restore state in case a memory access causes a fault.
+ */
+int kgdb_fault_setjmp(unsigned long *curr_context)
+{
+	__asm__ __volatile__("mflr 0; stw 0,0(%0);"
+			     "stw 1,4(%0); stw 2,8(%0);"
+			     "mfcr 0; stw 0,12(%0);"
+			     "stmw 13,16(%0)"::"r"(curr_context));
+	return 0;
+}
+
+void kgdb_fault_longjmp(unsigned long *curr_context)
+{
+	__asm__ __volatile__("lmw 13,16(%0);"
+			     "lwz 0,12(%0); mtcrf 0x38,0;"
+			     "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
+			     "mtlr 0; mr 3,1"::"r"(curr_context));
+}
+
+/*
+ * This function does PoerPC specific procesing for interfacing to gdb.
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+			       char *remcom_in_buffer, char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	char *ptr = &remcom_in_buffer[1];
+	unsigned long addr;
+
+	switch (remcom_in_buffer[0])
+		{
+		/*
+		 * sAA..AA   Step one instruction from AA..AA
+		 * This will return an error to gdb ..
+		 */
+		case 's':
+		case 'c':
+			/* handle the optional parameter */
+			if (kgdb_hex2long (&ptr, &addr))
+				linux_regs->nip = addr;
+
+			atomic_set(&cpu_doing_single_step, -1);
+			/* set the trace bit if we're stepping */
+			if (remcom_in_buffer[0] == 's') {
+#if defined (CONFIG_40x) || defined(CONFIG_BOOKE)
+				mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) |
+						DBCR0_IC | DBCR0_IDM);
+				linux_regs->msr |= MSR_DE;
+#else
+				linux_regs->msr |= MSR_SE;
+#endif
+				debugger_step = 1;
+				if (kgdb_contthread)
+					atomic_set(&cpu_doing_single_step,
+							smp_processor_id());
+			}
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * Global data
+ */
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08},
+};
+
+int kgdb_arch_init(void)
+{
+	debugger = kgdb_debugger;
+	debugger_bpt = kgdb_breakpoint;
+	debugger_sstep = kgdb_singlestep;
+	debugger_iabr_match = kgdb_iabr_match;
+	debugger_dabr_match = kgdb_dabr_match;
+
+	return 0;
+}
+
+arch_initcall(kgdb_arch_init);
Index: linux-2.6.13/arch/ppc/kernel/Makefile
===================================================================
--- linux-2.6.13.orig/arch/ppc/kernel/Makefile
+++ linux-2.6.13/arch/ppc/kernel/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_POWER4)		+= cpu_setup_power
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
-obj-$(CONFIG_KGDB)		+= ppc-stub.o
+obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
Index: linux-2.6.13/arch/ppc/kernel/ppc-stub.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/kernel/ppc-stub.c
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * ppc-stub.c:  KGDB support for the Linux kernel.
- *
- * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
- * some stuff borrowed from Paul Mackerras' xmon
- * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu)
- *
- * Modifications to run under Linux
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * This file originally came from the gdb sources, and the
- * copyright notices have been retained below.
- */
-
-/****************************************************************************
-
-		THIS SOFTWARE IS NOT COPYRIGHTED
-
-   HP offers the following for use in the public domain.  HP makes no
-   warranty with regard to the software or its performance and the
-   user accepts the software "AS IS" with all faults.
-
-   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
-   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-****************************************************************************/
-
-/****************************************************************************
- *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
- *
- *  Module name: remcom.c $
- *  Revision: 1.34 $
- *  Date: 91/03/09 12:29:49 $
- *  Contributor:     Lake Stevens Instrument Division$
- *
- *  Description:     low level support for gdb debugger. $
- *
- *  Considerations:  only works on target hardware $
- *
- *  Written by:      Glenn Engel $
- *  ModuleState:     Experimental $
- *
- *  NOTES:           See Below $
- *
- *  Modified for SPARC by Stu Grossman, Cygnus Support.
- *
- *  This code has been extensively tested on the Fujitsu SPARClite demo board.
- *
- *  To enable debugger support, two things need to happen.  One, a
- *  call to set_debug_traps() is necessary in order to allow any breakpoints
- *  or error conditions to be properly intercepted and reported to gdb.
- *  Two, a breakpoint needs to be generated to begin communication.  This
- *  is most easily accomplished by a call to breakpoint().  Breakpoint()
- *  simulates a breakpoint by executing a trap #1.
- *
- *************
- *
- *    The following gdb commands are supported:
- *
- * command          function		          Return value
- *
- *    g             return the value of the CPU registers  hex data or ENN
- *    G             set the value of the CPU registers     OK or ENN
- *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
- *
- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
- *
- *    c             Resume at current address              SNN   ( signal NN)
- *    cAA..AA       Continue at address AA..AA             SNN
- *
- *    s             Step one instruction                   SNN
- *    sAA..AA       Step one instruction from AA..AA       SNN
- *
- *    k             kill
- *
- *    ?             What was the last sigval ?             SNN   (signal NN)
- *
- *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
- *							   baud rate
- *
- * All commands and responses are sent with a packet which includes a
- * checksum.  A packet consists of
- *
- * $<packet info>#<checksum>.
- *
- * where
- * <packet info> :: <characters representing the command or response>
- * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
- *
- * When a packet is received, it is first acknowledged with either '+' or '-'.
- * '+' indicates a successful transfer.  '-' indicates a failed transfer.
- *
- * Example:
- *
- * Host:                  Reply:
- * $m0,10#2a               +$00010203040506070809101112131415#42
- *
- ****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-
-#include <asm/cacheflush.h>
-#include <asm/system.h>
-#include <asm/signal.h>
-#include <asm/kgdb.h>
-#include <asm/pgtable.h>
-#include <asm/ptrace.h>
-
-void breakinst(void);
-
-/*
- * BUFMAX defines the maximum number of characters in inbound/outbound buffers
- * at least NUMREGBYTES*2 are needed for register packets
- */
-#define BUFMAX 2048
-static char remcomInBuffer[BUFMAX];
-static char remcomOutBuffer[BUFMAX];
-
-static int initialized;
-static int kgdb_active;
-static int kgdb_started;
-static u_int fault_jmp_buf[100];
-static int kdebug;
-
-
-static const char hexchars[]="0123456789abcdef";
-
-/* Place where we save old trap entries for restoration - sparc*/
-/* struct tt_entry kgdb_savettable[256]; */
-/* typedef void (*trapfunc_t)(void); */
-
-static void kgdb_fault_handler(struct pt_regs *regs);
-static int handle_exception (struct pt_regs *regs);
-
-#if 0
-/* Install an exception handler for kgdb */
-static void exceptionHandler(int tnum, unsigned int *tfunc)
-{
-	/* We are dorking with a live trap table, all irqs off */
-}
-#endif
-
-int
-kgdb_setjmp(long *buf)
-{
-	asm ("mflr 0; stw 0,0(%0);"
-	     "stw 1,4(%0); stw 2,8(%0);"
-	     "mfcr 0; stw 0,12(%0);"
-	     "stmw 13,16(%0)"
-	     : : "r" (buf));
-	/* XXX should save fp regs as well */
-	return 0;
-}
-void
-kgdb_longjmp(long *buf, int val)
-{
-	if (val == 0)
-		val = 1;
-	asm ("lmw 13,16(%0);"
-	     "lwz 0,12(%0); mtcrf 0x38,0;"
-	     "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
-	     "mtlr 0; mr 3,%1"
-	     : : "r" (buf), "r" (val));
-}
-/* Convert ch from a hex digit to an int */
-static int
-hex(unsigned 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;
-}
-
-/* Convert the memory pointed to by mem into hex, placing result in buf.
- * Return a pointer to the last char put in buf (null), in case of mem fault,
- * return 0.
- */
-static unsigned char *
-mem2hex(const char *mem, char *buf, int count)
-{
-	unsigned char ch;
-	unsigned short tmp_s;
-	unsigned long tmp_l;
-
-	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
-		debugger_fault_handler = kgdb_fault_handler;
-
-		/* Accessing 16 bit and 32 bit objects in a single
-		** load instruction is required to avoid bad side
-		** effects for some IO registers.
-		*/
-
-		if ((count == 2) && (((long)mem & 1) == 0)) {
-			tmp_s = *(unsigned short *)mem;
-			mem += 2;
-			*buf++ = hexchars[(tmp_s >> 12) & 0xf];
-			*buf++ = hexchars[(tmp_s >> 8) & 0xf];
-			*buf++ = hexchars[(tmp_s >> 4) & 0xf];
-			*buf++ = hexchars[tmp_s & 0xf];
-
-		} else if ((count == 4) && (((long)mem & 3) == 0)) {
-			tmp_l = *(unsigned int *)mem;
-			mem += 4;
-			*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 {
-			while (count-- > 0) {
-				ch = *mem++;
-				*buf++ = hexchars[ch >> 4];
-				*buf++ = hexchars[ch & 0xf];
-			}
-		}
-
-	} else {
-		/* error condition */
-	}
-	debugger_fault_handler = NULL;
-	*buf = 0;
-	return buf;
-}
-
-/* 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.
-*/
-static char *
-hex2mem(char *buf, char *mem, int count)
-{
-	unsigned char ch;
-	int i;
-	char *orig_mem;
-	unsigned short tmp_s;
-	unsigned long tmp_l;
-
-	orig_mem = mem;
-
-	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
-		debugger_fault_handler = kgdb_fault_handler;
-
-		/* Accessing 16 bit and 32 bit objects in a single
-		** store instruction is required to avoid bad side
-		** effects for some IO registers.
-		*/
-
-		if ((count == 2) && (((long)mem & 1) == 0)) {
-			tmp_s = hex(*buf++) << 12;
-			tmp_s |= hex(*buf++) << 8;
-			tmp_s |= hex(*buf++) << 4;
-			tmp_s |= hex(*buf++);
-
-			*(unsigned short *)mem = tmp_s;
-			mem += 2;
-
-		} else if ((count == 4) && (((long)mem & 3) == 0)) {
-			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++);
-
-			*(unsigned long *)mem = tmp_l;
-			mem += 4;
-
-		} else {
-			for (i=0; i<count; i++) {
-				ch = hex(*buf++) << 4;
-				ch |= hex(*buf++);
-				*mem++ = ch;
-			}
-		}
-
-
-		/*
-		** Flush the data cache, invalidate the instruction cache.
-		*/
-		flush_icache_range((int)orig_mem, (int)orig_mem + count - 1);
-
-	} else {
-		/* error condition */
-	}
-	debugger_fault_handler = NULL;
-	return mem;
-}
-
-/*
- * While we find nice hex chars, build an int.
- * Return number of chars processed.
- */
-static int
-hexToInt(char **ptr, int *intValue)
-{
-	int numChars = 0;
-	int hexValue;
-
-	*intValue = 0;
-
-	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
-		debugger_fault_handler = kgdb_fault_handler;
-		while (**ptr) {
-			hexValue = hex(**ptr);
-			if (hexValue < 0)
-				break;
-
-			*intValue = (*intValue << 4) | hexValue;
-			numChars ++;
-
-			(*ptr)++;
-		}
-	} else {
-		/* error condition */
-	}
-	debugger_fault_handler = NULL;
-
-	return (numChars);
-}
-
-/* scan for the sequence $<data>#<checksum> */
-static void
-getpacket(char *buffer)
-{
-	unsigned char checksum;
-	unsigned char xmitcsum;
-	int i;
-	int count;
-	unsigned char ch;
-
-	do {
-		/* wait around for the start character, ignore all other
-		 * characters */
-		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
-
-		checksum = 0;
-		xmitcsum = -1;
-
-		count = 0;
-
-		/* now, read until a # or end of buffer is found */
-		while (count < BUFMAX) {
-			ch = getDebugChar() & 0x7f;
-			if (ch == '#')
-				break;
-			checksum = checksum + ch;
-			buffer[count] = ch;
-			count = count + 1;
-		}
-
-		if (count >= BUFMAX)
-			continue;
-
-		buffer[count] = 0;
-
-		if (ch == '#') {
-			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
-			xmitcsum |= hex(getDebugChar() & 0x7f);
-			if (checksum != xmitcsum)
-				putDebugChar('-');	/* failed checksum */
-			else {
-				putDebugChar('+'); /* successful transfer */
-				/* if a sequence char is present, reply the ID */
-				if (buffer[2] == ':') {
-					putDebugChar(buffer[0]);
-					putDebugChar(buffer[1]);
-					/* remove sequence chars from buffer */
-					count = strlen(buffer);
-					for (i=3; i <= count; i++)
-						buffer[i-3] = buffer[i];
-				}
-			}
-		}
-	} while (checksum != xmitcsum);
-}
-
-/* send the packet in buffer. */
-static void putpacket(unsigned char *buffer)
-{
-	unsigned char checksum;
-	int count;
-	unsigned char ch, recv;
-
-	/* $<packet info>#<checksum>. */
-	do {
-		putDebugChar('$');
-		checksum = 0;
-		count = 0;
-
-		while ((ch = buffer[count])) {
-			putDebugChar(ch);
-			checksum += ch;
-			count += 1;
-		}
-
-		putDebugChar('#');
-		putDebugChar(hexchars[checksum >> 4]);
-		putDebugChar(hexchars[checksum & 0xf]);
-		recv = getDebugChar();
-	} while ((recv & 0x7f) != '+');
-}
-
-static void kgdb_flush_cache_all(void)
-{
-	flush_instruction_cache();
-}
-
-/* Set up exception handlers for tracing and breakpoints
- * [could be called kgdb_init()]
- */
-void set_debug_traps(void)
-{
-#if 0
-	unsigned char c;
-
-	save_and_cli(flags);
-
-	/* In case GDB is started before us, ack any packets (presumably
-	 * "$?#xx") sitting there.
-	 *
-	 * I've found this code causes more problems than it solves,
-	 * so that's why it's commented out.  GDB seems to work fine
-	 * now starting either before or after the kernel   -bwb
-	 */
-
-	while((c = getDebugChar()) != '$');
-	while((c = getDebugChar()) != '#');
-	c = getDebugChar(); /* eat first csum byte */
-	c = getDebugChar(); /* eat second csum byte */
-	putDebugChar('+'); /* ack it */
-#endif
-	debugger = kgdb;
-	debugger_bpt = kgdb_bpt;
-	debugger_sstep = kgdb_sstep;
-	debugger_iabr_match = kgdb_iabr_match;
-	debugger_dabr_match = kgdb_dabr_match;
-
-	initialized = 1;
-}
-
-static void kgdb_fault_handler(struct pt_regs *regs)
-{
-	kgdb_longjmp((long*)fault_jmp_buf, 1);
-}
-
-int kgdb_bpt(struct pt_regs *regs)
-{
-	return handle_exception(regs);
-}
-
-int kgdb_sstep(struct pt_regs *regs)
-{
-	return handle_exception(regs);
-}
-
-void kgdb(struct pt_regs *regs)
-{
-	handle_exception(regs);
-}
-
-int kgdb_iabr_match(struct pt_regs *regs)
-{
-	printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n");
-	return handle_exception(regs);
-}
-
-int kgdb_dabr_match(struct pt_regs *regs)
-{
-	printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n");
-	return handle_exception(regs);
-}
-
-/* Convert the hardware trap type code to a unix signal number. */
-/*
- * This table contains the mapping between PowerPC hardware trap types, and
- * signals, which are primarily what GDB understands.
- */
-static struct hard_trap_info
-{
-	unsigned int tt;		/* Trap type code for powerpc */
-	unsigned char signo;		/* Signal that we map this trap into */
-} hard_trap_info[] = {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
-	{ 0x100, SIGINT  },		/* critical input interrupt */
-	{ 0x200, SIGSEGV },		/* machine check */
-	{ 0x300, SIGSEGV },		/* data storage */
-	{ 0x400, SIGBUS  },		/* instruction storage */
-	{ 0x500, SIGINT  },		/* interrupt */
-	{ 0x600, SIGBUS  },		/* alignment */
-	{ 0x700, SIGILL  },		/* program */
-	{ 0x800, SIGILL  },		/* reserved */
-	{ 0x900, SIGILL  },		/* reserved */
-	{ 0xa00, SIGILL  },		/* reserved */
-	{ 0xb00, SIGILL  },		/* reserved */
-	{ 0xc00, SIGCHLD },		/* syscall */
-	{ 0xd00, SIGILL  },		/* reserved */
-	{ 0xe00, SIGILL  },		/* reserved */
-	{ 0xf00, SIGILL  },		/* reserved */
-	/*
-	** 0x1000  PIT
-	** 0x1010  FIT
-	** 0x1020  watchdog
-	** 0x1100  data TLB miss
-	** 0x1200  instruction TLB miss
-	*/
-	{ 0x2002, SIGTRAP},		/* debug */
-#else
-	{ 0x200, SIGSEGV },		/* machine check */
-	{ 0x300, SIGSEGV },		/* address error (store) */
-	{ 0x400, SIGBUS },		/* instruction bus error */
-	{ 0x500, SIGINT },		/* interrupt */
-	{ 0x600, SIGBUS },		/* alingment */
-	{ 0x700, SIGTRAP },		/* breakpoint trap */
-	{ 0x800, SIGFPE },		/* fpu unavail */
-	{ 0x900, SIGALRM },		/* decrementer */
-	{ 0xa00, SIGILL },		/* reserved */
-	{ 0xb00, SIGILL },		/* reserved */
-	{ 0xc00, SIGCHLD },		/* syscall */
-	{ 0xd00, SIGTRAP },		/* single-step/watch */
-	{ 0xe00, SIGFPE },		/* fp assist */
-#endif
-	{ 0, 0}				/* Must be last */
-
-};
-
-static int computeSignal(unsigned int tt)
-{
-	struct hard_trap_info *ht;
-
-	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
-		if (ht->tt == tt)
-			return ht->signo;
-
-	return SIGHUP; /* default for things we don't know about */
-}
-
-#define PC_REGNUM 64
-#define SP_REGNUM 1
-
-/*
- * This function does all command processing for interfacing to gdb.
- */
-static int
-handle_exception (struct pt_regs *regs)
-{
-	int sigval;
-	int addr;
-	int length;
-	char *ptr;
-	unsigned int msr;
-
-	/* We don't handle user-mode breakpoints. */
-	if (user_mode(regs))
-		return 0;
-
-	if (debugger_fault_handler) {
-		debugger_fault_handler(regs);
-		panic("kgdb longjump failed!\n");
-	}
-	if (kgdb_active) {
-		printk(KERN_ERR "interrupt while in kgdb, returning\n");
-		return 0;
-	}
-
-	kgdb_active = 1;
-	kgdb_started = 1;
-
-#ifdef KGDB_DEBUG
-	printk("kgdb: entering handle_exception; trap [0x%x]\n",
-			(unsigned int)regs->trap);
-#endif
-
-	kgdb_interruptible(0);
-	lock_kernel();
-	msr = mfmsr();
-	mtmsr(msr & ~MSR_EE);	/* disable interrupts */
-
-	if (regs->nip == (unsigned long)breakinst) {
-		/* Skip over breakpoint trap insn */
-		regs->nip += 4;
-	}
-
-	/* reply to host that an exception has occurred */
-	sigval = computeSignal(regs->trap);
-	ptr = remcomOutBuffer;
-
-	*ptr++ = 'T';
-	*ptr++ = hexchars[sigval >> 4];
-	*ptr++ = hexchars[sigval & 0xf];
-	*ptr++ = hexchars[PC_REGNUM >> 4];
-	*ptr++ = hexchars[PC_REGNUM & 0xf];
-	*ptr++ = ':';
-	ptr = mem2hex((char *)&regs->nip, ptr, 4);
-	*ptr++ = ';';
-	*ptr++ = hexchars[SP_REGNUM >> 4];
-	*ptr++ = hexchars[SP_REGNUM & 0xf];
-	*ptr++ = ':';
-	ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
-	*ptr++ = ';';
-	*ptr++ = 0;
-
-	putpacket(remcomOutBuffer);
-	if (kdebug)
-		printk("remcomOutBuffer: %s\n", remcomOutBuffer);
-
-	/* XXX We may want to add some features dealing with poking the
-	 * XXX page tables, ... (look at sparc-stub.c for more info)
-	 * XXX also required hacking to the gdb sources directly...
-	 */
-
-	while (1) {
-		remcomOutBuffer[0] = 0;
-
-		getpacket(remcomInBuffer);
-		switch (remcomInBuffer[0]) {
-		case '?': /* report most recent signal */
-			remcomOutBuffer[0] = 'S';
-			remcomOutBuffer[1] = hexchars[sigval >> 4];
-			remcomOutBuffer[2] = hexchars[sigval & 0xf];
-			remcomOutBuffer[3] = 0;
-			break;
-#if 0
-		case 'q': /* this screws up gdb for some reason...*/
-		{
-			extern long _start, sdata, __bss_start;
-
-			ptr = &remcomInBuffer[1];
-			if (strncmp(ptr, "Offsets", 7) != 0)
-				break;
-
-			ptr = remcomOutBuffer;
-			sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
-				&_start, &sdata, &__bss_start);
-			break;
-		}
-#endif
-		case 'd':
-			/* toggle debug flag */
-			kdebug ^= 1;
-			break;
-
-		case 'g':	/* return the value of the CPU registers.
-				 * some of them are non-PowerPC names :(
-				 * they are stored in gdb like:
-				 * struct {
-				 *     u32 gpr[32];
-				 *     f64 fpr[32];
-				 *     u32 pc, ps, cnd, lr; (ps=msr)
-				 *     u32 cnt, xer, mq;
-				 * }
-				 */
-		{
-			int i;
-			ptr = remcomOutBuffer;
-			/* General Purpose Regs */
-			ptr = mem2hex((char *)regs, ptr, 32 * 4);
-			/* Floating Point Regs - FIXME */
-			/*ptr = mem2hex((char *), ptr, 32 * 8);*/
-			for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
-				ptr[i] = '0';
-			}
-			ptr += 32*8*2;
-			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
-			ptr = mem2hex((char *)&regs->nip, ptr, 4);
-			ptr = mem2hex((char *)&regs->msr, ptr, 4);
-			ptr = mem2hex((char *)&regs->ccr, ptr, 4);
-			ptr = mem2hex((char *)&regs->link, ptr, 4);
-			ptr = mem2hex((char *)&regs->ctr, ptr, 4);
-			ptr = mem2hex((char *)&regs->xer, ptr, 4);
-		}
-			break;
-
-		case 'G': /* set the value of the CPU registers */
-		{
-			ptr = &remcomInBuffer[1];
-
-			/*
-			 * If the stack pointer has moved, you should pray.
-			 * (cause only god can help you).
-			 */
-
-			/* General Purpose Regs */
-			hex2mem(ptr, (char *)regs, 32 * 4);
-
-			/* Floating Point Regs - FIXME?? */
-			/*ptr = hex2mem(ptr, ??, 32 * 8);*/
-			ptr += 32*8*2;
-
-			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
-			ptr = hex2mem(ptr, (char *)&regs->nip, 4);
-			ptr = hex2mem(ptr, (char *)&regs->msr, 4);
-			ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
-			ptr = hex2mem(ptr, (char *)&regs->link, 4);
-			ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
-			ptr = hex2mem(ptr, (char *)&regs->xer, 4);
-
-			strcpy(remcomOutBuffer,"OK");
-		}
-			break;
-		case 'H':
-			/* don't do anything, yet, just acknowledge */
-			hexToInt(&ptr, &addr);
-			strcpy(remcomOutBuffer,"OK");
-			break;
-
-		case 'm':	/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
-				/* Try to read %x,%x.  */
-
-			ptr = &remcomInBuffer[1];
-
-			if (hexToInt(&ptr, &addr) && *ptr++ == ','
-					&& hexToInt(&ptr, &length)) {
-				if (mem2hex((char *)addr, remcomOutBuffer,
-							length))
-					break;
-				strcpy(remcomOutBuffer, "E03");
-			} else
-				strcpy(remcomOutBuffer, "E01");
-			break;
-
-		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
-			/* Try to read '%x,%x:'.  */
-
-			ptr = &remcomInBuffer[1];
-
-			if (hexToInt(&ptr, &addr) && *ptr++ == ','
-					&& hexToInt(&ptr, &length)
-					&& *ptr++ == ':') {
-				if (hex2mem(ptr, (char *)addr, length))
-					strcpy(remcomOutBuffer, "OK");
-				else
-					strcpy(remcomOutBuffer, "E03");
-				flush_icache_range(addr, addr+length);
-			} else
-				strcpy(remcomOutBuffer, "E02");
-			break;
-
-
-		case 'k': /* kill the program, actually just continue */
-		case 'c': /* cAA..AA  Continue; address AA..AA optional */
-			/* try to read optional parameter, pc unchanged if no parm */
-
-			ptr = &remcomInBuffer[1];
-			if (hexToInt(&ptr, &addr))
-				regs->nip = addr;
-
-/* Need to flush the instruction cache here, as we may have deposited a
- * breakpoint, and the icache probably has no way of knowing that a data ref to
- * some location may have changed something that is in the instruction cache.
- */
-			kgdb_flush_cache_all();
-			mtmsr(msr);
-
-			kgdb_interruptible(1);
-			unlock_kernel();
-			kgdb_active = 0;
-			if (kdebug) {
-				printk("remcomInBuffer: %s\n", remcomInBuffer);
-				printk("remcomOutBuffer: %s\n", remcomOutBuffer);
-			}
-			return 1;
-
-		case 's':
-			kgdb_flush_cache_all();
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
-			mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC);
-			regs->msr |= MSR_DE;
-#else
-			regs->msr |= MSR_SE;
-#endif
-			unlock_kernel();
-			kgdb_active = 0;
-			if (kdebug) {
-				printk("remcomInBuffer: %s\n", remcomInBuffer);
-				printk("remcomOutBuffer: %s\n", remcomOutBuffer);
-			}
-			return 1;
-
-		case 'r':		/* Reset (if user process..exit ???)*/
-			panic("kgdb reset.");
-			break;
-		}			/* switch */
-		if (remcomOutBuffer[0] && kdebug) {
-			printk("remcomInBuffer: %s\n", remcomInBuffer);
-			printk("remcomOutBuffer: %s\n", remcomOutBuffer);
-		}
-		/* reply to the request */
-		putpacket(remcomOutBuffer);
-	} /* while(1) */
-}
-
-/* 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)
-{
-	if (!initialized) {
-		printk("breakpoint() called b4 kgdb init\n");
-		return;
-	}
-
-	asm("	.globl breakinst	\n\
-	     breakinst: .long 0x7d821008");
-}
-
-#ifdef CONFIG_KGDB_CONSOLE
-/* Output string in GDB O-packet format if GDB has connected. If nothing
-   output, returns 0 (caller must then handle output). */
-int
-kgdb_output_string (const char* s, unsigned int count)
-{
-	char buffer[512];
-
-	if (!kgdb_started)
-		return 0;
-
-	count = (count <= (sizeof(buffer) / 2 - 2))
-		? count : (sizeof(buffer) / 2 - 2);
-
-	buffer[0] = 'O';
-	mem2hex (s, &buffer[1], count);
-	putpacket(buffer);
-
-	return 1;
-}
-#endif
-
-static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs,
-			     struct tty_struct *tty)
-{
-	printk("Entering GDB stub\n");
-	breakpoint();
-}
-static struct sysrq_key_op sysrq_gdb_op = {
-        .handler        = sysrq_handle_gdb,
-        .help_msg       = "Gdb",
-        .action_msg     = "GDB",
-};
-
-static int gdb_register_sysrq(void)
-{
-	printk("Registering GDB sysrq handler\n");
-	register_sysrq_key('g', &sysrq_gdb_op);
-	return 0;
-}
-module_init(gdb_register_sysrq);
Index: linux-2.6.13/arch/ppc/kernel/setup.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/kernel/setup.c
+++ linux-2.6.13/arch/ppc/kernel/setup.c
@@ -45,10 +45,6 @@
 #include <asm/ppc_sys.h>
 #endif
 
-#if defined CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-
 extern void platform_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7);
 extern void bootx_init(unsigned long r4, unsigned long phys);
@@ -703,18 +699,6 @@ void __init setup_arch(char **cmdline_p)
 #endif /* CONFIG_XMON */
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
 
-#if defined(CONFIG_KGDB)
-	if (ppc_md.kgdb_map_scc)
-		ppc_md.kgdb_map_scc();
-	set_debug_traps();
-	if (strstr(cmd_line, "gdb")) {
-		if (ppc_md.progress)
-			ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
-		printk("kgdb breakpoint activated\n");
-		breakpoint();
-	}
-#endif
-
 	/*
 	 * Set cache line size based on type of cpu as a default.
 	 * Systems with OF can look in the properties on the cpu node(s)
Index: linux-2.6.13/arch/ppc/mm/fault.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/mm/fault.c
+++ linux-2.6.13/arch/ppc/mm/fault.c
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/kgdb.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -332,6 +333,14 @@ bad_page_fault(struct pt_regs *regs, uns
 		return;
 	}
 
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault) {
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+	}
+#endif
+
 	/* kernel has accessed a bad area */
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_kernel_faults)
Index: linux-2.6.13/arch/ppc/platforms/4xx/bubinga.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/4xx/bubinga.c
+++ linux-2.6.13/arch/ppc/platforms/4xx/bubinga.c
@@ -4,7 +4,7 @@
  * Author: SAW (IBM), derived from walnut.c.
  *         Maintained by MontaVista Software <source@mvista.com>
  *
- * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
+ * 2003-2004 (c) MontaVista Softare 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.
@@ -101,17 +101,26 @@ bubinga_early_serial_map(void)
 	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
 	port.line = 0;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 0)
 		printk("Early serial init of port 0 failed\n");
-	}
+#endif
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &port);
+#endif
 
 	port.membase = (void*)ACTING_UART1_IO_BASE;
 	port.irq = ACTING_UART1_INT;
 	port.line = 1;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 0)
 		printk("Early serial init of port 1 failed\n");
-	}
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &port);
+#endif
 }
 
 void __init
@@ -256,8 +265,4 @@ platform_init(unsigned long r3, unsigned
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
 #endif
-#ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = bubinga_early_serial_map;
-#endif
 }
-
Index: linux-2.6.13/arch/ppc/platforms/4xx/ebony.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/4xx/ebony.c
+++ linux-2.6.13/arch/ppc/platforms/4xx/ebony.c
@@ -36,6 +36,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/kgdb.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -242,14 +243,20 @@ ebony_early_serial_map(void)
 	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
 	port.line = 0;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 0)
 		printk("Early serial init of port 0 failed\n");
-	}
+#endif
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
 	/* Configure debug serial access */
 	gen550_init(0, &port);
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &port);
+#endif
 
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250)
 	/* Purge TLB entry added in head_44x.S for early serial access */
 	_tlbie(UART0_IO_BASE);
 #endif
@@ -259,14 +266,18 @@ ebony_early_serial_map(void)
 	port.uartclk = clocks.uart1;
 	port.line = 1;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 1)
 		printk("Early serial init of port 1 failed\n");
-	}
+#endif
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
 	/* Configure debug serial access */
 	gen550_init(1, &port);
 #endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &port);
+#endif
 }
 
 static void __init
@@ -352,8 +363,4 @@ void __init platform_init(unsigned long 
 
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
-#ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = ebony_early_serial_map;
-#endif
 }
-
Index: linux-2.6.13/arch/ppc/platforms/4xx/ocotea.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/4xx/ocotea.c
+++ linux-2.6.13/arch/ppc/platforms/4xx/ocotea.c
@@ -34,6 +34,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/kgdb.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -260,14 +261,20 @@ ocotea_early_serial_map(void)
 	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
 	port.line = 0;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 0)
 		printk("Early serial init of port 0 failed\n");
-	}
+#endif
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
 	/* Configure debug serial access */
 	gen550_init(0, &port);
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &port);
+#endif
 
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250)
 	/* Purge TLB entry added in head_44x.S for early serial access */
 	_tlbie(UART0_IO_BASE);
 #endif
@@ -277,14 +284,18 @@ ocotea_early_serial_map(void)
 	port.uartclk = clocks.uart1;
 	port.line = 1;
 
-	if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&port) != 1)
 		printk("Early serial init of port 1 failed\n");
-	}
+#endif
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
 	/* Configure debug serial access */
 	gen550_init(1, &port);
 #endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &port);
+#endif
 }
 
 static void __init
@@ -363,8 +374,5 @@ void __init platform_init(unsigned long 
 
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
-#ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = ocotea_early_serial_map;
-#endif
 	ppc_md.init = ocotea_init;
 }
Index: linux-2.6.13/arch/ppc/platforms/4xx/xilinx_ml300.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/4xx/xilinx_ml300.c
+++ linux-2.6.13/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -42,9 +42,6 @@
  *      ppc4xx_map_io				arch/ppc/syslib/ppc4xx_setup.c
  *  start_kernel				init/main.c
  *    setup_arch				arch/ppc/kernel/setup.c
- * #if defined(CONFIG_KGDB)
- *      *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc
- * #endif
  *      *ppc_md.setup_arch == ml300_setup_arch	this file
  *        ppc4xx_setup_arch			arch/ppc/syslib/ppc4xx_setup.c
  *          ppc4xx_find_bridges			arch/ppc/syslib/ppc405_pci.c
@@ -83,7 +80,6 @@ ml300_map_io(void)
 static void __init
 ml300_early_serial_map(void)
 {
-#ifdef CONFIG_SERIAL_8250
 	struct serial_state old_ports[] = { SERIAL_PORT_DFNS };
 	struct uart_port port;
 	int i;
@@ -99,11 +95,14 @@ ml300_early_serial_map(void)
 		port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
 		port.line = i;
 
-		if (early_serial_setup(&port) != 0) {
+#ifdef CONFIG_SERIAL_8250
+		if (early_serial_setup(&port) != 0)
 			printk("Early serial init of port %d failed\n", i);
-		}
+#endif
+#ifdef CONFIG_KGDB_8250
+		kgdb8250_add_port(i, &port)
+#endif
 	}
-#endif /* CONFIG_SERIAL_8250 */
 }
 
 void __init
@@ -138,9 +137,4 @@ platform_init(unsigned long r3, unsigned
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
 	ppc_md.power_off = xilinx_power_off;
 #endif
-
-#ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = ml300_early_serial_map;
-#endif
 }
-
Index: linux-2.6.13/arch/ppc/platforms/85xx/sbc8560.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/85xx/sbc8560.c
+++ linux-2.6.13/arch/ppc/platforms/85xx/sbc8560.c
@@ -54,7 +54,6 @@
 #include <syslib/ppc85xx_common.h>
 #include <syslib/ppc85xx_setup.h>
 
-#ifdef CONFIG_SERIAL_8250
 static void __init
 sbc8560_early_serial_map(void)
 {
@@ -70,27 +69,34 @@ sbc8560_early_serial_map(void)
         uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE);
 	uart_req.type = PORT_16650;
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-        gen550_init(0, &uart_req);
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&uart_req) != 0)
+		printk("Early serial init of port 0 failed\n");
 #endif
- 
-        if (early_serial_setup(&uart_req) != 0)
-                printk("Early serial init of port 0 failed\n");
- 
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	gen550_init(0, &uart_req);
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &uart_req);
+#endif
+
         /* Assume early_serial_setup() doesn't modify uart_req */
 	uart_req.line = 1;
         uart_req.mapbase = UARTB_ADDR;
         uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE);
 	uart_req.irq = MPC85xx_IRQ_EXT10;
- 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-        gen550_init(1, &uart_req);
+
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&uart_req) != 0)
+		printk("Early serial init of port 1 failed\n");
 #endif
- 
-        if (early_serial_setup(&uart_req) != 0)
-                printk("Early serial init of port 1 failed\n");
-}
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	gen550_init(1, &uart_req);
 #endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &uart_req);
+#endif
+}
 
 /* ************************************************************************
  *
@@ -118,9 +124,7 @@ sbc8560_setup_arch(void)
 	/* setup PCI host bridges */
 	mpc85xx_setup_hose();
 #endif
-#ifdef CONFIG_SERIAL_8250
 	sbc8560_early_serial_map();
-#endif
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	/* Invalidate the entry we stole earlier the serial ports
 	 * should be properly mapped */ 
Index: linux-2.6.13/arch/ppc/platforms/chestnut.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/chestnut.c
+++ linux-2.6.13/arch/ppc/platforms/chestnut.c
@@ -496,7 +496,7 @@ chestnut_power_off(void)
 static void __init
 chestnut_map_io(void)
 {
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250)
 	io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000,
 		_PAGE_IO);
 #endif
@@ -571,9 +571,6 @@ platform_init(unsigned long r3, unsigned
 #if defined(CONFIG_SERIAL_TEXT_DEBUG)
 	ppc_md.progress = gen550_progress;
 #endif
-#if defined(CONFIG_KGDB)
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 
 	if (ppc_md.progress)
                 ppc_md.progress("chestnut_init(): exit", 0);
Index: linux-2.6.13/arch/ppc/platforms/cpci690.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/cpci690.c
+++ linux-2.6.13/arch/ppc/platforms/cpci690.c
@@ -429,7 +429,7 @@ cpci690_set_bat(u32 addr, u32 size)
 	mb();
 }
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
 static void __init
 cpci690_map_io(void)
 {
@@ -475,15 +475,13 @@ platform_init(unsigned long r3, unsigned
 	cpci690_set_bat(CPCI690_BR_BASE, 32 * MB);
 	cpci690_br_base = CPCI690_BR_BASE;
 
-#ifdef	CONFIG_SERIAL_TEXT_DEBUG
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
 	ppc_md.setup_io_mappings = cpci690_map_io;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = mv64x60_mpsc_progress;
 	mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
 #endif	/* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef	CONFIG_KGDB
-	ppc_md.setup_io_mappings = cpci690_map_io;
-	ppc_md.early_serial_map = cpci690_early_serial_map;
-#endif	/* CONFIG_KGDB */
+#endif	/* defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC) */
 
 #if defined(CONFIG_SERIAL_MPSC)
 	platform_notify = cpci690_platform_notify;
Index: linux-2.6.13/arch/ppc/platforms/mcpn765.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/mcpn765.c
+++ linux-2.6.13/arch/ppc/platforms/mcpn765.c
@@ -519,9 +519,4 @@ platform_init(unsigned long r3, unsigned
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-
-	return;
 }
Index: linux-2.6.13/arch/ppc/platforms/pcore.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/pcore.c
+++ linux-2.6.13/arch/ppc/platforms/pcore.c
@@ -346,7 +346,4 @@ platform_init(unsigned long r3, unsigned
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 }
Index: linux-2.6.13/arch/ppc/platforms/pplus.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/pplus.c
+++ linux-2.6.13/arch/ppc/platforms/pplus.c
@@ -908,9 +908,6 @@ platform_init(unsigned long r3, unsigned
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif				/* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 #ifdef CONFIG_SMP
 	ppc_md.smp_ops = &pplus_smp_ops;
 #endif				/* CONFIG_SMP */
Index: linux-2.6.13/arch/ppc/platforms/sandpoint.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/sandpoint.c
+++ linux-2.6.13/arch/ppc/platforms/sandpoint.c
@@ -751,9 +751,6 @@ platform_init(unsigned long r3, unsigned
 	ppc_md.nvram_read_val = todc_mc146818_read_val;
 	ppc_md.nvram_write_val = todc_mc146818_write_val;
 
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif
Index: linux-2.6.13/arch/ppc/platforms/spruce.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/platforms/spruce.c
+++ linux-2.6.13/arch/ppc/platforms/spruce.c
@@ -181,26 +181,32 @@ spruce_early_serial_map(void)
 	serial_req.membase = (u_char *)UART0_IO_BASE;
 	serial_req.regshift = 0;
 
-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
-	gen550_init(0, &serial_req);
-#endif
 #ifdef CONFIG_SERIAL_8250
 	if (early_serial_setup(&serial_req) != 0)
 		printk("Early serial init of port 0 failed\n");
 #endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	gen550_init(0, &serial_req);
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &port);
+#endif
 
 	/* Assume early_serial_setup() doesn't modify serial_req */
 	serial_req.line = 1;
 	serial_req.irq = UART1_INT;
 	serial_req.membase = (u_char *)UART1_IO_BASE;
 
-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
-	gen550_init(1, &serial_req);
-#endif
 #ifdef CONFIG_SERIAL_8250
 	if (early_serial_setup(&serial_req) != 0)
 		printk("Early serial init of port 1 failed\n");
 #endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	gen550_init(1, &serial_req);
+#endif
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &serial_req);
+#endif
 }
 
 TODC_ALLOC();
@@ -319,7 +325,4 @@ platform_init(unsigned long r3, unsigned
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 }
Index: linux-2.6.13/arch/ppc/syslib/gen550.h
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/gen550.h
+++ linux-2.6.13/arch/ppc/syslib/gen550.h
@@ -13,4 +13,3 @@
 
 extern void gen550_progress(char *, unsigned short);
 extern void gen550_init(int, struct uart_port *);
-extern void gen550_kgdb_map_scc(void);
Index: linux-2.6.13/arch/ppc/syslib/gen550_kgdb.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/gen550_kgdb.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * arch/ppc/syslib/gen550_kgdb.c
- *
- * Generic 16550 kgdb support intended to be useful on a variety
- * of platforms.  To enable this support, it is necessary to set
- * the CONFIG_GEN550 option.  Any virtual mapping of the serial
- * port(s) to be used can be accomplished by setting
- * ppc_md.early_serial_map to a platform-specific mapping function.
- *
- * Adapted from ppc4xx_kgdb.c.
- *
- * Author: Matt Porter <mporter@kernel.crashing.org>
- *
- * 2002-2004 (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.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <asm/machdep.h>
-
-extern unsigned long serial_init(int, void *);
-extern unsigned long serial_getc(unsigned long);
-extern unsigned long serial_putc(unsigned long, unsigned char);
-
-#if defined(CONFIG_KGDB_TTYS0)
-#define KGDB_PORT 0
-#elif defined(CONFIG_KGDB_TTYS1)
-#define KGDB_PORT 1
-#elif defined(CONFIG_KGDB_TTYS2)
-#define KGDB_PORT 2
-#elif defined(CONFIG_KGDB_TTYS3)
-#define KGDB_PORT 3
-#else
-#error "invalid kgdb_tty port"
-#endif
-
-static volatile unsigned int kgdb_debugport;
-
-void putDebugChar(unsigned char c)
-{
-	if (kgdb_debugport == 0)
-		kgdb_debugport = serial_init(KGDB_PORT, NULL);
-
-	serial_putc(kgdb_debugport, c);
-}
-
-int getDebugChar(void)
-{
-	if (kgdb_debugport == 0)
-		kgdb_debugport = serial_init(KGDB_PORT, NULL);
-
-	return(serial_getc(kgdb_debugport));
-}
-
-void kgdb_interruptible(int enable)
-{
-	return;
-}
-
-void putDebugString(char* str)
-{
-	while (*str != '\0') {
-		putDebugChar(*str);
-		str++;
-	}
-	putDebugChar('\r');
-	return;
-}
-
-/*
- * Note: gen550_init() must be called already on the port we are going
- * to use.
- */
-void
-gen550_kgdb_map_scc(void)
-{
-	printk(KERN_DEBUG "kgdb init\n");
-	if (ppc_md.early_serial_map)
-		ppc_md.early_serial_map();
-	kgdb_debugport = serial_init(KGDB_PORT, NULL);
-}
Index: linux-2.6.13/arch/ppc/syslib/ibm44x_common.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/ibm44x_common.c
+++ linux-2.6.13/arch/ppc/syslib/ibm44x_common.c
@@ -161,9 +161,6 @@ void __init ibm44x_platform_init(void)
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = gen550_progress;
 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
 
 	/*
 	 * The Abatron BDI JTAG debugger does not tolerate others
Index: linux-2.6.13/arch/ppc/syslib/Makefile
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/Makefile
+++ linux-2.6.13/arch/ppc/syslib/Makefile
@@ -87,7 +87,6 @@ obj-$(CONFIG_PCI_8260)		+= m82xx_pci.o i
 obj-$(CONFIG_8260_PCI9)		+= m8260_pci_erratum9.o
 obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
 ifeq ($(CONFIG_PPC_GEN550),y)
-obj-$(CONFIG_KGDB)		+= gen550_kgdb.o gen550_dbg.o
 obj-$(CONFIG_SERIAL_TEXT_DEBUG)	+= gen550_dbg.o
 endif
 ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y)
Index: linux-2.6.13/arch/ppc/syslib/mv64x60.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/mv64x60.c
+++ linux-2.6.13/arch/ppc/syslib/mv64x60.c
@@ -239,6 +239,12 @@ static struct resource mv64x60_mpsc0_res
 		.end	= MV64x60_IRQ_SDMA_0,
 		.flags	= IORESOURCE_IRQ,
 	},
+	[4] = {
+		.name	= "mpsc 0 irq",
+		.start	= MV64x60_IRQ_MPSC_0,
+		.end	= MV64x60_IRQ_MPSC_0,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device mpsc0_device = {
@@ -296,6 +302,12 @@ static struct resource mv64x60_mpsc1_res
 		.end	= MV64360_IRQ_SDMA_1,
 		.flags	= IORESOURCE_IRQ,
 	},
+	[4] = {
+		.name	= "mpsc 1 irq",
+		.start	= MV64360_IRQ_MPSC_1,
+		.end	= MV64360_IRQ_MPSC_1,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device mpsc1_device = {
@@ -1435,12 +1447,46 @@ mv64x60_pd_fixup(struct mv64x60_handle *
 static int __init
 mv64x60_add_pds(void)
 {
-	return platform_add_devices(mv64x60_pd_devs,
-		ARRAY_SIZE(mv64x60_pd_devs));
+	int i, ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(mv64x60_pd_devs); i++) {
+		if (mv64x60_pd_devs[i]) {
+			ret = platform_device_register(mv64x60_pd_devs[i]);
+		}
+		if (ret) {
+			while (--i >= 0)
+				platform_device_unregister(mv64x60_pd_devs[i]);
+			break;
+		}
+	}
+	return ret;
 }
 arch_initcall(mv64x60_add_pds);
 
 /*
+ * mv64x60_early_get_pdev_data()
+ *
+ * Get the data associated with a platform device by name and number.
+ */
+struct platform_device * __init
+mv64x60_early_get_pdev_data(const char *name, int id, int remove)
+{
+	int i;
+	struct platform_device *pdev;
+
+	for (i = 0; i <ARRAY_SIZE(mv64x60_pd_devs); i++) {
+		if ((pdev = mv64x60_pd_devs[i]) &&
+			pdev->id == id &&
+			!strcmp(pdev->name, name)) {
+			if (remove)
+				mv64x60_pd_devs[i] = NULL;
+			return pdev;
+		}
+	}
+	return NULL;
+}
+
+/*
  *****************************************************************************
  *
  *	GT64260-Specific Routines
@@ -1866,6 +1912,12 @@ gt64260b_chip_specific_init(struct mv64x
 		r->start = MV64x60_IRQ_SDMA_0;
 		r->end = MV64x60_IRQ_SDMA_0;
 	}
+	if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 1))
+		!= NULL) {
+
+		r->start = GT64260_IRQ_MPSC_1;
+		r->end = GT64260_IRQ_MPSC_1;
+	}
 #endif
 
 	return;
Index: linux-2.6.13/arch/ppc/syslib/mv64x60_dbg.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/mv64x60_dbg.c
+++ linux-2.6.13/arch/ppc/syslib/mv64x60_dbg.c
@@ -36,7 +36,7 @@ static struct mv64x60_handle	mv64x60_dbg
 void
 mv64x60_progress_init(u32 base)
 {
-	mv64x60_dbg_bh.v_base = base;
+	mv64x60_dbg_bh.v_base = (void*)base;
 	return;
 }
 
@@ -71,53 +71,3 @@ mv64x60_mpsc_progress(char *s, unsigned 
 	return;
 }
 #endif	/* CONFIG_SERIAL_TEXT_DEBUG */
-
-
-#if defined(CONFIG_KGDB)
-
-#if defined(CONFIG_KGDB_TTYS0)
-#define KGDB_PORT 0
-#elif defined(CONFIG_KGDB_TTYS1)
-#define KGDB_PORT 1
-#else
-#error "Invalid kgdb_tty port"
-#endif
-
-void
-putDebugChar(unsigned char c)
-{
-	mv64x60_polled_putc(KGDB_PORT, (char)c);
-}
-
-int
-getDebugChar(void)
-{
-	unsigned char	c;
-
-	while (!mv64x60_polled_getc(KGDB_PORT, &c));
-	return (int)c;
-}
-
-void
-putDebugString(char* str)
-{
-	while (*str != '\0') {
-		putDebugChar(*str);
-		str++;
-	}
-	putDebugChar('\r');
-	return;
-}
-
-void
-kgdb_interruptible(int enable)
-{
-}
-
-void
-kgdb_map_scc(void)
-{
-	if (ppc_md.early_serial_map)
-		ppc_md.early_serial_map();
-}
-#endif	/* CONFIG_KGDB */
Index: linux-2.6.13/arch/ppc/syslib/ppc85xx_setup.c
===================================================================
--- linux-2.6.13.orig/arch/ppc/syslib/ppc85xx_setup.c
+++ linux-2.6.13/arch/ppc/syslib/ppc85xx_setup.c
@@ -71,7 +71,6 @@ mpc85xx_calibrate_decr(void)
 	mtspr(SPRN_TCR, TCR_DIE);
 }
 
-#ifdef CONFIG_SERIAL_8250
 void __init
 mpc85xx_early_serial_map(void)
 {
@@ -87,7 +86,7 @@ mpc85xx_early_serial_map(void)
 	pdata[0].mapbase += binfo->bi_immr_base;
 	pdata[0].membase = ioremap(pdata[0].mapbase, MPC85xx_UART0_SIZE);
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250)
 	memset(&serial_req, 0, sizeof (serial_req));
 	serial_req.iotype = SERIAL_IO_MEM;
 	serial_req.mapbase = pdata[0].mapbase;
@@ -95,18 +94,24 @@ mpc85xx_early_serial_map(void)
 	serial_req.regshift = 0;
 
 	gen550_init(0, &serial_req);
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &serial_req);
+#endif
 #endif
 
 	pdata[1].uartclk = binfo->bi_busfreq;
 	pdata[1].mapbase += binfo->bi_immr_base;
 	pdata[1].membase = ioremap(pdata[1].mapbase, MPC85xx_UART0_SIZE);
 
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250)
 	/* Assume gen550_init() doesn't modify serial_req */
 	serial_req.mapbase = pdata[1].mapbase;
 	serial_req.membase = pdata[1].membase;
 
 	gen550_init(1, &serial_req);
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(1, &serial_req);
+#endif
 #endif
 }
 #endif
@@ -365,5 +370,3 @@ mpc85xx_setup_hose(void)
 	return;
 }
 #endif /* CONFIG_PCI */
-
-
Index: linux-2.6.13/drivers/serial/kgdb_mpsc.c
===================================================================
--- /dev/null
+++ linux-2.6.13/drivers/serial/kgdb_mpsc.c
@@ -0,0 +1,313 @@
+/*
+ * drivers/serial/kgdb_mpsc.
+ *
+ * KGDB driver for the Marvell MultiProtocol Serial Controller (MPCS)
+ *
+ * Based on the polled boot loader driver by Ajit Prem (ajit.prem@motorola.com)
+ *
+ * Author: Randy Vinson <rvinson@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * 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 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kgdb.h>
+#include <linux/mv643xx.h>
+#include <linux/device.h>
+#include <asm/mv64x60.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "mpsc.h"
+
+/* Speed of the UART. */
+#if defined(CONFIG_KGDB_9600BAUD)
+static int kgdbmpsc_baud = 9600;
+#elif defined(CONFIG_KGDB_19200BAUD)
+static int kgdbmpsc_baud = 19200;
+#elif defined(CONFIG_KGDB_38400BAUD)
+static int kgdbmpsc_baud = 38400;
+#elif defined(CONFIG_KGDB_57600BAUD)
+static int kgdbmpsc_baud = 57600;
+#else
+static int kgdbmpsc_baud = 115200;	/* Start with this if not given */
+#endif
+
+/* Index of the UART, matches ttyMX naming. */
+#if defined(CONFIG_KGDB_SERIAL_PORT_1)
+static int kgdbmpsc_ttyMM = 1;
+#else
+static int kgdbmpsc_ttyMM = 0;	/* Start with this if not given */
+#endif
+
+#define MPSC_INTR_REG_SELECT(x)	((x) + (8 * kgdbmpsc_ttyMM))
+
+static int kgdbmpsc_init(void);
+
+static struct platform_device mpsc_dev, shared_dev;
+
+static void __iomem *mpsc_base;
+static void __iomem *brg_base;
+static void __iomem *routing_base;
+static void __iomem *sdma_base;
+
+static unsigned int mpsc_irq;
+
+static void kgdb_write_debug_char(int c)
+{
+	u32 data;
+
+	data = readl(mpsc_base + MPSC_MPCR);
+	writeb(c, mpsc_base + MPSC_CHR_1);
+	mb();
+	data = readl(mpsc_base + MPSC_CHR_2);
+	data |= MPSC_CHR_2_TTCS;
+	writel(data, mpsc_base + MPSC_CHR_2);
+	mb();
+
+	while (readl(mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS) ;
+}
+
+static int kgdb_get_debug_char(void)
+{
+	unsigned char c;
+
+	while (!(readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) &
+		 MPSC_INTR_CAUSE_RCC)) ;
+
+	c = readb(mpsc_base + MPSC_CHR_10 + (1 << 1));
+	mb();
+	writeb(c, mpsc_base + MPSC_CHR_10 + (1 << 1));
+	mb();
+	writel(~MPSC_INTR_CAUSE_RCC, sdma_base +
+	       MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE));
+	return (c);
+}
+
+/*
+ * 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
+kgdbmpsc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (irq != mpsc_irq)
+		return IRQ_NONE;
+	/*
+	 * If  there is some other CPU in KGDB then this is a
+	 * spurious interrupt. so return without even checking a byte
+	 */
+	if (atomic_read(&debugger_active))
+		return IRQ_NONE;
+
+	if (readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) &
+	    MPSC_INTR_CAUSE_RCC)
+		breakpoint();
+
+	return IRQ_HANDLED;
+}
+
+static int __init kgdbmpsc_init(void)
+{
+	struct mpsc_pdata *pdata;
+	u32 cdv;
+
+	if (!brg_base || !mpsc_base || !routing_base || !sdma_base)
+		return -1;
+
+	/* Set MPSC Routing to enable both ports */
+	writel(0x0, routing_base + MPSC_MRR);
+
+	/* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
+	writel(0x00000100, routing_base + MPSC_RCRR);
+	writel(0x00000100, routing_base + MPSC_TCRR);
+
+	/* Disable all MPSC interrupts and clear any pending interrupts */
+	writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK));
+	writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE));
+
+	pdata = (struct mpsc_pdata *)mpsc_dev.dev.platform_data;
+
+	/* cdv = (clock/(2*16*baud rate)) for 16X mode. */
+	cdv = ((pdata->brg_clk_freq / (32 * kgdbmpsc_baud)) - 1);
+	writel((pdata->brg_clk_src << 18) | (1 << 16) | cdv,
+	       brg_base + BRG_BCR);
+
+	/* Put MPSC into UART mode, no null modem, 16x clock mode */
+	writel(0x000004c4, mpsc_base + MPSC_MMCRL);
+	writel(0x04400400, mpsc_base + MPSC_MMCRH);
+
+	writel(0, mpsc_base + MPSC_CHR_1);
+	writel(0, mpsc_base + MPSC_CHR_9);
+	writel(0, mpsc_base + MPSC_CHR_10);
+	writel(4, mpsc_base + MPSC_CHR_3);
+	writel(0x20000000, mpsc_base + MPSC_CHR_4);
+	writel(0x9000, mpsc_base + MPSC_CHR_5);
+	writel(0, mpsc_base + MPSC_CHR_6);
+	writel(0, mpsc_base + MPSC_CHR_7);
+	writel(0, mpsc_base + MPSC_CHR_8);
+
+	/* 8 data bits, 1 stop bit */
+	writel((3 << 12), mpsc_base + MPSC_MPCR);
+
+	/* Enter "hunt" mode */
+	writel((1 << 31), mpsc_base + MPSC_CHR_2);
+
+	udelay(100);
+	return 0;
+}
+
+static void __iomem *__init
+kgdbmpsc_map_resource(struct platform_device *pd, int type, int num)
+{
+	void __iomem *base = NULL;
+	struct resource *r;
+
+	if ((r = platform_get_resource(pd, IORESOURCE_MEM, num)))
+		base = ioremap(r->start, r->end - r->start + 1);
+	return base;
+}
+
+static void __iomem *__init
+kgdbmpsc_unmap_resource(struct platform_device *pd, int type, int num,
+			void __iomem * base)
+{
+	if (base)
+		iounmap(base);
+	return NULL;
+}
+
+static void __init
+kgdbmpsc_reserve_resource(struct platform_device *pd, int type, int num)
+{
+	struct resource *r;
+
+	if ((r = platform_get_resource(pd, IORESOURCE_MEM, num)))
+		request_mem_region(r->start, r->end - r->start + 1, "kgdb");
+}
+
+static int __init kgdbmpsc_local_init(void)
+{
+	if (!mpsc_dev.num_resources || !shared_dev.num_resources)
+		return 1;	/* failure */
+
+	mpsc_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM,
+					  MPSC_BASE_ORDER);
+	brg_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM,
+					 MPSC_BRG_BASE_ORDER);
+
+	/* get the platform data for the shared registers and get them mapped */
+	routing_base = kgdbmpsc_map_resource(&shared_dev,
+					     IORESOURCE_MEM,
+					     MPSC_ROUTING_BASE_ORDER);
+	sdma_base =
+	    kgdbmpsc_map_resource(&shared_dev, IORESOURCE_MEM,
+				  MPSC_SDMA_INTR_BASE_ORDER);
+
+	mpsc_irq = platform_get_irq(&mpsc_dev, 1);
+
+	if (mpsc_base && brg_base && routing_base && sdma_base)
+		return 0;	/* success */
+
+	return 1;		/* failure */
+}
+
+static void __init kgdbmpsc_local_exit(void)
+{
+	if (sdma_base)
+		sdma_base = kgdbmpsc_unmap_resource(&shared_dev, IORESOURCE_MEM,
+						    MPSC_SDMA_INTR_BASE_ORDER,
+						    sdma_base);
+	if (routing_base)
+		routing_base = kgdbmpsc_unmap_resource(&shared_dev,
+						       IORESOURCE_MEM,
+						       MPSC_ROUTING_BASE_ORDER,
+						       routing_base);
+	if (brg_base)
+		brg_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM,
+						   MPSC_BRG_BASE_ORDER,
+						   brg_base);
+	if (mpsc_base)
+		mpsc_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM,
+						    MPSC_BASE_ORDER, mpsc_base);
+}
+
+static void __init kgdbmpsc_update_pdata(struct platform_device *pdev)
+{
+
+	snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id);
+}
+
+static int __init kgdbmpsc_pdev_init(void)
+{
+	struct platform_device *pdev;
+
+	/* get the platform data for the specified port. */
+	pdev = mv64x60_early_get_pdev_data(MPSC_CTLR_NAME, kgdbmpsc_ttyMM, 1);
+	if (pdev) {
+		memcpy(&mpsc_dev, pdev, sizeof(struct platform_device));
+		if (platform_notify) {
+			kgdbmpsc_update_pdata(&mpsc_dev);
+			platform_notify(&mpsc_dev.dev);
+		}
+
+		/* get the platform data for the shared registers. */
+		pdev = mv64x60_early_get_pdev_data(MPSC_SHARED_NAME, 0, 0);
+		if (pdev) {
+			memcpy(&shared_dev, pdev,
+			       sizeof(struct platform_device));
+			if (platform_notify) {
+				kgdbmpsc_update_pdata(&shared_dev);
+				platform_notify(&shared_dev.dev);
+			}
+		}
+	}
+	return 0;
+}
+
+postcore_initcall(kgdbmpsc_pdev_init);
+
+static int __init kgdbmpsc_init_io(void)
+{
+
+	kgdbmpsc_pdev_init();
+
+	if (kgdbmpsc_local_init()) {
+		kgdbmpsc_local_exit();
+		return -1;
+	}
+
+	if (kgdbmpsc_init() == -1)
+		return -1;
+	return 0;
+}
+
+static void __init kgdbmpsc_hookup_irq(void)
+{
+	unsigned int msk;
+	if (!request_irq(mpsc_irq, kgdbmpsc_interrupt, 0, "kgdb mpsc", NULL)) {
+		/* Enable interrupt */
+		msk = readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK));
+		msk |= MPSC_INTR_CAUSE_RCC;
+		writel(msk, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK));
+
+		kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM,
+					  MPSC_BASE_ORDER);
+		kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM,
+					  MPSC_BRG_BASE_ORDER);
+	}
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.read_char = kgdb_get_debug_char,
+	.write_char = kgdb_write_debug_char,
+	.init = kgdbmpsc_init_io,
+	.late_init = kgdbmpsc_hookup_irq,
+};
Index: linux-2.6.13/drivers/serial/Makefile
===================================================================
--- linux-2.6.13.orig/drivers/serial/Makefile
+++ linux-2.6.13/drivers/serial/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_SERIAL_IMX) += imx.o
 obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
 obj-$(CONFIG_SERIAL_ICOM) += icom.o
 obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
+obj-$(CONFIG_KGDB_MPSC) += kgdb_mpsc.o
 obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
Index: linux-2.6.13/drivers/serial/mpsc.h
===================================================================
--- linux-2.6.13.orig/drivers/serial/mpsc.h
+++ linux-2.6.13/drivers/serial/mpsc.h
@@ -207,6 +207,10 @@ struct mpsc_port_info *mpsc_device_remov
 #define	MPSC_RCRR			0x0004
 #define	MPSC_TCRR			0x0008
 
+/* MPSC Interrupt registers (offset from MV64x60_SDMA_INTR_OFFSET) */
+#define MPSC_INTR_CAUSE			0x0004
+#define MPSC_INTR_MASK			0x0084
+#define MPSC_INTR_CAUSE_RCC		(1<<6)
 /*
  *****************************************************************************
  *
Index: linux-2.6.13/include/asm-ppc/kgdb.h
===================================================================
--- linux-2.6.13.orig/include/asm-ppc/kgdb.h
+++ linux-2.6.13/include/asm-ppc/kgdb.h
@@ -2,6 +2,8 @@
  * kgdb.h: Defines and declarations for serial line source level
  *         remote debugging of the Linux kernel using gdb.
  *
+ * PPC Mods (C) 2004 Tom Rini (trini@mvista.com)
+ * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com)
  * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -12,46 +14,32 @@
 
 #ifndef __ASSEMBLY__
 
-/* Things specific to the gen550 backend. */
-struct uart_port;
-
-extern void gen550_progress(char *, unsigned short);
-extern void gen550_kgdb_map_scc(void);
-extern void gen550_init(int, struct uart_port *);
-
-/* Things specific to the pmac backend. */
-extern void zs_kgdb_hook(int tty_num);
-
-/* To init the kgdb engine. (called by serial hook)*/
-extern void set_debug_traps(void);
-
-/* To enter the debugger explicitly. */
-extern void breakpoint(void);
+#define BREAK_INSTR_SIZE	4
+#ifndef CONFIG_E500
+#define MAXREG			(PT_FPSCR+1)
+#else
+/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/
+#define MAXREG                 ((32*2)+6+2+1)
+#endif
+#define NUMREGBYTES		(MAXREG * sizeof(int))
+#define BUFMAX			((NUMREGBYTES * 2) + 512)
+#define OUTBUFMAX		((NUMREGBYTES * 2) + 512)
+/* CR/LR, R1, R2, R13-R31 inclusive. */
+#define NUMCRITREGBYTES		(23 * sizeof(int))
+#define BREAKPOINT()		asm(".long 0x7d821008"); /* twge r2, r2 */
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
 
 /* For taking exceptions
  * these are defined in traps.c
  */
+struct pt_regs;
 extern void (*debugger)(struct pt_regs *regs);
 extern int (*debugger_bpt)(struct pt_regs *regs);
 extern int (*debugger_sstep)(struct pt_regs *regs);
 extern int (*debugger_iabr_match)(struct pt_regs *regs);
 extern int (*debugger_dabr_match)(struct pt_regs *regs);
 extern void (*debugger_fault_handler)(struct pt_regs *regs);
-
-/* What we bring to the party */
-int kgdb_bpt(struct pt_regs *regs);
-int kgdb_sstep(struct pt_regs *regs);
-void kgdb(struct pt_regs *regs);
-int kgdb_iabr_match(struct pt_regs *regs);
-int kgdb_dabr_match(struct pt_regs *regs);
-
-/*
- * external low-level support routines (ie macserial.c)
- */
-extern void kgdb_interruptible(int); /* control interrupts from serial */
-extern void putDebugChar(char);   /* write a single character      */
-extern char getDebugChar(void);   /* read and return a single char */
-
 #endif /* !(__ASSEMBLY__) */
 #endif /* !(_PPC_KGDB_H) */
 #endif /* __KERNEL__ */
Index: linux-2.6.13/include/asm-ppc/machdep.h
===================================================================
--- linux-2.6.13.orig/include/asm-ppc/machdep.h
+++ linux-2.6.13/include/asm-ppc/machdep.h
@@ -59,9 +59,7 @@ struct machdep_calls {
 	unsigned long	(*find_end_of_memory)(void);
 	void		(*setup_io_mappings)(void);
 
-	void		(*early_serial_map)(void);
   	void		(*progress)(char *, unsigned short);
-	void		(*kgdb_map_scc)(void);
 
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
Index: linux-2.6.13/include/asm-ppc/mv64x60_defs.h
===================================================================
--- linux-2.6.13.orig/include/asm-ppc/mv64x60_defs.h
+++ linux-2.6.13/include/asm-ppc/mv64x60_defs.h
@@ -57,7 +57,8 @@
 #define	MV64x60_IRQ_I2C				37
 #define	MV64x60_IRQ_BRG				39
 #define	MV64x60_IRQ_MPSC_0			40
-#define	MV64x60_IRQ_MPSC_1			42
+#define	MV64360_IRQ_MPSC_1			41
+#define	GT64260_IRQ_MPSC_1			42
 #define	MV64x60_IRQ_COMM			43
 #define	MV64x60_IRQ_P0_GPP_0_7			56
 #define	MV64x60_IRQ_P0_GPP_8_15			57
Index: linux-2.6.13/include/asm-ppc/mv64x60.h
===================================================================
--- linux-2.6.13.orig/include/asm-ppc/mv64x60.h
+++ linux-2.6.13/include/asm-ppc/mv64x60.h
@@ -332,6 +332,8 @@ u32 mv64x60_calc_mem_size(struct mv64x60
 
 void mv64x60_progress_init(u32 base);
 void mv64x60_mpsc_progress(char *s, unsigned short hex);
+struct platform_device * mv64x60_early_get_pdev_data(const char *name,
+		int id, int remove);
 
 extern struct mv64x60_32bit_window
 	gt64260_32bit_windows[MV64x60_32BIT_WIN_COUNT];
Index: linux-2.6.13/lib/Kconfig.debug
===================================================================
--- linux-2.6.13.orig/lib/Kconfig.debug
+++ linux-2.6.13/lib/Kconfig.debug
@@ -168,7 +168,7 @@ config WANT_EXTRA_DEBUG_INFORMATION
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86)
+	depends on DEBUG_KERNEL && (X86 || ((!SMP || BROKEN) && (PPC32)))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
@@ -194,6 +194,7 @@ choice
 	prompt "Method for KGDB communication"
 	depends on KGDB
 	default KGDB_ONLY_MODULES
+	default KGDB_MPSC if SERIAL_MPSC
 	help
 	  There are a number of different ways in which you can communicate
 	  with KGDB.  The most common is via serial, with the 8250 driver
@@ -210,4 +211,11 @@ config KGDB_ONLY_MODULES
 	  Use only kernel modules to configure KGDB I/O after the
 	  kernel is booted.
 
+config KGDB_MPSC
+	bool "KGDB on MV64x60 MPSC"
+	depends on SERIAL_MPSC
+	help
+	  Uses a Marvell GT64260B or MV64x60 Multi-Purpose Serial
+	  Controller (MPSC) channel. Note that the GT64260A is not
+	  supported.
 endchoice
_

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

* [patch 04/16] I/O driver for 8250-compatible UARTs
       [not found] ` <1.2982005.trini@kernel.crashing.org>
  2005-08-29 16:09   ` [patch 02/16] Add support for i386 platforms to KGDB Tom Rini
  2005-08-29 16:09   ` [patch 03/16] Add support for PowerPC32 platforms to KGDB Tom Rini
@ 2005-08-29 16:09   ` Tom Rini
  2005-08-29 16:18     ` Russell King
  2005-08-31 19:38     ` Bjorn Helgaas
  2005-08-29 16:09   ` [patch 05/16] Add support for MIPS platforms to KGDB Tom Rini
                     ` (11 subsequent siblings)
  14 siblings, 2 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:09 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, rmk


CC: Russell King <rmk@arm.linux.org.uk>
This is the I/O driver for any 8250-compatible UARTs.  This also adds some
small hooks into the normal serial core so that we can take away the uart and
make sure only KGDB is trying to use it.  We also make sure that if KGDB_8250
is enabled, SERIAL_8250_NR_UARTS is set to the default of 4.  This is so that
if we can always depend on that constant in the 8250 driver for giving our
table a size.  To make it easier (or in some cases, possible) to free up ports
on a shared irq system, we add a line member to plat_serial8250_port.

Since the last time this was submitted, I believe that all of the objections
that Russell King noted have been fixed.

---

 linux-2.6.13-trini/drivers/serial/8250.c       |   21 
 linux-2.6.13-trini/drivers/serial/8250.h       |    1 
 linux-2.6.13-trini/drivers/serial/Kconfig      |    2 
 linux-2.6.13-trini/drivers/serial/Makefile     |    1 
 linux-2.6.13-trini/drivers/serial/kgdb_8250.c  |  594 +++++++++++++++++++++
 linux-2.6.13-trini/include/linux/kgdb.h        |    3 
 linux-2.6.13-trini/include/linux/serial_8250.h |    1 
 linux-2.6.13-trini/lib/Kconfig.debug           |   92 +++
 8 files changed, 712 insertions(+), 3 deletions(-)

diff -puN drivers/serial/8250.c~8250 drivers/serial/8250.c
--- linux-2.6.13/drivers/serial/8250.c~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/drivers/serial/8250.c	2005-08-15 07:53:39.000000000 -0700
@@ -2516,6 +2516,27 @@ void serial8250_unregister_port(int line
 }
 EXPORT_SYMBOL(serial8250_unregister_port);
 
+/**
+ *	serial8250_unregister_by_port - remove a 16x50 serial port
+ *	at runtime.
+ *	@port: A &struct uart_port that describes the port to remove.
+ *
+ *	Remove one serial port.  This may not be called from interrupt
+ *	context.  We hand the port back to the our control.
+ */
+void serial8250_unregister_by_port(struct uart_port *port)
+{
+	struct uart_8250_port *uart;
+
+	down(&serial_sem);
+	uart = serial8250_find_match_or_unused(port);
+	up(&serial_sem);
+
+	if (uart)
+		serial8250_unregister_port(uart->port.line);
+}
+EXPORT_SYMBOL(serial8250_unregister_by_port);
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
diff -puN drivers/serial/8250.h~8250 drivers/serial/8250.h
--- linux-2.6.13/drivers/serial/8250.h~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/drivers/serial/8250.h	2005-08-15 07:53:39.000000000 -0700
@@ -19,6 +19,7 @@
 
 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);
 
diff -puN drivers/serial/Kconfig~8250 drivers/serial/Kconfig
--- linux-2.6.13/drivers/serial/Kconfig~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/drivers/serial/Kconfig	2005-08-15 07:53:39.000000000 -0700
@@ -87,7 +87,7 @@ config SERIAL_8250_ACPI
 
 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 -puN /dev/null drivers/serial/kgdb_8250.c
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/drivers/serial/kgdb_8250.c	2005-08-16 14:57:32.000000000 -0700
@@ -0,0 +1,594 @@
+/*
+ * 8250 interface 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 (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>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serialP.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/serial.h>		/* For BASE_BAUD and SERIAL_PORT_DFNS */
+
+#include "8250.h"
+
+#define GDB_BUF_SIZE	512	/* power of 2, please */
+
+MODULE_DESCRIPTION("KGDB driver for the 8250");
+MODULE_LICENSE("GPL");
+/* These will conflict with early_param otherwise. */
+#ifdef CONFIG_KGDB_8250_MODULE
+static char config[256];
+module_param_string(kgdb8250, config, 256, 0);
+MODULE_PARM_DESC(kgdb8250, " kgdb8250=<port number>,<baud rate>\n");
+static struct kgdb_io local_kgdb_io_ops;
+#endif				/* CONFIG_KGDB_8250_MODULE */
+
+/* Speed of the UART. */
+#if defined(CONFIG_KGDB_9600BAUD)
+static int kgdb8250_baud = 9600;
+#elif defined(CONFIG_KGDB_19200BAUD)
+static int kgdb8250_baud = 19200;
+#elif defined(CONFIG_KGDB_38400BAUD)
+static int kgdb8250_baud = 38400;
+#elif defined(CONFIG_KGDB_57600BAUD)
+static int kgdb8250_baud = 57600;
+#else
+static int kgdb8250_baud = 115200;	/* Start with this if not given */
+#endif
+
+/* Index of the UART, matches ttySX naming. */
+#if defined(CONFIG_KGDB_PORT_1)
+static int kgdb8250_ttyS = 1;
+#elif defined(CONFIG_KGDB_PORT_2)
+static int kgdb8250_ttyS = 2;
+#elif defined(CONFIG_KGDB_PORT_3)
+static int kgdb8250_ttyS = 3;
+#else
+static int kgdb8250_ttyS = 0;	/* Start with this if not given */
+#endif
+
+/* Flag for if we need to call request_mem_region */
+static int kgdb8250_needs_request_mem_region;
+
+static char kgdb8250_buf[GDB_BUF_SIZE];
+static atomic_t kgdb8250_buf_in_cnt;
+static int kgdb8250_buf_out_inx;
+
+/* Old-style serial definitions, if existant, and a counter. */
+static int old_rs_table_copied;
+static struct serial_state __initdata old_rs_table[] = {
+#ifdef SERIAL_PORT_DFNS
+	SERIAL_PORT_DFNS
+#endif
+};
+
+/* Our internal table of UARTS. */
+#define UART_NR	CONFIG_SERIAL_8250_NR_UARTS
+static struct uart_port kgdb8250_ports[UART_NR] = {
+#ifndef CONFIG_KGDB_SIMPLE_SERIAL
+	{
+#if defined(CONFIG_KGDB_IRQ) && defined(CONFIG_KGDB_PORT)
+		.irq = CONFIG_KGDB_IRQ,
+		.iobase = CONFIG_KGDB_PORT,
+		.iotype = UPIO_PORT,
+#elif CONFIG_KGDB_IOMEMBASE
+		.membase = (unsigned char *)CONFIG_KGDB_IOMEMBASE,
+		.iotype = UPIO_MEM,
+#endif
+	 },
+#endif
+};
+
+/* Macros to easily get what we want from kgdb8250_ports[kgdb8250_ttyS] */
+#define CURRENTPORT		kgdb8250_ports[kgdb8250_ttyS]
+#define KGDB8250_IRQ		CURRENTPORT.irq
+#define KGDB8250_REG_SHIFT	CURRENTPORT.regshift
+
+/* Base of the UART. */
+static void *kgdb8250_addr;
+
+/* Forward declarations. */
+static int kgdb8250_init(void);
+static int kgdb_init_io(void);
+static int __init kgdb8250_opt(char *str);
+static void __init kgdb8250_hookup_irq(void);
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void kgdb_put_debug_char(u8 chr)
+{
+	while (!(ioread8(kgdb8250_addr + (UART_LSR << KGDB8250_REG_SHIFT)) &
+		 UART_LSR_THRE)) ;
+
+	iowrite8(chr, kgdb8250_addr + (UART_TX << KGDB8250_REG_SHIFT));
+}
+
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int read_data_bfr(void)
+{
+	char it = ioread8(kgdb8250_addr + (UART_LSR << KGDB8250_REG_SHIFT));
+
+	if (it & UART_LSR_DR)
+		return ioread8(kgdb8250_addr +
+				  (UART_RX << KGDB8250_REG_SHIFT));
+
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		kgdb8250_init();
+		kgdb_put_debug_char('-');
+		return '-';
+	}
+
+	return -1;
+}
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+ */
+
+static int kgdb_get_debug_char(void)
+{
+	int retchr;
+
+	/* intr routine has q'd chars */
+	if (atomic_read(&kgdb8250_buf_in_cnt) != 0) {
+		retchr = kgdb8250_buf[kgdb8250_buf_out_inx++];
+		kgdb8250_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&kgdb8250_buf_in_cnt);
+		return retchr;
+	}
+
+	do {
+		retchr = read_data_bfr();
+	} while (retchr < 0);
+
+	return retchr;
+}
+
+/*
+ * 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, struct pt_regs *regs)
+{
+	char iir;
+
+	if (irq != KGDB8250_IRQ)
+		return IRQ_NONE;
+	/*
+	 * If  there is some other CPU in KGDB then this is a
+	 * spurious interrupt. so return without even checking a byte
+	 */
+	if (atomic_read(&debugger_active))
+		return IRQ_NONE;
+
+	iir = ioread8(kgdb8250_addr + (UART_IIR << KGDB8250_REG_SHIFT));
+	if (iir & UART_IIR_RDI) {
+		if (kgdb_io_ops.init != kgdb_init_io) {
+			/* Throw away the data if another I/O routine
+			 * is active.
+			 */
+			char it = ioread8(kgdb8250_addr +
+					     (UART_LSR << KGDB8250_REG_SHIFT));
+			if (it & UART_LSR_DR)
+				ioread8(kgdb8250_addr +
+					   (UART_RX << KGDB8250_REG_SHIFT));
+		} else
+			breakpoint();
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Returns:
+ *	0 on success, 1 on failure.
+ */
+static int kgdb8250_init(void)
+{
+	unsigned cval;
+	int bits = 8;
+	int parity = 'n';
+	int cflag = CREAD | HUPCL | CLOCAL;
+	char ier = UART_IER_RDI;
+	unsigned int base_baud;
+
+	base_baud = CURRENTPORT.uartclk ? CURRENTPORT.uartclk / 16 : BASE_BAUD;
+
+	/*
+	 *      Now construct a cflag setting.
+	 */
+	switch (kgdb8250_baud) {
+	case 1200:
+		cflag |= B1200;
+		break;
+	case 2400:
+		cflag |= B2400;
+		break;
+	case 4800:
+		cflag |= B4800;
+		break;
+	case 19200:
+		cflag |= B19200;
+		break;
+	case 38400:
+		cflag |= B38400;
+		break;
+	case 57600:
+		cflag |= B57600;
+		break;
+	case 115200:
+		cflag |= B115200;
+		break;
+	default:
+		kgdb8250_baud = 9600;
+		/* Fall through */
+	case 9600:
+		cflag |= B9600;
+		break;
+	}
+	switch (bits) {
+	case 7:
+		cflag |= CS7;
+		break;
+	default:
+	case 8:
+		cflag |= CS8;
+		break;
+	}
+	switch (parity) {
+	case 'o':
+	case 'O':
+		cflag |= PARODD;
+		break;
+	case 'e':
+	case 'E':
+		cflag |= PARENB;
+		break;
+	}
+
+	/*
+	 *      Divisor, bytesize and parity
+	 *
+	 */
+
+	cval = cflag & (CSIZE | CSTOPB);
+	cval >>= 4;
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	/* Disable UART interrupts, set DTR and RTS high and set speed. */
+	cval = 0x3;
+#if defined(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;
+			iowrite8(1, kgdb8250_addr +
+				    (UART_OMAP_OSC_12M_SEL <<
+				     KGDB8250_REG_SHIFT));
+		} else {
+			iowrite8(0, kgdb8250_addr +
+				    (UART_OMAP_OSC_12M_SEL <<
+				     KGDB8250_REG_SHIFT));
+		}
+	}
+#endif
+	/* set DLAB */
+	iowrite8(cval | UART_LCR_DLAB, kgdb8250_addr +
+		    (UART_LCR << KGDB8250_REG_SHIFT));
+	/* LS */
+	iowrite8(base_baud / kgdb8250_baud & 0xff, kgdb8250_addr +
+		    (UART_DLL << KGDB8250_REG_SHIFT));
+	/* MS  */
+	iowrite8(base_baud / kgdb8250_baud >> 8, kgdb8250_addr +
+		    (UART_DLM << KGDB8250_REG_SHIFT));
+	/* reset DLAB */
+	iowrite8(cval, kgdb8250_addr + (UART_LCR << KGDB8250_REG_SHIFT));
+
+	/*
+	 * XScale-specific bits that need to be set
+	 */
+	if (CURRENTPORT.type == PORT_XSCALE)
+		ier |= UART_IER_UUE | UART_IER_RTOIE;
+
+	/* turn on interrupts */
+	iowrite8(ier, kgdb8250_addr + (UART_IER << KGDB8250_REG_SHIFT));
+	iowrite8(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS,
+		    kgdb8250_addr + (UART_MCR << KGDB8250_REG_SHIFT));
+
+	/*
+	 *      If we read 0xff from the LSR, there is no UART here.
+	 */
+	if (ioread8(kgdb8250_addr + (UART_LSR << KGDB8250_REG_SHIFT)) ==
+	    0xff)
+		return -1;
+	return 0;
+}
+
+/*
+ * Copy the old serial_state table to our uart_port table if we haven't
+ * had values specifically configured in.  We need to make sure this only
+ * happens once.
+ */
+static void __init kgdb8250_copy_rs_table(void)
+{
+#ifdef CONFIG_KGDB_SIMPLE_SERIAL
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(old_rs_table); i++) {
+		kgdb8250_ports[i].iobase = old_rs_table[i].port;
+		kgdb8250_ports[i].irq = irq_canonicalize(old_rs_table[i].irq);
+		kgdb8250_ports[i].uartclk = old_rs_table[i].baud_base * 16;
+		kgdb8250_ports[i].membase = old_rs_table[i].iomem_base;
+		kgdb8250_ports[i].iotype = old_rs_table[i].io_type;
+		kgdb8250_ports[i].regshift = old_rs_table[i].iomem_reg_shift;
+		kgdb8250_ports[i].line = i;
+	}
+#endif
+
+	old_rs_table_copied = 1;
+}
+
+/*
+ * Perform static initalization tasks which we need to always do,
+ * even if KGDB isn't going to be invoked immediately.
+ */
+static int kgdb8250_local_init(void)
+{
+	if (old_rs_table_copied == 0)
+		kgdb8250_copy_rs_table();
+
+	switch (CURRENTPORT.iotype) {
+	case UPIO_MEM:
+		if (CURRENTPORT.mapbase)
+			kgdb8250_needs_request_mem_region = 1;
+		if (CURRENTPORT.flags & UPF_IOREMAP) {
+			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
+						      8 << KGDB8250_REG_SHIFT);
+			if (!CURRENTPORT.membase)
+				return 1;	/* Failed. */
+		}
+		kgdb8250_addr = CURRENTPORT.membase;
+		break;
+	case UPIO_PORT:
+	default:
+		kgdb8250_addr = ioport_map(CURRENTPORT.iobase,
+				8 << KGDB8250_REG_SHIFT);
+		if (!kgdb8250_addr)
+			return 1;	/* Failed. */
+	}
+
+	return 0;
+}
+
+static int kgdb_init_io(void)
+{
+#ifdef CONFIG_KGDB_8250_MODULE
+	if (strlen(config)) {
+		if (kgdb8250_opt(config))
+			return -EINVAL;
+	} else {
+		printk(KERN_ERR "kgdb8250: argument error, usage: "
+		       "kgdb8250=<port number>,<baud rate>");
+#ifdef CONFIG_IA64
+		printk(",<irq>,<iomem base>");
+#endif
+		printk("\n");
+		return -EINVAL;
+	}
+#endif				/* CONFIG_KGDB_8250_MODULE */
+
+	if (kgdb8250_local_init()) {
+		printk(KERN_ERR "kgdb8250: local init failed\n");
+		return -EIO;
+	}
+
+	if (kgdb8250_init() == -1) {
+		printk(KERN_ERR "kgdb8250: init failed\n");
+		return -EIO;
+	}
+#ifdef CONFIG_KGDB_8250_MODULE
+	/* Attach the kgdb irq. When this is built into the kernel, it
+	 * is called as a part of late_init sequence.
+	 */
+	kgdb8250_hookup_irq();
+	if (kgdb_register_io_module(&local_kgdb_io_ops))
+		return -EINVAL;
+
+	printk(KERN_INFO "kgdb8250: debugging enabled\n");
+#endif				/* CONFIG_KGD_8250_MODULE */
+
+	return 0;
+}
+
+/*
+ * Hookup our IRQ line.  We will already have been initialized at
+ * this point.
+ */
+static void __init kgdb8250_hookup_irq(void)
+{
+#if defined(CONFIG_SERIAL_8250) || defined (CONFIG_SERIAL_8250_MODULE)
+	/* Take the port away from the main driver. */
+	serial8250_unregister_by_port(&CURRENTPORT);
+
+	/* Now reinit the port as the above has disabled things. */
+	kgdb8250_init();
+#endif
+	/* We may need to call request_mem_region() first. */
+	if (kgdb8250_needs_request_mem_region)
+		request_mem_region(CURRENTPORT.mapbase,
+				   8 << KGDB8250_REG_SHIFT, "kgdb");
+	if (request_irq(KGDB8250_IRQ, kgdb8250_interrupt, SA_SHIRQ,
+		    "GDB-stub", &CURRENTPORT) < 0)
+		printk(KERN_ERR "KGDB failed to request the serial IRQ (%d)\n",
+				KGDB8250_IRQ);
+}
+
+#ifdef CONFIG_KGDB_8250_MODULE
+/* If it is a module the kgdb_io_ops should be a static which
+ * is passed to the KGDB I/O initialization
+ */
+static
+struct kgdb_io local_kgdb_io_ops = {
+#else				/* ! CONFIG_KGDB_8250_MODULE */
+struct kgdb_io kgdb_io_ops = {
+#endif				/* ! CONFIG_KGD_8250_MODULE */
+	.read_char = kgdb_get_debug_char,
+	.write_char = kgdb_put_debug_char,
+	.init = kgdb_init_io,
+	.late_init = kgdb8250_hookup_irq,
+	.pre_exception = NULL,
+	.post_exception = NULL
+};
+
+/**
+ * 	kgdb8250_get_ttyS - Return the index of the UART used by kgdb,
+ *	matches ttySX naming.
+ */
+int kgdb8250_get_ttyS(void)
+{
+	return kgdb8250_ttyS;
+}
+
+/**
+ * 	kgdb8250_add_port - Define a serial port for use with KGDB
+ * 	@i: The index of the port being added
+ * 	@serial_req: The &struct uart_port describing the port
+ *
+ * 	On platforms where we must register the serial device
+ * 	dynamically, this is the best option if a platform also normally
+ * 	calls early_serial_setup().
+ */
+void kgdb8250_add_port(int i, struct uart_port *serial_req)
+{
+	/* Copy the old table in if needed. */
+	if (old_rs_table_copied == 0)
+		kgdb8250_copy_rs_table();
+
+	/* Copy the whole thing over. */
+	memcpy(&kgdb8250_ports[i], serial_req, sizeof(struct uart_port));
+}
+
+/**
+ * 	kgdb8250_add_platform_port - Define a serial port for use with KGDB
+ * 	@i: The index of the port being added
+ * 	@p: The &struct plat_serial8250_port describing the port
+ *
+ * 	On platforms where we must register the serial device
+ * 	dynamically, this is the best option if a platform normally
+ * 	handles uart setup with an array of &struct plat_serial8250_port.
+ */
+void kgdb8250_add_platform_port(int i, struct plat_serial8250_port *p)
+{
+	/* Copy the old table in if needed. */
+	if (old_rs_table_copied == 0)
+		kgdb8250_copy_rs_table();
+
+	kgdb8250_ports[i].iobase = p->iobase;
+	kgdb8250_ports[i].membase = p->membase;
+	kgdb8250_ports[i].irq = p->irq;
+	kgdb8250_ports[i].uartclk = p->uartclk;
+	kgdb8250_ports[i].regshift = p->regshift;
+	kgdb8250_ports[i].iotype = p->iotype;
+	kgdb8250_ports[i].flags = p->flags;
+	kgdb8250_ports[i].mapbase = p->mapbase;
+	kgdb8250_ports[i].line = p->line;
+}
+
+/*
+ * Syntax for this cmdline option is "kgdb8250=ttyno,baudrate"
+ * with ",irq,iomembase" tacked on the end on IA64.
+ */
+static int __init kgdb8250_opt(char *str)
+{
+	if (*str < '0' || *str > '3')
+		goto errout;
+	kgdb8250_ttyS = *str - '0';
+	str++;
+	if (*str != ',')
+		goto errout;
+	str++;
+	kgdb8250_baud = simple_strtoul(str, &str, 10);
+	if (kgdb8250_baud != 9600 && kgdb8250_baud != 19200 &&
+	    kgdb8250_baud != 38400 && kgdb8250_baud != 57600 &&
+	    kgdb8250_baud != 115200)
+		goto errout;
+
+#ifdef CONFIG_IA64
+	if (*str == ',') {
+		str++;
+		KGDB8250_IRQ = simple_strtoul(str, &str, 10);
+		if (*str == ',') {
+			str++;
+			CURRENTPORT.iotype = SERIAL_IO_MEM;
+			CURRENTPORT.membase =
+			    (unsigned char *)simple_strtoul(str, &str, 0);
+		}
+	}
+#endif
+
+	return 0;
+
+      errout:
+	printk(KERN_ERR "Invalid syntax for option kgdb8250=\n");
+	return 1;
+}
+
+#ifdef CONFIG_KGDB_8250_MODULE
+static void cleanup_kgdb8250(void)
+{
+	kgdb_unregister_io_module(&local_kgdb_io_ops);
+
+	/* Clean up the irq and memory */
+	free_irq(KGDB8250_IRQ, &CURRENTPORT);
+
+	if (kgdb8250_needs_request_mem_region)
+		release_mem_region(CURRENTPORT.mapbase,
+				   8 << KGDB8250_REG_SHIFT);
+	/* Hook up the serial port back to what it was previously
+	 * hooked up to.
+	 */
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+	/* Give the port back to the 8250 driver. */
+	serial8250_register_port(&CURRENTPORT);
+#endif
+}
+
+module_init(kgdb_init_io);
+module_exit(cleanup_kgdb8250);
+#else				/* ! CONFIG_KGDB_8250_MODULE */
+early_param("kgdb8250", kgdb8250_opt);
+#endif				/* ! CONFIG_KGDB_8250_MODULE */
diff -puN drivers/serial/Makefile~8250 drivers/serial/Makefile
--- linux-2.6.13/drivers/serial/Makefile~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/drivers/serial/Makefile	2005-08-15 07:53:39.000000000 -0700
@@ -57,3 +57,4 @@ obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+obj-$(CONFIG_KGDB_8250) += kgdb_8250.o
diff -puN include/linux/kgdb.h~8250 include/linux/kgdb.h
--- linux-2.6.13/include/linux/kgdb.h~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/include/linux/kgdb.h	2005-08-16 14:57:32.000000000 -0700
@@ -224,7 +224,7 @@ typedef unsigned char threadref[8];
  */
 struct kgdb_io {
 	int (*read_char) (void);
-	void (*write_char) (int);
+	void (*write_char) (u8);
 	void (*flush) (void);
 	int (*init) (void);
 	void (*late_init) (void);
@@ -241,6 +241,7 @@ extern void kgdb_unregister_io_module(st
 
 extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
 extern void kgdb8250_add_platform_port(int i, struct plat_serial8250_port *serial_req);
+extern int kgdb8250_get_ttyS(void);
 
 extern int kgdb_hex2long(char **ptr, long *long_val);
 extern char *kgdb_mem2hex(char *mem, char *buf, int count);
diff -puN include/linux/serial_8250.h~8250 include/linux/serial_8250.h
--- linux-2.6.13/include/linux/serial_8250.h~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/include/linux/serial_8250.h	2005-08-15 07:53:39.000000000 -0700
@@ -24,6 +24,7 @@ struct plat_serial8250_port {
 	unsigned char	iotype;		/* UPIO_* */
 	unsigned char	hub6;
 	unsigned int	flags;		/* UPF_* flags */
+	unsigned int	line;		/* logical line number */
 };
 
 #endif
diff -puN lib/Kconfig.debug~8250 lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~8250	2005-08-15 07:53:39.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-16 15:13:22.000000000 -0700
@@ -188,7 +188,7 @@ config KGDB_CONSOLE
 choice
 	prompt "Method for KGDB communication"
 	depends on KGDB
-	default KGDB_ONLY_MODULES
+	default KGDB_8250_NOMODULE
 	default KGDB_MPSC if SERIAL_MPSC
 	help
 	  There are a number of different ways in which you can communicate
@@ -206,6 +206,14 @@ config KGDB_ONLY_MODULES
 	  Use only kernel modules to configure KGDB I/O after the
 	  kernel is booted.
 
+config KGDB_8250_NOMODULE
+	bool "KGDB: On generic serial port (8250)"
+	select KGDB_8250
+	help
+	  Uses generic serial port (8250) to communicate with the host
+	  GDB.  This is independent of the normal (SERIAL_8250) driver
+	  for this chipset.
+
 config KGDB_MPSC
 	bool "KGDB on MV64x60 MPSC"
 	depends on SERIAL_MPSC
@@ -213,4 +221,86 @@ config KGDB_MPSC
 	  Uses a Marvell GT64260B or MV64x60 Multi-Purpose Serial
 	  Controller (MPSC) channel. Note that the GT64260A is not
 	  supported.
+
 endchoice
+
+config KGDB_8250
+	tristate "KGDB: On generic serial port (8250)" if !KGDB_8250_NOMODULE
+	depends on m && KGDB_ONLY_MODULES
+	help
+	  Uses generic serial port (8250) to communicate with the host
+	  GDB.  This is independent of the normal (SERIAL_8250) driver
+	  for this chipset.
+
+config KGDB_SIMPLE_SERIAL
+	bool "Simple selection of KGDB serial port"
+	depends on KGDB_8250
+	default y
+	help
+	  If you say Y here, you will only have to pick the baud rate
+	  and serial port (ttyS) that you wish to use for KGDB.  If you
+	  say N, you will have provide the I/O port and IRQ number.  Note
+	  that if your serial ports are iomapped, such as on ia64, then
+	  you must say Y here.  If in doubt, say Y.
+
+choice
+    	prompt "Debug serial port BAUD"
+	depends on KGDB_8250
+	default KGDB_115200BAUD
+	help
+	  gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Standard rates from 9600 to 115200 are allowed, and this
+	  may be overridden via the commandline.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+choice
+	prompt "Serial port for KGDB"
+	depends on KGDB_SIMPLE_SERIAL
+	default KGDB_PORT_0
+
+config KGDB_PORT_0
+	bool "Primary serial port"
+
+config KGDB_PORT_1
+	bool "First serial port"
+
+config KGDB_PORT_2
+	bool "Second serial port"
+
+config KGDB_PORT_3
+	bool "Third serial port"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
+	default 3f8
+	help
+	  This is the unmapped (and on platforms with 1:1 mapping
+	  this is typically, but not always the same as the mapped)
+	  address of the serial port.  The stanards on your architecture
+	  may be found in include/asm-$(ARCH)/serial.h.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
+	default 4
+	help
+	  This is the IRQ for the debug port.  This must be known so that
+	  KGDB can interrupt the running system (either for a new
+	  connection or when in gdb and control-C is issued).
_

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

* [patch 05/16] Add support for MIPS platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (2 preceding siblings ...)
  2005-08-29 16:09   ` [patch 04/16] I/O driver for 8250-compatible UARTs Tom Rini
@ 2005-08-29 16:09   ` Tom Rini
  2005-08-29 16:10   ` [patch 06/16] Add support for IA64 " Tom Rini
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:09 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, mlachwani, ralf


This adds basic support to the MIPS architecture as well as support
specifically for the MIPS Malta and SiByte 1250-SWARM (32 and 64bit), all from
Manish Lachwani.  This looks like it should work on anything with an
8250-compatible uart, and be fairly easy to convert other boards custom uarts
as needed.

---

 linux-2.6.13-trini/arch/mips/Kconfig.debug                   |   19 
 linux-2.6.13-trini/arch/mips/kernel/Makefile                 |    3 
 linux-2.6.13-trini/arch/mips/kernel/irq.c                    |   32 
 linux-2.6.13-trini/arch/mips/kernel/kgdb-jmp.c               |  116 +
 linux-2.6.13-trini/arch/mips/kernel/kgdb-setjmp.S            |   27 
 linux-2.6.13-trini/arch/mips/kernel/kgdb.c                   |  296 ++
 linux-2.6.13-trini/arch/mips/kernel/kgdb_handler.S           |   58 
 linux-2.6.13-trini/arch/mips/kernel/traps.c                  |   26 
 linux-2.6.13-trini/arch/mips/mips-boards/generic/Makefile    |    1 
 linux-2.6.13-trini/arch/mips/mips-boards/generic/init.c      |   62 
 linux-2.6.13-trini/arch/mips/mips-boards/malta/malta_setup.c |    8 
 linux-2.6.13-trini/arch/mips/mm/extable.c                    |    7 
 linux-2.6.13-trini/arch/mips/sibyte/cfe/setup.c              |   14 
 linux-2.6.13-trini/arch/mips/sibyte/sb1250/Makefile          |    1 
 linux-2.6.13-trini/arch/mips/sibyte/sb1250/irq.c             |   57 
 linux-2.6.13-trini/arch/mips/sibyte/sb1250/irq_handler.S     |    2 
 linux-2.6.13-trini/arch/mips/sibyte/sb1250/kgdb_sibyte.c     |  164 +
 linux-2.6.13-trini/arch/mips/sibyte/swarm/Makefile           |    2 
 linux-2.6.13-trini/include/asm-mips/kdebug.h                 |   47 
 linux-2.6.13-trini/include/asm-mips/kgdb.h                   |   22 
 linux-2.6.13-trini/lib/Kconfig.debug                         |    7 
 linux-2.6.13/arch/mips/kernel/gdb-low.S                      |  370 ---
 linux-2.6.13/arch/mips/kernel/gdb-stub.c                     | 1091 ----------
 linux-2.6.13/arch/mips/sibyte/swarm/dbg_io.c                 |   76 
 24 files changed, 791 insertions(+), 1717 deletions(-)

diff -puN arch/mips/Kconfig.debug~mips-lite arch/mips/Kconfig.debug
--- linux-2.6.13/arch/mips/Kconfig.debug~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/Kconfig.debug	2005-08-16 17:32:26.000000000 -0700
@@ -27,25 +27,6 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
-config KGDB
-	bool "Remote GDB kernel debugging"
-	depends on DEBUG_KERNEL
-	select DEBUG_INFO
-	help
-	  If you say Y here, it will be possible to remotely debug the MIPS
-	  kernel using gdb. This enlarges your kernel image disk size by
-	  several megabytes and requires a machine with more than 16 MB,
-	  better 32 MB RAM to avoid excessive linking time. This is only
-	  useful for kernel hackers. If unsure, say N.
-
-config GDB_CONSOLE
-	bool "Console output to GDB"
-	depends on KGDB
-	help
-	  If you are using GDB for remote debugging over a serial port and
-	  would like kernel messages to be formatted into GDB $O packets so
-	  that GDB prints them as program output, say 'Y'.
-
 config SB1XXX_CORELIS
 	bool "Corelis Debugger"
 	depends on SIBYTE_SB1xxx_SOC
diff -L arch/mips/kernel/gdb-low.S -puN arch/mips/kernel/gdb-low.S~mips-lite /dev/null
--- linux-2.6.13/arch/mips/kernel/gdb-low.S
+++ /dev/null	2005-08-15 07:19:53.144310000 -0700
@@ -1,370 +0,0 @@
-/*
- * gdb-low.S contains the low-level trap handler for the GDB stub.
- *
- * Copyright (C) 1995 Andreas Busse
- */
-#include <linux/config.h>
-#include <linux/sys.h>
-
-#include <asm/asm.h>
-#include <asm/errno.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/gdb-stub.h>
-
-#ifdef CONFIG_MIPS32
-#define DMFC0	mfc0
-#define DMTC0	mtc0
-#define LDC1	lwc1
-#define SDC1	lwc1
-#endif
-#ifdef CONFIG_MIPS64
-#define DMFC0	dmfc0
-#define DMTC0	dmtc0
-#define LDC1	ldc1
-#define SDC1	ldc1
-#endif
-
-/*
- * [jsun] We reserves about 2x GDB_FR_SIZE in stack.  The lower (addressed)
- * part is used to store registers and passed to exception handler.
- * The upper part is reserved for "call func" feature where gdb client
- * saves some of the regs, setups call frame and passes args.
- *
- * A trace shows about 200 bytes are used to store about half of all regs.
- * The rest should be big enough for frame setup and passing args.
- */
-
-/*
- * The low level trap handler
- */
-		.align 	5
-		NESTED(trap_low, GDB_FR_SIZE, sp)
- 		.set	noat
-		.set 	noreorder
-
-		mfc0	k0, CP0_STATUS
-		sll	k0, 3     		/* extract cu0 bit */
-		bltz	k0, 1f
-		move	k1, sp
-
-		/*
-		 * Called from user mode, go somewhere else.
-		 */
-		lui	k1, %hi(saved_vectors)
-		mfc0	k0, CP0_CAUSE
-		andi	k0, k0, 0x7c
-		add	k1, k1, k0
-		lw	k0, %lo(saved_vectors)(k1)
-		jr	k0
-		nop
-1:
-		move	k0, sp
-		subu	sp, k1, GDB_FR_SIZE*2	# see comment above
-		LONG_S	k0, GDB_FR_REG29(sp)
-		LONG_S	$2, GDB_FR_REG2(sp)
-
-/*
- * First save the CP0 and special registers
- */
-
-		mfc0	v0, CP0_STATUS
-		LONG_S	v0, GDB_FR_STATUS(sp)
-		mfc0	v0, CP0_CAUSE
-		LONG_S	v0, GDB_FR_CAUSE(sp)
-		DMFC0	v0, CP0_EPC
-		LONG_S	v0, GDB_FR_EPC(sp)
-		DMFC0	v0, CP0_BADVADDR
-		LONG_S	v0, GDB_FR_BADVADDR(sp)
-		mfhi	v0
-		LONG_S	v0, GDB_FR_HI(sp)
-		mflo	v0
-		LONG_S	v0, GDB_FR_LO(sp)
-
-/*
- * Now the integer registers
- */
-
-		LONG_S	zero, GDB_FR_REG0(sp)		/* I know... */
-		LONG_S	$1, GDB_FR_REG1(sp)
-		/* v0 already saved */
-		LONG_S	$3, GDB_FR_REG3(sp)
-		LONG_S	$4, GDB_FR_REG4(sp)
-		LONG_S	$5, GDB_FR_REG5(sp)
-		LONG_S	$6, GDB_FR_REG6(sp)
-		LONG_S	$7, GDB_FR_REG7(sp)
-		LONG_S	$8, GDB_FR_REG8(sp)
-		LONG_S	$9, GDB_FR_REG9(sp)
-		LONG_S	$10, GDB_FR_REG10(sp)
-		LONG_S	$11, GDB_FR_REG11(sp)
-		LONG_S	$12, GDB_FR_REG12(sp)
-		LONG_S	$13, GDB_FR_REG13(sp)
-		LONG_S	$14, GDB_FR_REG14(sp)
-		LONG_S	$15, GDB_FR_REG15(sp)
-		LONG_S	$16, GDB_FR_REG16(sp)
-		LONG_S	$17, GDB_FR_REG17(sp)
-		LONG_S	$18, GDB_FR_REG18(sp)
-		LONG_S	$19, GDB_FR_REG19(sp)
-		LONG_S	$20, GDB_FR_REG20(sp)
-		LONG_S	$21, GDB_FR_REG21(sp)
-		LONG_S	$22, GDB_FR_REG22(sp)
-		LONG_S	$23, GDB_FR_REG23(sp)
-		LONG_S	$24, GDB_FR_REG24(sp)
-		LONG_S	$25, GDB_FR_REG25(sp)
-		LONG_S	$26, GDB_FR_REG26(sp)
-		LONG_S	$27, GDB_FR_REG27(sp)
-		LONG_S	$28, GDB_FR_REG28(sp)
-		/* sp already saved */
-		LONG_S	$30, GDB_FR_REG30(sp)
-		LONG_S	$31, GDB_FR_REG31(sp)
-
-		CLI				/* disable interrupts */
-
-/*
- * Followed by the floating point registers
- */
-		mfc0	v0, CP0_STATUS		/* FPU enabled? */
-		srl	v0, v0, 16
-		andi	v0, v0, (ST0_CU1 >> 16)
-
-		beqz	v0,2f			/* disabled, skip */
-		 nop
-
-		SDC1	$0, GDB_FR_FPR0(sp)
-		SDC1	$1, GDB_FR_FPR1(sp)
-		SDC1	$2, GDB_FR_FPR2(sp)
-		SDC1	$3, GDB_FR_FPR3(sp)
-		SDC1	$4, GDB_FR_FPR4(sp)
-		SDC1	$5, GDB_FR_FPR5(sp)
-		SDC1	$6, GDB_FR_FPR6(sp)
-		SDC1	$7, GDB_FR_FPR7(sp)
-		SDC1	$8, GDB_FR_FPR8(sp)
-		SDC1	$9, GDB_FR_FPR9(sp)
-		SDC1	$10, GDB_FR_FPR10(sp)
-		SDC1	$11, GDB_FR_FPR11(sp)
-		SDC1	$12, GDB_FR_FPR12(sp)
-		SDC1	$13, GDB_FR_FPR13(sp)
-		SDC1	$14, GDB_FR_FPR14(sp)
-		SDC1	$15, GDB_FR_FPR15(sp)
-		SDC1	$16, GDB_FR_FPR16(sp)
-		SDC1	$17, GDB_FR_FPR17(sp)
-		SDC1	$18, GDB_FR_FPR18(sp)
-		SDC1	$19, GDB_FR_FPR19(sp)
-		SDC1	$20, GDB_FR_FPR20(sp)
-		SDC1	$21, GDB_FR_FPR21(sp)
-		SDC1	$22, GDB_FR_FPR22(sp)
-		SDC1	$23, GDB_FR_FPR23(sp)
-		SDC1	$24, GDB_FR_FPR24(sp)
-		SDC1	$25, GDB_FR_FPR25(sp)
-		SDC1	$26, GDB_FR_FPR26(sp)
-		SDC1	$27, GDB_FR_FPR27(sp)
-		SDC1	$28, GDB_FR_FPR28(sp)
-		SDC1	$29, GDB_FR_FPR29(sp)
-		SDC1	$30, GDB_FR_FPR30(sp)
-		SDC1	$31, GDB_FR_FPR31(sp)
-
-/*
- * FPU control registers
- */
-
-		cfc1	v0, CP1_STATUS
-		LONG_S	v0, GDB_FR_FSR(sp)
-		cfc1	v0, CP1_REVISION
-		LONG_S	v0, GDB_FR_FIR(sp)
-
-/*
- * Current stack frame ptr
- */
-
-2:
-		LONG_S	sp, GDB_FR_FRP(sp)
-
-/*
- * CP0 registers (R4000/R4400 unused registers skipped)
- */
-
-		mfc0	v0, CP0_INDEX
-		LONG_S	v0, GDB_FR_CP0_INDEX(sp)
-		mfc0	v0, CP0_RANDOM
-		LONG_S	v0, GDB_FR_CP0_RANDOM(sp)
-		DMFC0	v0, CP0_ENTRYLO0
-		LONG_S	v0, GDB_FR_CP0_ENTRYLO0(sp)
-		DMFC0	v0, CP0_ENTRYLO1
-		LONG_S	v0, GDB_FR_CP0_ENTRYLO1(sp)
-		DMFC0	v0, CP0_CONTEXT
-		LONG_S	v0, GDB_FR_CP0_CONTEXT(sp)
-		mfc0	v0, CP0_PAGEMASK
-		LONG_S	v0, GDB_FR_CP0_PAGEMASK(sp)
-		mfc0	v0, CP0_WIRED
-		LONG_S	v0, GDB_FR_CP0_WIRED(sp)
-		DMFC0	v0, CP0_ENTRYHI
-		LONG_S	v0, GDB_FR_CP0_ENTRYHI(sp)
-		mfc0	v0, CP0_PRID
-		LONG_S	v0, GDB_FR_CP0_PRID(sp)
-
-		.set	at
-
-/*
- * Continue with the higher level handler
- */
-
-		move	a0,sp
-
-		jal	handle_exception
-		 nop
-
-/*
- * Restore all writable registers, in reverse order
- */
-
-		.set	noat
-
-		LONG_L	v0, GDB_FR_CP0_ENTRYHI(sp)
-		LONG_L	v1, GDB_FR_CP0_WIRED(sp)
-		DMTC0	v0, CP0_ENTRYHI
-		mtc0	v1, CP0_WIRED
-		LONG_L	v0, GDB_FR_CP0_PAGEMASK(sp)
-		LONG_L	v1, GDB_FR_CP0_ENTRYLO1(sp)
-		mtc0	v0, CP0_PAGEMASK
-		DMTC0	v1, CP0_ENTRYLO1
-		LONG_L	v0, GDB_FR_CP0_ENTRYLO0(sp)
-		LONG_L	v1, GDB_FR_CP0_INDEX(sp)
-		DMTC0	v0, CP0_ENTRYLO0
-		LONG_L	v0, GDB_FR_CP0_CONTEXT(sp)
-		mtc0	v1, CP0_INDEX
-		DMTC0	v0, CP0_CONTEXT
-
-
-/*
- * Next, the floating point registers
- */
-		mfc0	v0, CP0_STATUS		/* check if the FPU is enabled */
-		srl	v0, v0, 16
-		andi	v0, v0, (ST0_CU1 >> 16)
-
-		beqz	v0, 3f			/* disabled, skip */
-		 nop
-
-		LDC1	$31, GDB_FR_FPR31(sp)
-		LDC1	$30, GDB_FR_FPR30(sp)
-		LDC1	$29, GDB_FR_FPR29(sp)
-		LDC1	$28, GDB_FR_FPR28(sp)
-		LDC1	$27, GDB_FR_FPR27(sp)
-		LDC1	$26, GDB_FR_FPR26(sp)
-		LDC1	$25, GDB_FR_FPR25(sp)
-		LDC1	$24, GDB_FR_FPR24(sp)
-		LDC1	$23, GDB_FR_FPR23(sp)
-		LDC1	$22, GDB_FR_FPR22(sp)
-		LDC1	$21, GDB_FR_FPR21(sp)
-		LDC1	$20, GDB_FR_FPR20(sp)
-		LDC1	$19, GDB_FR_FPR19(sp)
-		LDC1	$18, GDB_FR_FPR18(sp)
-		LDC1	$17, GDB_FR_FPR17(sp)
-		LDC1	$16, GDB_FR_FPR16(sp)
-		LDC1	$15, GDB_FR_FPR15(sp)
-		LDC1	$14, GDB_FR_FPR14(sp)
-		LDC1	$13, GDB_FR_FPR13(sp)
-		LDC1	$12, GDB_FR_FPR12(sp)
-		LDC1	$11, GDB_FR_FPR11(sp)
-		LDC1	$10, GDB_FR_FPR10(sp)
-		LDC1	$9, GDB_FR_FPR9(sp)
-		LDC1	$8, GDB_FR_FPR8(sp)
-		LDC1	$7, GDB_FR_FPR7(sp)
-		LDC1	$6, GDB_FR_FPR6(sp)
-		LDC1	$5, GDB_FR_FPR5(sp)
-		LDC1	$4, GDB_FR_FPR4(sp)
-		LDC1	$3, GDB_FR_FPR3(sp)
-		LDC1	$2, GDB_FR_FPR2(sp)
-		LDC1	$1, GDB_FR_FPR1(sp)
-		LDC1	$0, GDB_FR_FPR0(sp)
-
-/*
- * Now the CP0 and integer registers
- */
-
-3:
-		mfc0	t0, CP0_STATUS
-		ori	t0, 0x1f
-		xori	t0, 0x1f
-		mtc0	t0, CP0_STATUS
-
-		LONG_L	v0, GDB_FR_STATUS(sp)
-		LONG_L	v1, GDB_FR_EPC(sp)
-		mtc0	v0, CP0_STATUS
-		DMTC0	v1, CP0_EPC
-		LONG_L	v0, GDB_FR_HI(sp)
-		LONG_L	v1, GDB_FR_LO(sp)
-		mthi	v0
-		mtlo	v1
-		LONG_L	$31, GDB_FR_REG31(sp)
-		LONG_L	$30, GDB_FR_REG30(sp)
-		LONG_L	$28, GDB_FR_REG28(sp)
-		LONG_L	$27, GDB_FR_REG27(sp)
-		LONG_L	$26, GDB_FR_REG26(sp)
-		LONG_L	$25, GDB_FR_REG25(sp)
-		LONG_L	$24, GDB_FR_REG24(sp)
-		LONG_L	$23, GDB_FR_REG23(sp)
-		LONG_L	$22, GDB_FR_REG22(sp)
-		LONG_L	$21, GDB_FR_REG21(sp)
-		LONG_L	$20, GDB_FR_REG20(sp)
-		LONG_L	$19, GDB_FR_REG19(sp)
-		LONG_L	$18, GDB_FR_REG18(sp)
-		LONG_L	$17, GDB_FR_REG17(sp)
-		LONG_L	$16, GDB_FR_REG16(sp)
-		LONG_L	$15, GDB_FR_REG15(sp)
-		LONG_L	$14, GDB_FR_REG14(sp)
-		LONG_L	$13, GDB_FR_REG13(sp)
-		LONG_L	$12, GDB_FR_REG12(sp)
-		LONG_L	$11, GDB_FR_REG11(sp)
-		LONG_L	$10, GDB_FR_REG10(sp)
-		LONG_L	$9, GDB_FR_REG9(sp)
-		LONG_L	$8, GDB_FR_REG8(sp)
-		LONG_L	$7, GDB_FR_REG7(sp)
-		LONG_L	$6, GDB_FR_REG6(sp)
-		LONG_L	$5, GDB_FR_REG5(sp)
-		LONG_L	$4, GDB_FR_REG4(sp)
-		LONG_L	$3, GDB_FR_REG3(sp)
-		LONG_L	$2, GDB_FR_REG2(sp)
-		LONG_L	$1, GDB_FR_REG1(sp)
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-		LONG_L	k0, GDB_FR_EPC(sp)
-		LONG_L	$29, GDB_FR_REG29(sp)		/* Deallocate stack */
-		jr	k0
-		rfe
-#else
-		LONG_L	sp, GDB_FR_REG29(sp)		/* Deallocate stack */
-
-		.set	mips3
-		eret
-		.set	mips0
-#endif
-		.set	at
-		.set	reorder
-		END(trap_low)
-
-LEAF(kgdb_read_byte)
-4:		lb	t0, (a0)
-		sb	t0, (a1)
-		li	v0, 0
-		jr	ra
-		.section __ex_table,"a"
-		PTR	4b, kgdbfault
-		.previous
-		END(kgdb_read_byte)
-
-LEAF(kgdb_write_byte)
-5:		sb	a0, (a1)
-		li	v0, 0
-		jr	ra
-		.section __ex_table,"a"
-		PTR	5b, kgdbfault
-		.previous
-		END(kgdb_write_byte)
-
-		.type	kgdbfault@function
-		.ent	kgdbfault
-
-kgdbfault:	li	v0, -EFAULT
-		jr	ra
-		.end	kgdbfault
diff -L arch/mips/kernel/gdb-stub.c -puN arch/mips/kernel/gdb-stub.c~mips-lite /dev/null
--- linux-2.6.13/arch/mips/kernel/gdb-stub.c
+++ /dev/null	2005-08-15 07:19:53.144310000 -0700
@@ -1,1091 +0,0 @@
-/*
- *  arch/mips/kernel/gdb-stub.c
- *
- *  Originally written by Glenn Engel, Lake Stevens Instrument Division
- *
- *  Contributed by HP Systems
- *
- *  Modified for SPARC by Stu Grossman, Cygnus Support.
- *
- *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
- *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
- *
- *  Copyright (C) 1995 Andreas Busse
- *
- *  Copyright (C) 2003 MontaVista Software Inc.
- *  Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- */
-
-/*
- *  To enable debugger support, two things need to happen.  One, a
- *  call to set_debug_traps() is necessary in order to allow any breakpoints
- *  or error conditions to be properly intercepted and reported to gdb.
- *  Two, a breakpoint needs to be generated to begin communication.  This
- *  is most easily accomplished by a call to breakpoint().  Breakpoint()
- *  simulates a breakpoint by executing a BREAK instruction.
- *
- *
- *    The following gdb commands are supported:
- *
- * command          function                               Return value
- *
- *    g             return the value of the CPU registers  hex data or ENN
- *    G             set the value of the CPU registers     OK or ENN
- *
- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
- *
- *    c             Resume at current address              SNN   ( signal NN)
- *    cAA..AA       Continue at address AA..AA             SNN
- *
- *    s             Step one instruction                   SNN
- *    sAA..AA       Step one instruction from AA..AA       SNN
- *
- *    k             kill
- *
- *    ?             What was the last sigval ?             SNN   (signal NN)
- *
- *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
- *							   baud rate
- *
- * All commands and responses are sent with a packet which includes a
- * checksum.  A packet consists of
- *
- * $<packet info>#<checksum>.
- *
- * where
- * <packet info> :: <characters representing the command or response>
- * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
- *
- * When a packet is received, it is first acknowledged with either '+' or '-'.
- * '+' indicates a successful transfer.  '-' indicates a failed transfer.
- *
- * Example:
- *
- * Host:                  Reply:
- * $m0,10#2a               +$00010203040506070809101112131415#42
- *
- *
- *  ==============
- *  MORE EXAMPLES:
- *  ==============
- *
- *  For reference -- the following are the steps that one
- *  company took (RidgeRun Inc) to get remote gdb debugging
- *  going. In this scenario the host machine was a PC and the
- *  target platform was a Galileo EVB64120A MIPS evaluation
- *  board.
- *
- *  Step 1:
- *  First download gdb-5.0.tar.gz from the internet.
- *  and then build/install the package.
- *
- *  Example:
- *    $ tar zxf gdb-5.0.tar.gz
- *    $ cd gdb-5.0
- *    $ ./configure --target=mips-linux-elf
- *    $ make
- *    $ install
- *    $ which mips-linux-elf-gdb
- *    /usr/local/bin/mips-linux-elf-gdb
- *
- *  Step 2:
- *  Configure linux for remote debugging and build it.
- *
- *  Example:
- *    $ cd ~/linux
- *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
- *    $ make
- *
- *  Step 3:
- *  Download the kernel to the remote target and start
- *  the kernel running. It will promptly halt and wait
- *  for the host gdb session to connect. It does this
- *  since the "Kernel Hacking" option has defined
- *  CONFIG_KGDB which in turn enables your calls
- *  to:
- *     set_debug_traps();
- *     breakpoint();
- *
- *  Step 4:
- *  Start the gdb session on the host.
- *
- *  Example:
- *    $ mips-linux-elf-gdb vmlinux
- *    (gdb) set remotebaud 115200
- *    (gdb) target remote /dev/ttyS1
- *    ...at this point you are connected to
- *       the remote target and can use gdb
- *       in the normal fasion. Setting
- *       breakpoints, single stepping,
- *       printing variables, etc.
- */
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/reboot.h>
-
-#include <asm/asm.h>
-#include <asm/cacheflush.h>
-#include <asm/mipsregs.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/gdb-stub.h>
-#include <asm/inst.h>
-
-/*
- * external low-level support routines
- */
-
-extern int putDebugChar(char c);    /* write a single character      */
-extern char getDebugChar(void);     /* read and return a single char */
-extern void trap_low(void);
-
-/*
- * breakpoint and test functions
- */
-extern void breakpoint(void);
-extern void breakinst(void);
-extern void async_breakpoint(void);
-extern void async_breakinst(void);
-extern void adel(void);
-
-/*
- * local prototypes
- */
-
-static void getpacket(char *buffer);
-static void putpacket(char *buffer);
-static int computeSignal(int tt);
-static int hex(unsigned char ch);
-static int hexToInt(char **ptr, int *intValue);
-static int hexToLong(char **ptr, long *longValue);
-static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
-void handle_exception(struct gdb_regs *regs);
-
-int kgdb_enabled;
-
-/*
- * spin locks for smp case
- */
-static spinlock_t kgdb_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t kgdb_cpulock[NR_CPUS] = { [0 ... NR_CPUS-1] = SPIN_LOCK_UNLOCKED};
-
-/*
- * BUFMAX defines the maximum number of characters in inbound/outbound buffers
- * at least NUMREGBYTES*2 are needed for register packets
- */
-#define BUFMAX 2048
-
-static char input_buffer[BUFMAX];
-static char output_buffer[BUFMAX];
-static int initialized;	/* !0 means we've been initialized */
-static int kgdb_started;
-static const char hexchars[]="0123456789abcdef";
-
-/* Used to prevent crashes in memory access.  Note that they'll crash anyway if
-   we haven't set up fault handlers yet... */
-int kgdb_read_byte(unsigned char *address, unsigned char *dest);
-int kgdb_write_byte(unsigned char val, unsigned char *dest);
-
-/*
- * Convert ch from a hex digit to an int
- */
-static int hex(unsigned 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 getpacket(char *buffer)
-{
-	unsigned char checksum;
-	unsigned char xmitcsum;
-	int i;
-	int count;
-	unsigned char ch;
-
-	do {
-		/*
-		 * wait around for the start character,
-		 * ignore all other characters
-		 */
-		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
-
-		checksum = 0;
-		xmitcsum = -1;
-		count = 0;
-
-		/*
-		 * now, read until a # or end of buffer is found
-		 */
-		while (count < BUFMAX) {
-			ch = getDebugChar();
-			if (ch == '#')
-				break;
-			checksum = checksum + ch;
-			buffer[count] = ch;
-			count = count + 1;
-		}
-
-		if (count >= BUFMAX)
-			continue;
-
-		buffer[count] = 0;
-
-		if (ch == '#') {
-			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
-			xmitcsum |= hex(getDebugChar() & 0x7f);
-
-			if (checksum != xmitcsum)
-				putDebugChar('-');	/* failed checksum */
-			else {
-				putDebugChar('+'); /* successful transfer */
-
-				/*
-				 * if a sequence char is present,
-				 * reply the sequence ID
-				 */
-				if (buffer[2] == ':') {
-					putDebugChar(buffer[0]);
-					putDebugChar(buffer[1]);
-
-					/*
-					 * remove sequence chars from buffer
-					 */
-					count = strlen(buffer);
-					for (i=3; i <= count; i++)
-						buffer[i-3] = buffer[i];
-				}
-			}
-		}
-	}
-	while (checksum != xmitcsum);
-}
-
-/*
- * send the packet in buffer.
- */
-static void putpacket(char *buffer)
-{
-	unsigned char checksum;
-	int count;
-	unsigned char ch;
-
-	/*
-	 * $<packet info>#<checksum>.
-	 */
-
-	do {
-		putDebugChar('$');
-		checksum = 0;
-		count = 0;
-
-		while ((ch = buffer[count]) != 0) {
-			if (!(putDebugChar(ch)))
-				return;
-			checksum += ch;
-			count += 1;
-		}
-
-		putDebugChar('#');
-		putDebugChar(hexchars[checksum >> 4]);
-		putDebugChar(hexchars[checksum & 0xf]);
-
-	}
-	while ((getDebugChar() & 0x7f) != '+');
-}
-
-
-/*
- * Convert the memory pointed to by mem into hex, placing result in buf.
- * Return a pointer to the last char put in buf (null), in case of mem fault,
- * return 0.
- * may_fault is non-zero if we are reading from arbitrary memory, but is currently
- * not used.
- */
-static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
-{
-	unsigned char ch;
-
-	while (count-- > 0) {
-		if (kgdb_read_byte(mem++, &ch) != 0)
-			return 0;
-		*buf++ = hexchars[ch >> 4];
-		*buf++ = hexchars[ch & 0xf];
-	}
-
-	*buf = 0;
-
-	return buf;
-}
-
-/*
- * 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_fault is non-zero if we are reading from arbitrary memory, but is currently
- * not used.
- */
-static char *hex2mem(char *buf, char *mem, int count, int binary, int may_fault)
-{
-	int i;
-	unsigned char ch;
-
-	for (i=0; i<count; i++)
-	{
-		if (binary) {
-			ch = *buf++;
-			if (ch == 0x7d)
-				ch = 0x20 ^ *buf++;
-		}
-		else {
-			ch = hex(*buf++) << 4;
-			ch |= hex(*buf++);
-		}
-		if (kgdb_write_byte(ch, mem++) != 0)
-			return 0;
-	}
-
-	return mem;
-}
-
-/*
- * This table contains the mapping between SPARC hardware trap types, and
- * signals, which are primarily what GDB understands.  It also indicates
- * which hardware traps we need to commandeer when initializing the stub.
- */
-static struct hard_trap_info {
-	unsigned char tt;		/* Trap type code for MIPS R3xxx and R4xxx */
-	unsigned char signo;		/* Signal that we map this trap into */
-} hard_trap_info[] = {
-	{ 6, SIGBUS },			/* instruction bus error */
-	{ 7, SIGBUS },			/* data bus error */
-	{ 9, SIGTRAP },			/* break */
-	{ 10, SIGILL },			/* reserved instruction */
-/*	{ 11, SIGILL },		*/	/* CPU unusable */
-	{ 12, SIGFPE },			/* overflow */
-	{ 13, SIGTRAP },		/* trap */
-	{ 14, SIGSEGV },		/* virtual instruction cache coherency */
-	{ 15, SIGFPE },			/* floating point exception */
-	{ 23, SIGSEGV },		/* watch */
-	{ 31, SIGSEGV },		/* virtual data cache coherency */
-	{ 0, 0}				/* Must be last */
-};
-
-/* Save the normal trap handlers for user-mode traps. */
-void *saved_vectors[32];
-
-/*
- * Set up exception handlers for tracing and breakpoints
- */
-void set_debug_traps(void)
-{
-	struct hard_trap_info *ht;
-	unsigned long flags;
-	unsigned char c;
-
-	local_irq_save(flags);
-	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
-		saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low);
-
-	putDebugChar('+'); /* 'hello world' */
-	/*
-	 * In case GDB is started before us, ack any packets
-	 * (presumably "$?#xx") sitting there.
-	 */
-	while((c = getDebugChar()) != '$');
-	while((c = getDebugChar()) != '#');
-	c = getDebugChar(); /* eat first csum byte */
-	c = getDebugChar(); /* eat second csum byte */
-	putDebugChar('+'); /* ack it */
-
-	initialized = 1;
-	local_irq_restore(flags);
-}
-
-void restore_debug_traps(void)
-{
-	struct hard_trap_info *ht;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
-		set_except_vector(ht->tt, saved_vectors[ht->tt]);
-	local_irq_restore(flags);
-}
-
-/*
- * Convert the MIPS hardware trap type code to a Unix signal number.
- */
-static int computeSignal(int tt)
-{
-	struct hard_trap_info *ht;
-
-	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
-		if (ht->tt == tt)
-			return ht->signo;
-
-	return SIGHUP;		/* default for things we don't know about */
-}
-
-/*
- * While we find nice hex chars, build an int.
- * Return number of chars processed.
- */
-static int hexToInt(char **ptr, int *intValue)
-{
-	int numChars = 0;
-	int hexValue;
-
-	*intValue = 0;
-
-	while (**ptr) {
-		hexValue = hex(**ptr);
-		if (hexValue < 0)
-			break;
-
-		*intValue = (*intValue << 4) | hexValue;
-		numChars ++;
-
-		(*ptr)++;
-	}
-
-	return (numChars);
-}
-
-static int hexToLong(char **ptr, long *longValue)
-{
-	int numChars = 0;
-	int hexValue;
-
-	*longValue = 0;
-
-	while (**ptr) {
-		hexValue = hex(**ptr);
-		if (hexValue < 0)
-			break;
-
-		*longValue = (*longValue << 4) | hexValue;
-		numChars ++;
-
-		(*ptr)++;
-	}
-
-	return numChars;
-}
-
-
-#if 0
-/*
- * Print registers (on target console)
- * Used only to debug the stub...
- */
-void show_gdbregs(struct gdb_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg0, regs->reg1, regs->reg2, regs->reg3,
-               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg8, regs->reg9, regs->reg10, regs->reg11,
-               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg16, regs->reg17, regs->reg18, regs->reg19,
-               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
-	printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg24, regs->reg25, regs->reg26, regs->reg27,
-	       regs->reg28, regs->reg29, regs->reg30, regs->reg31);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
-	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-}
-#endif /* dead code */
-
-/*
- * We single-step by setting breakpoints. When an exception
- * is handled, we need to restore the instructions hoisted
- * when the breakpoints were set.
- *
- * This is where we save the original instructions.
- */
-static struct gdb_bp_save {
-	unsigned long addr;
-	unsigned int val;
-} step_bp[2];
-
-#define BP 0x0000000d  /* break opcode */
-
-/*
- * Set breakpoint instructions for single stepping.
- */
-static void single_step(struct gdb_regs *regs)
-{
-	union mips_instruction insn;
-	unsigned long targ;
-	int is_branch, is_cond, i;
-
-	targ = regs->cp0_epc;
-	insn.word = *(unsigned int *)targ;
-	is_branch = is_cond = 0;
-
-	switch (insn.i_format.opcode) {
-	/*
-	 * jr and jalr are in r_format format.
-	 */
-	case spec_op:
-		switch (insn.r_format.func) {
-		case jalr_op:
-		case jr_op:
-			targ = *(&regs->reg0 + insn.r_format.rs);
-			is_branch = 1;
-			break;
-		}
-		break;
-
-	/*
-	 * This group contains:
-	 * bltz_op, bgez_op, bltzl_op, bgezl_op,
-	 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
-	 */
-	case bcond_op:
-		is_branch = is_cond = 1;
-		targ += 4 + (insn.i_format.simmediate << 2);
-		break;
-
-	/*
-	 * These are unconditional and in j_format.
-	 */
-	case jal_op:
-	case j_op:
-		is_branch = 1;
-		targ += 4;
-		targ >>= 28;
-		targ <<= 28;
-		targ |= (insn.j_format.target << 2);
-		break;
-
-	/*
-	 * These are conditional.
-	 */
-	case beq_op:
-	case beql_op:
-	case bne_op:
-	case bnel_op:
-	case blez_op:
-	case blezl_op:
-	case bgtz_op:
-	case bgtzl_op:
-	case cop0_op:
-	case cop1_op:
-	case cop2_op:
-	case cop1x_op:
-		is_branch = is_cond = 1;
-		targ += 4 + (insn.i_format.simmediate << 2);
-		break;
-	}
-
-	if (is_branch) {
-		i = 0;
-		if (is_cond && targ != (regs->cp0_epc + 8)) {
-			step_bp[i].addr = regs->cp0_epc + 8;
-			step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8);
-			*(unsigned *)(regs->cp0_epc + 8) = BP;
-		}
-		step_bp[i].addr = targ;
-		step_bp[i].val  = *(unsigned *)targ;
-		*(unsigned *)targ = BP;
-	} else {
-		step_bp[0].addr = regs->cp0_epc + 4;
-		step_bp[0].val  = *(unsigned *)(regs->cp0_epc + 4);
-		*(unsigned *)(regs->cp0_epc + 4) = BP;
-	}
-}
-
-/*
- *  If asynchronously interrupted by gdb, then we need to set a breakpoint
- *  at the interrupted instruction so that we wind up stopped with a
- *  reasonable stack frame.
- */
-static struct gdb_bp_save async_bp;
-
-/*
- * Swap the interrupted EPC with our asynchronous breakpoint routine.
- * This is safer than stuffing the breakpoint in-place, since no cache
- * flushes (or resulting smp_call_functions) are required.  The
- * assumption is that only one CPU will be handling asynchronous bp's,
- * and only one can be active at a time.
- */
-extern spinlock_t smp_call_lock;
-void set_async_breakpoint(unsigned long *epc)
-{
-	/* skip breaking into userland */
-	if ((*epc & 0x80000000) == 0)
-		return;
-
-	/* avoid deadlock if someone is make IPC */
-	if (spin_is_locked(&smp_call_lock))
-		return;
-
-	async_bp.addr = *epc;
-	*epc = (unsigned long)async_breakpoint;
-}
-
-void kgdb_wait(void *arg)
-{
-	unsigned flags;
-	int cpu = smp_processor_id();
-
-	local_irq_save(flags);
-
-	spin_lock(&kgdb_cpulock[cpu]);
-	spin_unlock(&kgdb_cpulock[cpu]);
-
-	local_irq_restore(flags);
-}
-
-
-/*
- * This function does all command processing for interfacing to gdb.  It
- * returns 1 if you should skip the instruction at the trap address, 0
- * otherwise.
- */
-void handle_exception (struct gdb_regs *regs)
-{
-	int trap;			/* Trap type */
-	int sigval;
-	long addr;
-	int length;
-	char *ptr;
-	unsigned long *stack;
-	int i;
-	int bflag = 0;
-
-	kgdb_started = 1;
-
-	/*
-	 * acquire the big kgdb spinlock
-	 */
-	if (!spin_trylock(&kgdb_lock)) {
-		/* 
-		 * some other CPU has the lock, we should go back to 
-		 * receive the gdb_wait IPC
-		 */
-		return;
-	}
-
-	/*
-	 * If we're in async_breakpoint(), restore the real EPC from
-	 * the breakpoint.
-	 */
-	if (regs->cp0_epc == (unsigned long)async_breakinst) {
-		regs->cp0_epc = async_bp.addr;
-		async_bp.addr = 0;
-	}
-
-	/* 
-	 * acquire the CPU spinlocks
-	 */
-	for (i = num_online_cpus()-1; i >= 0; i--)
-		if (spin_trylock(&kgdb_cpulock[i]) == 0)
-			panic("kgdb: couldn't get cpulock %d\n", i);
-
-	/*
-	 * force other cpus to enter kgdb
-	 */
-	smp_call_function(kgdb_wait, NULL, 0, 0);
-
-	/*
-	 * If we're in breakpoint() increment the PC
-	 */
-	trap = (regs->cp0_cause & 0x7c) >> 2;
-	if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
-		regs->cp0_epc += 4;
-
-	/*
-	 * If we were single_stepping, restore the opcodes hoisted
-	 * for the breakpoint[s].
-	 */
-	if (step_bp[0].addr) {
-		*(unsigned *)step_bp[0].addr = step_bp[0].val;
-		step_bp[0].addr = 0;
-
-		if (step_bp[1].addr) {
-			*(unsigned *)step_bp[1].addr = step_bp[1].val;
-			step_bp[1].addr = 0;
-		}
-	}
-
-	stack = (long *)regs->reg29;			/* stack ptr */
-	sigval = computeSignal(trap);
-
-	/*
-	 * reply to host that an exception has occurred
-	 */
-	ptr = output_buffer;
-
-	/*
-	 * Send trap type (converted to signal)
-	 */
-	*ptr++ = 'T';
-	*ptr++ = hexchars[sigval >> 4];
-	*ptr++ = hexchars[sigval & 0xf];
-
-	/*
-	 * Send Error PC
-	 */
-	*ptr++ = hexchars[REG_EPC >> 4];
-	*ptr++ = hexchars[REG_EPC & 0xf];
-	*ptr++ = ':';
-	ptr = mem2hex((char *)&regs->cp0_epc, ptr, sizeof(long), 0);
-	*ptr++ = ';';
-
-	/*
-	 * Send frame pointer
-	 */
-	*ptr++ = hexchars[REG_FP >> 4];
-	*ptr++ = hexchars[REG_FP & 0xf];
-	*ptr++ = ':';
-	ptr = mem2hex((char *)&regs->reg30, ptr, sizeof(long), 0);
-	*ptr++ = ';';
-
-	/*
-	 * Send stack pointer
-	 */
-	*ptr++ = hexchars[REG_SP >> 4];
-	*ptr++ = hexchars[REG_SP & 0xf];
-	*ptr++ = ':';
-	ptr = mem2hex((char *)&regs->reg29, ptr, sizeof(long), 0);
-	*ptr++ = ';';
-
-	*ptr++ = 0;
-	putpacket(output_buffer);	/* send it off... */
-
-	/*
-	 * Wait for input from remote GDB
-	 */
-	while (1) {
-		output_buffer[0] = 0;
-		getpacket(input_buffer);
-
-		switch (input_buffer[0])
-		{
-		case '?':
-			output_buffer[0] = 'S';
-			output_buffer[1] = hexchars[sigval >> 4];
-			output_buffer[2] = hexchars[sigval & 0xf];
-			output_buffer[3] = 0;
-			break;
-
-		/*
-		 * Detach debugger; let CPU run
-		 */
-		case 'D':
-			putpacket(output_buffer);
-			goto finish_kgdb;
-			break;
-
-		case 'd':
-			/* toggle debug flag */
-			break;
-
-		/*
-		 * Return the value of the CPU registers
-		 */
-		case 'g':
-			ptr = output_buffer;
-			ptr = mem2hex((char *)&regs->reg0, ptr, 32*sizeof(long), 0); /* r0...r31 */
-			ptr = mem2hex((char *)&regs->cp0_status, ptr, 6*sizeof(long), 0); /* cp0 */
-			ptr = mem2hex((char *)&regs->fpr0, ptr, 32*sizeof(long), 0); /* f0...31 */
-			ptr = mem2hex((char *)&regs->cp1_fsr, ptr, 2*sizeof(long), 0); /* cp1 */
-			ptr = mem2hex((char *)&regs->frame_ptr, ptr, 2*sizeof(long), 0); /* frp */
-			ptr = mem2hex((char *)&regs->cp0_index, ptr, 16*sizeof(long), 0); /* cp0 */
-			break;
-
-		/*
-		 * set the value of the CPU registers - return OK
-		 */
-		case 'G':
-		{
-			ptr = &input_buffer[1];
-			hex2mem(ptr, (char *)&regs->reg0, 32*sizeof(long), 0, 0);
-			ptr += 32*(2*sizeof(long));
-			hex2mem(ptr, (char *)&regs->cp0_status, 6*sizeof(long), 0, 0);
-			ptr += 6*(2*sizeof(long));
-			hex2mem(ptr, (char *)&regs->fpr0, 32*sizeof(long), 0, 0);
-			ptr += 32*(2*sizeof(long));
-			hex2mem(ptr, (char *)&regs->cp1_fsr, 2*sizeof(long), 0, 0);
-			ptr += 2*(2*sizeof(long));
-			hex2mem(ptr, (char *)&regs->frame_ptr, 2*sizeof(long), 0, 0);
-			ptr += 2*(2*sizeof(long));
-			hex2mem(ptr, (char *)&regs->cp0_index, 16*sizeof(long), 0, 0);
-			strcpy(output_buffer,"OK");
-		 }
-		break;
-
-		/*
-		 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
-		 */
-		case 'm':
-			ptr = &input_buffer[1];
-
-			if (hexToLong(&ptr, &addr)
-				&& *ptr++ == ','
-				&& hexToInt(&ptr, &length)) {
-				if (mem2hex((char *)addr, output_buffer, length, 1))
-					break;
-				strcpy (output_buffer, "E03");
-			} else
-				strcpy(output_buffer,"E01");
-			break;
-
-		/*
-		 * XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA
-		 */
-		case 'X':
-			bflag = 1;
-			/* fall through */
-
-		/*
-		 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
-		 */
-		case 'M':
-			ptr = &input_buffer[1];
-
-			if (hexToLong(&ptr, &addr)
-				&& *ptr++ == ','
-				&& hexToInt(&ptr, &length)
-				&& *ptr++ == ':') {
-				if (hex2mem(ptr, (char *)addr, length, bflag, 1))
-					strcpy(output_buffer, "OK");
-				else
-					strcpy(output_buffer, "E03");
-			}
-			else
-				strcpy(output_buffer, "E02");
-			break;
-
-		/*
-		 * cAA..AA    Continue at address AA..AA(optional)
-		 */
-		case 'c':
-			/* try to read optional parameter, pc unchanged if no parm */
-
-			ptr = &input_buffer[1];
-			if (hexToLong(&ptr, &addr))
-				regs->cp0_epc = addr;
-	  
-			goto exit_kgdb_exception;
-			break;
-
-		/*
-		 * kill the program; let us try to restart the machine
-		 * Reset the whole machine.
-		 */
-		case 'k':
-		case 'r':
-			machine_restart("kgdb restarts machine");
-			break;
-
-		/*
-		 * Step to next instruction
-		 */
-		case 's':
-			/*
-			 * There is no single step insn in the MIPS ISA, so we
-			 * use breakpoints and continue, instead.
-			 */
-			single_step(regs);
-			goto exit_kgdb_exception;
-			/* NOTREACHED */
-			break;
-
-		/*
-		 * Set baud rate (bBB)
-		 * FIXME: Needs to be written
-		 */
-		case 'b':
-		{
-#if 0
-			int baudrate;
-			extern void set_timer_3();
-
-			ptr = &input_buffer[1];
-			if (!hexToInt(&ptr, &baudrate))
-			{
-				strcpy(output_buffer,"B01");
-				break;
-			}
-
-			/* Convert baud rate to uart clock divider */
-
-			switch (baudrate)
-			{
-				case 38400:
-					baudrate = 16;
-					break;
-				case 19200:
-					baudrate = 33;
-					break;
-				case 9600:
-					baudrate = 65;
-					break;
-				default:
-					baudrate = 0;
-					strcpy(output_buffer,"B02");
-					goto x1;
-			}
-
-			if (baudrate) {
-				putpacket("OK");	/* Ack before changing speed */
-				set_timer_3(baudrate); /* Set it */
-			}
-#endif
-		}
-		break;
-
-		}			/* switch */
-
-		/*
-		 * reply to the request
-		 */
-
-		putpacket(output_buffer);
-
-	} /* while */
-
-	return;
-
-finish_kgdb:
-	restore_debug_traps();
-
-exit_kgdb_exception:
-	/* release locks so other CPUs can go */
-	for (i = num_online_cpus()-1; i >= 0; i--)
-		spin_unlock(&kgdb_cpulock[i]);
-	spin_unlock(&kgdb_lock);
-
-	__flush_cache_all();
-	return;
-}
-
-/*
- * 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)
-{
-	if (!initialized)
-		return;
-
-	__asm__ __volatile__(
-			".globl	breakinst\n\t" 
-			".set\tnoreorder\n\t"
-			"nop\n"
-			"breakinst:\tbreak\n\t"
-			"nop\n\t"
-			".set\treorder"
-			);
-}
-
-/* Nothing but the break; don't pollute any registers */
-void async_breakpoint(void)
-{
-	__asm__ __volatile__(
-			".globl	async_breakinst\n\t" 
-			".set\tnoreorder\n\t"
-			"nop\n"
-			"async_breakinst:\tbreak\n\t"
-			"nop\n\t"
-			".set\treorder"
-			);
-}
-
-void adel(void)
-{
-	__asm__ __volatile__(
-			".globl\tadel\n\t"
-			"lui\t$8,0x8000\n\t"
-			"lw\t$9,1($8)\n\t"
-			);
-}
-
-/*
- * malloc is needed by gdb client in "call func()", even a private one
- * will make gdb happy
- */
-static void *malloc(size_t size)
-{
-	return kmalloc(size, GFP_ATOMIC);
-}
-
-static void free(void *where)
-{
-	kfree(where);
-}
-
-#ifdef CONFIG_GDB_CONSOLE
-
-void gdb_putsn(const char *str, int l)
-{
-	char outbuf[18];
-
-	if (!kgdb_started)
-		return;
-
-	outbuf[0]='O';
-
-	while(l) {
-		int i = (l>8)?8:l;
-		mem2hex((char *)str, &outbuf[1], i, 0);
-		outbuf[(i*2)+1]=0;
-		putpacket(outbuf);
-		str += i;
-		l -= i;
-	}
-}
-
-static void gdb_console_write(struct console *con, const char *s, unsigned n)
-{
-	gdb_putsn(s, n);
-}
-
-static struct console gdb_console = {
-	.name	= "gdb",
-	.write	= gdb_console_write,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1
-};
-
-static int __init register_gdb_console(void)
-{
-	register_console(&gdb_console);
-
-	return 0;
-}
-
-console_initcall(register_gdb_console);
-
-#endif
diff -puN arch/mips/kernel/irq.c~mips-lite arch/mips/kernel/irq.c
--- linux-2.6.13/arch/mips/kernel/irq.c~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/irq.c	2005-08-16 17:32:26.000000000 -0700
@@ -26,6 +26,10 @@
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/kgdb.h>
+
+/* Keep track of if we've done certain initialization already or not. */
+int kgdb_early_setup;
 
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
@@ -103,23 +107,13 @@ skip:
 	return 0;
 }
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-
-static int kgdb_flag = 1;
-static int __init nokgdb(char *str)
-{
-	kgdb_flag = 0;
-	return 1;
-}
-__setup("nokgdb", nokgdb);
-#endif
-
 void __init init_IRQ(void)
 {
 	int i;
 
+	if (kgdb_early_setup)
+		return;
+
 	for (i = 0; i < NR_IRQS; i++) {
 		irq_desc[i].status  = IRQ_DISABLED;
 		irq_desc[i].action  = NULL;
@@ -129,12 +123,12 @@ void __init init_IRQ(void)
 	}
 
 	arch_init_irq();
-
 #ifdef CONFIG_KGDB
-	if (kgdb_flag) {
-		printk("Wait for gdb client connection ...\n");
-		set_debug_traps();
-		breakpoint();
-	}
+	/*
+	 * We have been called before kgdb_arch_init(). Hence,
+	 * we dont want the traps to be reinitialized
+	 */
+	if (kgdb_early_setup == 0)
+		kgdb_early_setup = 1;
 #endif
 }
diff -puN /dev/null arch/mips/kernel/kgdb.c
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/kgdb.c	2005-08-16 17:32:46.000000000 -0700
@@ -0,0 +1,296 @@
+/*
+ * arch/mips/kernel/kgdb.c
+ *
+ *  Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ *  Contributed by HP Systems
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ *  Copyright (C) 1995 Andreas Busse
+ *
+ *  Copyright (C) 2003 MontaVista Software Inc.
+ *  Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ *  Copyright (C) 2004-2005 MontaVista Software Inc.
+ *  Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.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/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 <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <asm/inst.h>
+#include <asm/gdb-stub.h>
+#include <asm/cacheflush.h>
+#include <asm/kdebug.h>
+
+static struct hard_trap_info {
+	unsigned char tt;	/* Trap type code for MIPS R3xxx and R4xxx */
+	unsigned char signo;	/* Signal that we map this trap into */
+} hard_trap_info[] = {
+	{ 6, SIGBUS },		/* instruction bus error */
+	{ 7, SIGBUS },		/* data bus error */
+	{ 9, SIGTRAP },		/* break */
+/*	{ 11, SIGILL },	*/	/* CPU unusable */
+	{ 12, SIGFPE },		/* overflow */
+	{ 13, SIGTRAP },	/* trap */
+	{ 14, SIGSEGV },	/* virtual instruction cache coherency */
+	{ 15, SIGFPE },		/* floating point exception */
+	{ 23, SIGSEGV },	/* watch */
+	{ 31, SIGSEGV },	/* virtual data cache coherency */
+	{ 0, 0}			/* Must be last */
+};
+
+/* Save the normal trap handlers for user-mode traps. */
+void *saved_vectors[32];
+
+extern void trap_low(void);
+extern void breakinst(void);
+extern void init_IRQ(void);
+
+void kgdb_call_nmi_hook(void *ignored)
+{
+	kgdb_nmihook(smp_processor_id(), (void *)0);
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	local_irq_restore(flags);
+	smp_call_function(kgdb_call_nmi_hook, 0, 0, 0);
+	local_irq_save(flags);
+}
+
+static int compute_signal(int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;		/* default for things we don't know about */
+}
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void handle_exception(struct pt_regs *regs)
+{
+	int trap = (regs->cp0_cause & 0x7c) >> 2;
+
+	if (fixup_exception(regs)) {
+		return;
+	}
+
+	if (atomic_read(&debugger_active))
+		kgdb_nmihook(smp_processor_id(), regs);
+
+	if (atomic_read(&kgdb_setting_breakpoint))
+		if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
+			regs->cp0_epc += 4;
+
+	kgdb_handle_exception(0, compute_signal(trap), 0, regs);
+
+	/* In SMP mode, __flush_cache_all does IPI */
+	__flush_cache_all();
+}
+
+void set_debug_traps(void)
+{
+	struct hard_trap_info *ht;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low);
+
+	local_irq_restore(flags);
+}
+
+#if 0
+/* This should be called before we exit kgdb_handle_exception() I believe.
+ * -- Tom
+ */
+void restore_debug_traps(void)
+{
+	struct hard_trap_info *ht;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		set_except_vector(ht->tt, saved_vectors[ht->tt]);
+	local_irq_restore(flags);
+}
+#endif
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg = 0;
+	unsigned long *ptr = gdb_regs;
+
+	for (reg = 0; reg < 32; reg++)
+		*(ptr++) = regs->regs[reg];
+
+	*(ptr++) = regs->cp0_status;
+	*(ptr++) = regs->lo;
+	*(ptr++) = regs->hi;
+	*(ptr++) = regs->cp0_badvaddr;
+	*(ptr++) = regs->cp0_cause;
+	*(ptr++) = regs->cp0_epc;
+
+	return;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg = 0;
+	unsigned long *ptr = gdb_regs;
+
+	for (reg = 0; reg < 32; reg++)
+		regs->regs[reg] = *(ptr++);
+
+	regs->cp0_status = *(ptr++);
+	regs->lo = *(ptr++);
+	regs->hi = *(ptr++);
+	regs->cp0_badvaddr = *(ptr++);
+	regs->cp0_cause = *(ptr++);
+	regs->cp0_epc = *(ptr++);
+
+	return;
+}
+
+/*
+ * Similar to regs_to_gdb_regs() except that process is sleeping and so
+ * we may not be able to get all the info.
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	int reg = 0;
+	struct thread_info *ti = p->thread_info;
+	unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32;
+	struct pt_regs *regs = (struct pt_regs *)ksp - 1;
+	unsigned long *ptr = gdb_regs;
+
+	for (reg = 0; reg < 16; reg++)
+		*(ptr++) = regs->regs[reg];
+
+	/* S0 - S7 */
+	for (reg = 16; reg < 24; reg++)
+		*(ptr++) = regs->regs[reg];
+
+	for (reg = 24; reg < 28; reg++)
+		*(ptr++) = 0;
+
+	/* GP, SP, FP, RA */
+	for (reg = 28; reg < 32; reg++)
+		*(ptr++) = regs->regs[reg];
+
+	*(ptr++) = regs->cp0_status;
+	*(ptr++) = regs->lo;
+	*(ptr++) = regs->hi;
+	*(ptr++) = regs->cp0_badvaddr;
+	*(ptr++) = regs->cp0_cause;
+	*(ptr++) = regs->cp0_epc;
+
+	return;
+}
+
+/*
+ * Calls linux_debug_hook before the kernel dies. If KGDB is enabled,
+ * then try to fall into the debugger
+ */
+static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
+			    void *ptr)
+{
+	struct die_args *args = (struct die_args *)ptr;
+	struct pt_regs *regs = args->regs;
+	int trap = (regs->cp0_cause & 0x7c) >> 2;
+
+	/* See if KGDB is interested. */
+	if (user_mode(regs))
+		/* Userpace events, ignore. */
+		return NOTIFY_DONE;
+
+	kgdb_handle_exception(trap, compute_signal(trap), 0, regs);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_mips_notify,
+};
+
+/*
+ * Handle the 's' and 'c' commands
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+			       char *remcom_in_buffer, char *remcom_out_buffer,
+			       struct pt_regs *regs)
+{
+	char *ptr;
+	unsigned long address;
+	int cpu = smp_processor_id();
+
+	switch (remcom_in_buffer[0]) {
+	case 's':
+	case 'c':
+		/* handle the optional parameter */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &address))
+			regs->cp0_epc = address;
+
+		atomic_set(&cpu_doing_single_step, -1);
+		if (remcom_in_buffer[0] == 's')
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step, cpu);
+
+		return 0;
+	}
+
+	return -1;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+	.gdb_bpt_instr = {0xd},
+#else
+	.gdb_bpt_instr = {0x00, 0x00, 0x00, 0x0d},
+#endif
+};
+
+/*
+ * We use kgdb_early_setup so that functions we need to call now don't
+ * cause trouble when called again later.
+ */
+int kgdb_arch_init(void)
+{
+	/* Board-specifics. */
+	/* Force some calls to happen earlier. */
+	if (kgdb_early_setup == 0) {
+		trap_init();
+		init_IRQ();
+		kgdb_early_setup = 1;
+	}
+
+	/* Set our traps. */
+	/* This needs to be done more finely grained again, paired in
+	 * a before/after in kgdb_handle_exception(...) -- Tom */
+	set_debug_traps();
+	notifier_chain_register(&mips_die_chain, &kgdb_notifier);
+
+	return 0;
+}
diff -puN /dev/null arch/mips/kernel/kgdb_handler.S
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/kgdb_handler.S	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,58 @@
+/*
+ * arch/mips/kernel/kgdb_handler.S
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/*
+ * Trap Handler for the new KGDB framework. The main KGDB handler is
+ * handle_exception that will be called from here
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sys.h>
+
+#include <asm/asm.h>
+#include <asm/errno.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+	.align  5
+	NESTED(trap_low, PT_SIZE, sp)
+		.set    noat
+		.set	noreorder
+		SAVE_ALL
+		/*
+		 * Check for privileged instructions in user mode. For
+		 * this, check the cu0 bit in the CPU status register.
+		 */
+		mfc0	k0, CP0_STATUS
+		sll	k0, 3
+		bltz	k0, 1f
+		move	k1, sp
+
+		/*
+		 * GDB userland from within KGDB. If a user mode address
+		 * then jump to the saved exception handler
+		 */
+		lui	k1, %hi(saved_vectors)
+		mfc0	k0, CP0_CAUSE
+		andi	k0, k0, 0x7c
+		add	k1, k1, k0
+		lw	k0, %lo(saved_vectors)(k1)
+		jr	k0
+		nop
+1:
+		.set    at
+		.set	reorder
+		move    a0, sp
+		jal     handle_exception
+		j       ret_from_exception
+	END(trap_low)
diff -puN /dev/null arch/mips/kernel/kgdb-jmp.c
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/kgdb-jmp.c	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,116 @@
+/*
+ * arch/mips/kernel/kgdb-jmp.c
+ *
+ * Save and restore system registers so that within a limited frame we
+ * may have a fault and "jump back" to a known safe location.
+ *
+ * Author: Tom Rini <trini@kernel.crashing.org>
+ * Author: Manish Lachwani <mlachwani@mvista.com>
+ *
+ * Cribbed from glibc, which carries the following:
+ * Copyright (C) 1996, 1997, 2000, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2005 by MontaVista Software.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <linux/kgdb.h>
+#include <asm/interrupt.h>
+
+#ifdef CONFIG_MIPS64
+/*
+ * MIPS 64-bit
+ */
+
+int kgdb_fault_setjmp_aux(unsigned long *curr_context, int sp, int fp)
+{
+	__asm__ __volatile__ ("sd $gp, %0" : : "m" (curr_context[0]));
+	__asm__ __volatile__ ("sd $16, %0" : : "m" (curr_context[1]));
+	__asm__ __volatile__ ("sd $17, %0" : : "m" (curr_context[2]));
+	__asm__ __volatile__ ("sd $18, %0" : : "m" (curr_context[3]));
+	__asm__ __volatile__ ("sd $19, %0" : : "m" (curr_context[4]));
+	__asm__ __volatile__ ("sd $20, %0" : : "m" (curr_context[5]));
+	__asm__ __volatile__ ("sd $21, %0" : : "m" (curr_context[6]));
+	__asm__ __volatile__ ("sd $22, %0" : : "m" (curr_context[7]));
+	__asm__ __volatile__ ("sd $23, %0" : : "m" (curr_context[8]));
+	__asm__ __volatile__ ("sd $31, %0" : : "m" (curr_context[9]));
+	curr_context[10] = (long *)sp;
+	curr_context[11] = (long *)fp;
+
+	return 0;
+}
+
+void kgdb_fault_longjmp(unsigned long *curr_context)
+{
+	unsigned long sp_val, fp_val;
+
+	__asm__ __volatile__ ("ld $gp, %0" : : "m" (curr_context[0]));
+	__asm__ __volatile__ ("ld $16, %0" : : "m" (curr_context[1]));
+	__asm__ __volatile__ ("ld $17, %0" : : "m" (curr_context[2]));
+	__asm__ __volatile__ ("ld $18, %0" : : "m" (curr_context[3]));
+	__asm__ __volatile__ ("ld $19, %0" : : "m" (curr_context[4]));
+	__asm__ __volatile__ ("ld $20, %0" : : "m" (curr_context[5]));
+	__asm__ __volatile__ ("ld $21, %0" : : "m" (curr_context[6]));
+	__asm__ __volatile__ ("ld $22, %0" : : "m" (curr_context[7]));
+	__asm__ __volatile__ ("ld $23, %0" : : "m" (curr_context[8]));
+	__asm__ __volatile__ ("ld $25, %0" : : "m" (curr_context[9]));
+	sp_val = curr_context[10];
+	fp_val = curr_context[11];
+	__asm__ __volatile__ ("ld $29, %0\n\t"
+			      "ld $30, %1\n\t" : : "m" (sp_val), "m" (fp_val));
+
+	__asm__ __volatile__ ("dli $2, 1");
+	__asm__ __volatile__ ("j $25");
+
+	for (;;);
+}
+#else
+/*
+ * MIPS 32-bit
+ */
+
+int kgdb_fault_setjmp_aux(unsigned long *curr_context, int sp, int fp)
+{
+	__asm__ __volatile__("sw $gp, %0" : : "m" (curr_context[0]));
+	__asm__ __volatile__("sw $16, %0" : : "m" (curr_context[1]));
+	__asm__ __volatile__("sw $17, %0" : : "m" (curr_context[2]));
+	__asm__ __volatile__("sw $18, %0" : : "m" (curr_context[3]));
+	__asm__ __volatile__("sw $19, %0" : : "m" (curr_context[4]));
+	__asm__ __volatile__("sw $20, %0" : : "m" (curr_context[5]));
+	__asm__ __volatile__("sw $21, %0" : : "m" (curr_context[6]));
+	__asm__ __volatile__("sw $22, %0" : : "m" (curr_context[7]));
+	__asm__ __volatile__("sw $23, %0" : : "m" (curr_context[8]));
+	__asm__ __volatile__("sw $31, %0" : : "m" (curr_context[9]));
+	curr_context[10] = (long *)sp;
+	curr_context[11] = (long *)fp;
+
+	return 0;
+}
+
+void kgdb_fault_longjmp(unsigned long *curr_context)
+{
+	unsigned long sp_val, fp_val;
+
+	__asm__ __volatile__("lw $gp, %0" : : "m" (curr_context[0]));
+	__asm__ __volatile__("lw $16, %0" : : "m" (curr_context[1]));
+	__asm__ __volatile__("lw $17, %0" : : "m" (curr_context[2]));
+	__asm__ __volatile__("lw $18, %0" : : "m" (curr_context[3]));
+	__asm__ __volatile__("lw $19, %0" : : "m" (curr_context[4]));
+	__asm__ __volatile__("lw $20, %0" : : "m" (curr_context[5]));
+	__asm__ __volatile__("lw $21, %0" : : "m" (curr_context[6]));
+	__asm__ __volatile__("lw $22, %0" : : "m" (curr_context[7]));
+	__asm__ __volatile__("lw $23, %0" : : "m" (curr_context[8]));
+	__asm__ __volatile__("lw $25, %0" : : "m" (curr_context[9]));
+	sp_val = curr_context[10];
+	fp_val = curr_context[11];
+	__asm__ __volatile__("lw $29, %0\n\t"
+			      "lw $30, %1\n\t" : : "m" (sp_val), "m" (fp_val));
+
+	__asm__ __volatile__("li $2, 1");
+	__asm__ __volatile__("jr $25");
+
+	for (;;);
+}
+#endif
diff -puN /dev/null arch/mips/kernel/kgdb-setjmp.S
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/kgdb-setjmp.S	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,27 @@
+/*
+ * arch/mips/kernel/kgdb-jmp.c
+ *
+ * Save and restore system registers so that within a limited frame we
+ * may have a fault and "jump back" to a known safe location.
+ *
+ * Copyright (C) 2005 by MontaVista Software.
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ENTRY (kgdb_fault_setjmp)
+	move    a1, sp
+	move	a2, fp
+#ifdef CONFIG_MIPS64
+	nop
+#endif
+	j	kgdb_fault_setjmp_aux
+	.end	kgdb_fault_setjmp
diff -puN arch/mips/kernel/Makefile~mips-lite arch/mips/kernel/Makefile
--- linux-2.6.13/arch/mips/kernel/Makefile~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/Makefile	2005-08-16 17:32:26.000000000 -0700
@@ -52,7 +52,8 @@ obj-$(CONFIG_MIPS32_COMPAT)	+= ioctl32.o
 obj-$(CONFIG_MIPS32_N32)	+= binfmt_elfn32.o scall64-n32.o signal_n32.o
 obj-$(CONFIG_MIPS32_O32)	+= binfmt_elfo32.o scall64-o32.o ptrace32.o
 
-obj-$(CONFIG_KGDB)		+= gdb-low.o gdb-stub.o
+obj-$(CONFIG_KGDB)		+= kgdb_handler.o kgdb.o kgdb-jmp.o	\
+					kgdb-setjmp.o
 obj-$(CONFIG_PROC_FS)		+= proc.o
 
 obj-$(CONFIG_MIPS64)		+= cpu-bugs64.o
diff -puN arch/mips/kernel/traps.c~mips-lite arch/mips/kernel/traps.c
--- linux-2.6.13/arch/mips/kernel/traps.c~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/kernel/traps.c	2005-08-16 17:32:26.000000000 -0700
@@ -10,6 +10,8 @@
  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000, 01 MIPS Technologies, Inc.
  * Copyright (C) 2002, 2003, 2004  Maciej W. Rozycki
+ *
+ * KGDB specific changes - Manish Lachwani (mlachwani@mvista.com)
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -20,6 +22,7 @@
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
+#include <linux/kgdb.h>
 
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
@@ -37,6 +40,7 @@
 #include <asm/mmu_context.h>
 #include <asm/watch.h>
 #include <asm/types.h>
+#include <asm/kdebug.h>
 
 extern asmlinkage void handle_tlbm(void);
 extern asmlinkage void handle_tlbl(void);
@@ -69,6 +73,21 @@ int (*board_be_handler)(struct pt_regs *
  */
 #define MODULE_RANGE (8*1024*1024)
 
+struct notifier_block *mips_die_chain;
+static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED;
+
+int register_die_notifier(struct notifier_block *nb)
+{
+	int err = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&die_notifier_lock, flags);
+	err = notifier_chain_register(&mips_die_chain, nb);
+	spin_unlock_irqrestore(&die_notifier_lock, flags);
+
+	return err;
+}
+
 /*
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
@@ -271,8 +290,10 @@ NORET_TYPE void __die(const char * str, 
 void __die_if_kernel(const char * str, struct pt_regs * regs,
 		     const char * file, const char * func, unsigned long line)
 {
-	if (!user_mode(regs))
+	if (!user_mode(regs)) {
+		notify_die(DIE_TRAP, (char *)str, regs, 0);
 		__die(str, regs, file, func, line);
+	}
 }
 
 extern const struct exception_table_entry __start___dbe_table[];
@@ -958,6 +979,9 @@ void __init trap_init(void)
 	extern char except_vec4;
 	unsigned long i;
 
+	if (kgdb_early_setup)
+		return;	/* Already done */
+
 	per_cpu_trap_init();
 
 	/*
diff -puN arch/mips/mips-boards/generic/init.c~mips-lite arch/mips/mips-boards/generic/init.c
--- linux-2.6.13/arch/mips/mips-boards/generic/init.c~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/mips-boards/generic/init.c	2005-08-16 17:32:26.000000000 -0700
@@ -35,15 +35,6 @@
 #include <asm/mips-boards/malta.h>
 #endif
 
-#ifdef CONFIG_KGDB
-extern int rs_kgdb_hook(int, int);
-extern int rs_putDebugChar(char);
-extern char rs_getDebugChar(void);
-extern int saa9730_kgdb_hook(int);
-extern int saa9730_putDebugChar(char);
-extern char saa9730_getDebugChar(void);
-#endif
-
 int prom_argc;
 int *_prom_argv, *_prom_envp;
 
@@ -170,59 +161,6 @@ static void __init console_config(void)
 }
 #endif
 
-#ifdef CONFIG_KGDB
-void __init kgdb_config (void)
-{
-	extern int (*generic_putDebugChar)(char);
-	extern char (*generic_getDebugChar)(void);
-	char *argptr;
-	int line, speed;
-
-	argptr = prom_getcmdline();
-	if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
-		argptr += strlen("kgdb=ttyS");
-		if (*argptr != '0' && *argptr != '1')
-			printk("KGDB: Unknown serial line /dev/ttyS%c, "
-			       "falling back to /dev/ttyS1\n", *argptr);
-		line = *argptr == '0' ? 0 : 1;
-		printk("KGDB: Using serial line /dev/ttyS%d for session\n", line);
-
-		speed = 0;
-		if (*++argptr == ',')
-		{
-			int c;
-			while ((c = *++argptr) && ('0' <= c && c <= '9'))
-				speed = speed * 10 + c - '0';
-		}
-#ifdef CONFIG_MIPS_ATLAS
-		if (line == 1) {
-			speed = saa9730_kgdb_hook(speed);
-			generic_putDebugChar = saa9730_putDebugChar;
-			generic_getDebugChar = saa9730_getDebugChar;
-		}
-		else 
-#endif
-		{
-			speed = rs_kgdb_hook(line, speed);
-			generic_putDebugChar = rs_putDebugChar;
-			generic_getDebugChar = rs_getDebugChar;
-		}
-
-		prom_printf("KGDB: Using serial line /dev/ttyS%d at %d for session, "
-			    "please connect your debugger\n", line ? 1 : 0, speed);
-
-		{
-			char *s;
-			for (s = "Please connect GDB to this port\r\n"; *s; )
-				generic_putDebugChar (*s++);
-		}
-
-		kgdb_enabled = 1;
-		/* Breakpoint is invoked after interrupts are initialised */
-	}
-}
-#endif
-
 void __init prom_init(void)
 {
 	prom_argc = fw_arg0;
diff -puN arch/mips/mips-boards/generic/Makefile~mips-lite arch/mips/mips-boards/generic/Makefile
--- linux-2.6.13/arch/mips/mips-boards/generic/Makefile~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/mips-boards/generic/Makefile	2005-08-16 17:32:26.000000000 -0700
@@ -21,6 +21,5 @@
 obj-y				:= mipsIRQ.o reset.o display.o init.o memory.o \
 				   printf.o cmdline.o time.o
 obj-$(CONFIG_PCI)		+= pci.o
-obj-$(CONFIG_KGDB)		+= gdb_hook.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -puN arch/mips/mips-boards/malta/malta_setup.c~mips-lite arch/mips/mips-boards/malta/malta_setup.c
--- linux-2.6.13/arch/mips/mips-boards/malta/malta_setup.c~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/mips-boards/malta/malta_setup.c	2005-08-16 17:32:26.000000000 -0700
@@ -48,10 +48,6 @@ extern void mips_time_init(void);
 extern void mips_timer_setup(struct irqaction *irq);
 extern unsigned long mips_rtc_get_time(void);
 
-#ifdef CONFIG_KGDB
-extern void kgdb_config(void);
-#endif
-
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
 	{ "timer", 0x40, 0x5f, IORESOURCE_BUSY },
@@ -124,10 +120,6 @@ static int __init malta_setup(void)
 	 */
 	enable_dma(4);
 
-#ifdef CONFIG_KGDB
-	kgdb_config ();
-#endif
-
 	if ((mips_revision_corid == MIPS_REVISION_CORID_BONITO64) ||
 	    (mips_revision_corid == MIPS_REVISION_CORID_CORE_20K) ||
 	    (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL_BON)) {
diff -puN arch/mips/mm/extable.c~mips-lite arch/mips/mm/extable.c
--- linux-2.6.13/arch/mips/mm/extable.c~mips-lite	2005-08-16 17:32:25.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/mm/extable.c	2005-08-16 17:32:26.000000000 -0700
@@ -3,6 +3,7 @@
  */
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/kgdb.h>
 #include <asm/branch.h>
 #include <asm/uaccess.h>
 
@@ -16,6 +17,12 @@ int fixup_exception(struct pt_regs *regs
 
 		return 1;
 	}
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+#endif
 
 	return 0;
 }
diff -puN arch/mips/sibyte/cfe/setup.c~mips-lite arch/mips/sibyte/cfe/setup.c
--- linux-2.6.13/arch/mips/sibyte/cfe/setup.c~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/cfe/setup.c	2005-08-16 17:32:26.000000000 -0700
@@ -58,10 +58,6 @@ int cfe_cons_handle;
 extern unsigned long initrd_start, initrd_end;
 #endif
 
-#ifdef CONFIG_KGDB
-extern int kgdb_port;
-#endif
-
 static void ATTRIB_NORET cfe_linux_exit(void *arg)
 {
 	int warm = *(int *)arg;
@@ -242,9 +238,6 @@ void __init prom_init(void)
 	int argc = fw_arg0;
 	char **envp = (char **) fw_arg2;
 	int *prom_vec = (int *) fw_arg3;
-#ifdef CONFIG_KGDB
-	char *arg;
-#endif
 
 	_machine_restart   = cfe_linux_restart;
 	_machine_halt      = cfe_linux_halt;
@@ -308,13 +301,6 @@ void __init prom_init(void)
 		}
 	}
 
-#ifdef CONFIG_KGDB
-	if ((arg = strstr(arcs_cmdline,"kgdb=duart")) != NULL)
-		kgdb_port = (arg[10] == '0') ? 0 : 1;
-	else
-		kgdb_port = 1;
-#endif
-
 #ifdef CONFIG_BLK_DEV_INITRD
 	{
 		char *ptr;
diff -puN arch/mips/sibyte/sb1250/irq.c~mips-lite arch/mips/sibyte/sb1250/irq.c
--- linux-2.6.13/arch/mips/sibyte/sb1250/irq.c~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/sb1250/irq.c	2005-08-16 17:32:26.000000000 -0700
@@ -31,6 +31,7 @@
 #include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
+#include <asm/kgdb.h>
 
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
@@ -60,16 +61,6 @@ static void sb1250_set_affinity(unsigned
 extern unsigned long ldt_eoi_space;
 #endif
 
-#ifdef CONFIG_KGDB
-static int kgdb_irq;
-
-/* Default to UART1 */
-int kgdb_port = 1;
-#ifdef CONFIG_SIBYTE_SB1250_DUART
-extern char sb1250_duart_present[];
-#endif
-#endif
-
 static struct hw_interrupt_type sb1250_irq_type = {
 	"SB1250-IMR",
 	startup_sb1250_irq,
@@ -338,6 +329,11 @@ void __init arch_init_irq(void)
 	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
 		STATUSF_IP1 | STATUSF_IP0;
 
+#ifdef CONFIG_KGDB
+	if (kgdb_early_setup)
+		return;
+#endif
+
 	/* Default everything to IP2 */
 	for (i = 0; i < SB1250_NR_IRQS; i++) {	/* was I0 */
 		bus_writeq(IMR_IP2_VAL,
@@ -387,45 +383,4 @@ void __init arch_init_irq(void)
 	/* Enable necessary IPs, disable the rest */
 	change_c0_status(ST0_IM, imask);
 	set_except_vector(0, sb1250_irq_handler);
-
-#ifdef CONFIG_KGDB
-	if (kgdb_flag) {
-		kgdb_irq = K_INT_UART_0 + kgdb_port;
-
-#ifdef CONFIG_SIBYTE_SB1250_DUART	
-		sb1250_duart_present[kgdb_port] = 0;
-#endif
-		/* Setup uart 1 settings, mapper */
-		bus_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port)));
-
-		sb1250_steal_irq(kgdb_irq);
-		bus_writeq(IMR_IP6_VAL,
-			   IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
-				  (kgdb_irq<<3)));
-		sb1250_unmask_irq(0, kgdb_irq);
-	}
-#endif
 }
-
-#ifdef CONFIG_KGDB
-
-#include <linux/delay.h>
-
-#define duart_out(reg, val)     csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-#define duart_in(reg)           csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-
-void sb1250_kgdb_interrupt(struct pt_regs *regs)
-{
-	/*
-	 * Clear break-change status (allow some time for the remote
-	 * host to stop the break, since we would see another
-	 * interrupt on the end-of-break too)
-	 */
-	kstat_this_cpu.irqs[kgdb_irq]++;
-	mdelay(500);
-	duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
-				M_DUART_RX_EN | M_DUART_TX_EN);
-	set_async_breakpoint(&regs->cp0_epc);
-}
-
-#endif 	/* CONFIG_KGDB */
diff -puN arch/mips/sibyte/sb1250/irq_handler.S~mips-lite arch/mips/sibyte/sb1250/irq_handler.S
--- linux-2.6.13/arch/mips/sibyte/sb1250/irq_handler.S~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/sb1250/irq_handler.S	2005-08-16 17:32:26.000000000 -0700
@@ -102,7 +102,7 @@
 2:
 #endif
 
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_KGDB_SIBYTE
 	/* KGDB (uart 1) interrupt is routed to IP[6] */
 	andi	t1, s0, CAUSEF_IP6
 	beqz	t1, 1f
diff -puN /dev/null arch/mips/sibyte/sb1250/kgdb_sibyte.c
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/sb1250/kgdb_sibyte.c	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,164 @@
+/*
+ * arch/mips/sibyte/sb1250/kgdb_sibyte.c
+ *
+ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com
+ *
+ * 2004 (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.
+ */
+
+/*
+ * Support for KGDB on the Broadcom Sibyte. The SWARM board
+ * for example does not have a 8250/16550 compatible serial
+ * port. Hence, we need to have a driver for the serial
+ * ports to handle KGDB.  This board needs nothing in addition
+ * to what is normally provided by the gdb portion of the stub.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/addrspace.h>
+
+int kgdb_port = 1;
+static int kgdb_irq;
+
+extern char sb1250_duart_present[];
+extern int sb1250_steal_irq(int irq);
+
+/* Forward declarations. */
+static void kgdbsibyte_init_duart(void);
+static int kgdb_init_io(void);
+
+#define IMR_IP6_VAL	K_INT_MAP_I4
+#define	duart_out(reg, val)	csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+#define duart_in(reg)		csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
+
+static void kgdb_swarm_write_char(int c)
+{
+	while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0) ;
+	duart_out(R_DUART_TX_HOLD, c);
+}
+
+static int kgdb_swarm_read_char(void)
+{
+	int ret_char;
+	unsigned int status;
+
+	status = duart_in(R_DUART_STATUS);
+	while ((status & M_DUART_RX_RDY) == 0) {
+		status = duart_in(R_DUART_STATUS);
+	}
+
+	/*
+	 * Check for framing error
+	 */
+	if (status & M_DUART_FRM_ERR) {
+		kgdbsibyte_init_duart();
+		kgdb_swarm_write_char('-');
+		return '-';
+	}
+
+	ret_char = duart_in(R_DUART_RX_HOLD);
+
+	return ret_char;
+}
+
+void sb1250_kgdb_interrupt(struct pt_regs *regs)
+{
+	int kgdb_irq = K_INT_UART_0 + kgdb_port;
+	/*
+	 * Clear break-change status (allow some time for the remote
+	 * host to stop the break, since we would see another
+	 * interrupt on the end-of-break too)
+	 */
+	kstat_this_cpu.irqs[kgdb_irq]++;
+	mdelay(500);
+	duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
+		  M_DUART_RX_EN | M_DUART_TX_EN);
+	if (kgdb_io_ops.init != kgdb_init_io) {
+		/* Throw away the data if another I/O routine is
+		 * active.
+		 */
+		unsigned int status;
+
+		status = duart_in(R_DUART_STATUS);
+		while ((status & M_DUART_RX_RDY) == 0) {
+			status = duart_in(R_DUART_STATUS);
+		}
+		/*
+		 * Check for framing error
+		 */
+		if (status & M_DUART_FRM_ERR) {
+			kgdbsibyte_init_duart();
+		}
+		duart_in(R_DUART_RX_HOLD);
+	} else
+		breakpoint();
+
+}
+
+/*
+ * We use port #1 and we set it for 115200 BAUD, 8n1.
+ */
+static void kgdbsibyte_init_duart(void)
+{
+	/* Set 8n1. */
+	duart_out(R_DUART_MODE_REG_1,
+		  V_DUART_BITS_PER_CHAR_8 | V_DUART_PARITY_MODE_NONE);
+	duart_out(R_DUART_MODE_REG_2, M_DUART_STOP_BIT_LEN_1);
+	/* Set baud rate of 115200. */
+	duart_out(R_DUART_CLK_SEL, V_DUART_BAUD_RATE(115200));
+	/* Enable rx and tx */
+	duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN);
+}
+
+static int kgdb_init_io(void)
+{
+#ifdef CONFIG_SIBYTE_SB1250_DUART
+	sb1250_duart_present[kgdb_port] = 0;
+#endif
+
+	kgdbsibyte_init_duart();
+
+	return 0;
+}
+
+/*
+ * Hookup our IRQ line.  We will already have been initialized a
+ * this point.
+ */
+static void __init kgdbsibyte_hookup_irq(void)
+{
+	/* Steal the IRQ. */
+	kgdb_irq = K_INT_UART_0 + kgdb_port;
+
+	/* Setup uart 1 settings, mapper */
+	__raw_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port)));
+
+	sb1250_steal_irq(kgdb_irq);
+
+	__raw_writeq(IMR_IP6_VAL,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
+			    (kgdb_irq << 3)));
+
+	sb1250_unmask_irq(0, kgdb_irq);
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.read_char = kgdb_swarm_read_char,
+	.write_char = kgdb_swarm_write_char,
+	.init = kgdb_init_io,
+	.late_init = kgdbsibyte_hookup_irq,
+	.pre_exception = NULL,
+	.post_exception = NULL
+};
diff -puN arch/mips/sibyte/sb1250/Makefile~mips-lite arch/mips/sibyte/sb1250/Makefile
--- linux-2.6.13/arch/mips/sibyte/sb1250/Makefile~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/sb1250/Makefile	2005-08-16 17:32:26.000000000 -0700
@@ -4,5 +4,6 @@ obj-$(CONFIG_SMP)			+= smp.o
 obj-$(CONFIG_SIBYTE_TBPROF)		+= bcm1250_tbprof.o
 obj-$(CONFIG_SIBYTE_STANDALONE)		+= prom.o
 obj-$(CONFIG_SIBYTE_BUS_WATCHER)	+= bus_watcher.o
+obj-$(CONFIG_KGDB_SIBYTE)		+= kgdb_sibyte.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -L arch/mips/sibyte/swarm/dbg_io.c -puN arch/mips/sibyte/swarm/dbg_io.c~mips-lite /dev/null
--- linux-2.6.13/arch/mips/sibyte/swarm/dbg_io.c
+++ /dev/null	2005-08-15 07:19:53.144310000 -0700
@@ -1,76 +0,0 @@
-/*
- * kgdb debug routines for SiByte boards.
- *
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * 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 of the  License, or (at your
- * option) any later version.
- *
- */
-
-/* -------------------- BEGINNING OF CONFIG --------------------- */
-
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_uart.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/addrspace.h>
-
-/*
- * We use the second serial port for kgdb traffic.
- * 	115200, 8, N, 1.
- */
-
-#define	BAUD_RATE		115200
-#define	CLK_DIVISOR		V_DUART_BAUD_RATE(BAUD_RATE)
-#define	DATA_BITS		V_DUART_BITS_PER_CHAR_8		/* or 7    */
-#define	PARITY			V_DUART_PARITY_MODE_NONE	/* or even */
-#define	STOP_BITS		M_DUART_STOP_BIT_LEN_1		/* or 2    */
-
-static int duart_initialized = 0;	/* 0: need to be init'ed by kgdb */
-
-/* -------------------- END OF CONFIG --------------------- */
-extern int kgdb_port;
-
-#define	duart_out(reg, val)	csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-#define duart_in(reg)		csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-
-void putDebugChar(unsigned char c);
-unsigned char getDebugChar(void);
-static void
-duart_init(int clk_divisor, int data, int parity, int stop)
-{
-	duart_out(R_DUART_MODE_REG_1, data | parity);
-	duart_out(R_DUART_MODE_REG_2, stop);
-	duart_out(R_DUART_CLK_SEL, clk_divisor);
-
-	duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN);	/* enable rx and tx */
-}
-
-void
-putDebugChar(unsigned char c)
-{
-	if (!duart_initialized) {
-		duart_initialized = 1;
-		duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS);
-	}
-	while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0);
-	duart_out(R_DUART_TX_HOLD, c);
-}
-
-unsigned char
-getDebugChar(void)
-{
-	if (!duart_initialized) {
-		duart_initialized = 1;
-		duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS);
-	}
-	while ((duart_in(R_DUART_STATUS) & M_DUART_RX_RDY) == 0) ;
-	return duart_in(R_DUART_RX_HOLD);
-}
-
diff -puN arch/mips/sibyte/swarm/Makefile~mips-lite arch/mips/sibyte/swarm/Makefile
--- linux-2.6.13/arch/mips/sibyte/swarm/Makefile~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/arch/mips/sibyte/swarm/Makefile	2005-08-16 17:32:26.000000000 -0700
@@ -1,3 +1 @@
 lib-y				= setup.o rtc_xicor1241.o rtc_m41t81.o
-
-lib-$(CONFIG_KGDB)		+= dbg_io.o
diff -puN /dev/null include/asm-mips/kdebug.h
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/include/asm-mips/kdebug.h	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright (C) 2004  MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com
+ *
+ * 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 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef _MIPS_KDEBUG_H
+#define _MIPS_KDEBUG_H
+
+#include <linux/notifier.h>
+
+struct pt_regs;
+
+struct die_args {
+	struct pt_regs *regs;
+	const char *str;
+	long err;
+};
+
+int register_die_notifier(struct notifier_block *nb);
+extern struct notifier_block *mips_die_chain;
+
+enum die_val {
+	DIE_OOPS = 1,
+	DIE_PANIC,
+	DIE_DIE,
+	DIE_KERNELDEBUG,
+	DIE_TRAP,
+	DIE_PAGE_FAULT,
+};
+
+/*
+ * trap number can be computed from regs and signr can be computed using
+ * compute_signal()
+ */
+static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err)
+{
+	struct die_args args = { .regs=regs, .str=str, .err=err };
+	return notifier_call_chain(&mips_die_chain, val, &args);
+}
+
+#endif /* _MIPS_KDEBUG_H */
diff -puN /dev/null include/asm-mips/kgdb.h
--- /dev/null	2005-08-15 07:19:53.144310000 -0700
+++ linux-2.6.13-trini/include/asm-mips/kgdb.h	2005-08-16 17:32:26.000000000 -0700
@@ -0,0 +1,22 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+#define BUFMAX			2048
+#define NUMREGBYTES		(90*sizeof(long))
+#define NUMCRITREGBYTES		(12*sizeof(long))
+#define BREAK_INSTR_SIZE	4
+#define BREAKPOINT()		__asm__ __volatile__(		\
+					".globl breakinst\n\t"	\
+					".set\tnoreorder\n\t"	\
+					"nop\n"			\
+					"breakinst:\tbreak\n\t"	\
+					"nop\n\t"		\
+					".set\treorder")
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	0
+
+extern int kgdb_early_setup;
+
+#endif				/* _ASM_KGDB_H_ */
+#endif				/* __KERNEL__ */
diff -puN lib/Kconfig.debug~mips-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~mips-lite	2005-08-16 17:32:26.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-16 17:32:26.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || ((!SMP || BROKEN) && (PPC32)))
+	depends on DEBUG_KERNEL && (X86 || MIPS32 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
@@ -189,6 +189,7 @@ choice
 	prompt "Method for KGDB communication"
 	depends on KGDB
 	default KGDB_8250_NOMODULE
+	default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC
 	default KGDB_MPSC if SERIAL_MPSC
 	help
 	  There are a number of different ways in which you can communicate
@@ -222,6 +223,10 @@ config KGDB_MPSC
 	  Controller (MPSC) channel. Note that the GT64260A is not
 	  supported.
 
+config KGDB_SIBYTE
+	bool "KGDB: On the Broadcom SWARM serial port"
+	depends on MIPS && SIBYTE_SB1xxx_SOC
+
 endchoice
 
 config KGDB_8250
_

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

* [patch 06/16] Add support for IA64 platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (3 preceding siblings ...)
  2005-08-29 16:09   ` [patch 05/16] Add support for MIPS platforms to KGDB Tom Rini
@ 2005-08-29 16:10   ` Tom Rini
  2005-08-29 16:10   ` [patch 07/16] x86_64: Rename KDB_VECTOR to DEBUGGER_VECTOR Tom Rini
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:10 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, Robert.Picco, tony.luck


This is support of the IA64 arch for KGDB.  This is primarily the work of
Robert Picco.  There are also some IA64 changes in the serial patch so that
IA64 can pass in IRQ and iomembase, and all of this is documented in the
DocBook files.

---

 linux-2.6.13-trini/arch/ia64/kernel/Makefile   |    1 
 linux-2.6.13-trini/arch/ia64/kernel/entry.S    |    4 
 linux-2.6.13-trini/arch/ia64/kernel/ivt.S      |   15 
 linux-2.6.13-trini/arch/ia64/kernel/kgdb-jmp.S |  238 ++++
 linux-2.6.13-trini/arch/ia64/kernel/kgdb.c     | 1038 +++++++++++++++++++++
 linux-2.6.13-trini/arch/ia64/kernel/mca.c      |   10 
 linux-2.6.13-trini/arch/ia64/kernel/process.c  |    6 
 linux-2.6.13-trini/arch/ia64/kernel/smp.c      |   17 
 linux-2.6.13-trini/arch/ia64/kernel/traps.c    |   36 
 linux-2.6.13-trini/arch/ia64/kernel/unwind.c   |   87 +
 linux-2.6.13-trini/arch/ia64/mm/extable.c      |    6 
 linux-2.6.13-trini/arch/ia64/mm/fault.c        |    5 
 linux-2.6.13-trini/include/asm-ia64/kgdb.h     |   37 
 linux-2.6.13-trini/lib/Kconfig.debug           |    2 
 14 files changed, 1497 insertions(+), 5 deletions(-)

diff -puN arch/ia64/kernel/entry.S~ia64-lite arch/ia64/kernel/entry.S
--- linux-2.6.13/arch/ia64/kernel/entry.S~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/entry.S	2005-08-08 12:18:23.000000000 -0700
@@ -929,9 +929,9 @@ GLOBAL_ENTRY(ia64_leave_kernel)
 	shr.u r18=r19,16	// get byte size of existing "dirty" partition
 	;;
 	mov r16=ar.bsp		// get existing backing store pointer
-	addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0
+(pUStk)	addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0
 	;;
-	ld4 r17=[r17]		// r17 = cpu_data->phys_stacked_size_p8
+(pUStk)	ld4 r17=[r17]		// r17 = cpu_data->phys_stacked_size_p8
 (pKStk)	br.cond.dpnt skip_rbs_switch
 
 	/*
diff -puN arch/ia64/kernel/ivt.S~ia64-lite arch/ia64/kernel/ivt.S
--- linux-2.6.13/arch/ia64/kernel/ivt.S~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/ivt.S	2005-08-08 12:18:23.000000000 -0700
@@ -69,6 +69,13 @@
 # define DBG_FAULT(i)
 #endif
 
+#ifdef	CONFIG_KGDB
+#define	KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; or r31=r31,r30;; \
+		mov psr.l=r31;; srlz.i;;
+#else
+#define	KGDB_ENABLE_PSR_DB
+#endif
+
 #define MINSTATE_VIRT	/* needed by minstate.h */
 #include "minstate.h"
 
@@ -479,6 +486,7 @@ ENTRY(page_fault)
 	movl r14=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r14
 	;;
 	adds out2=16,r12			// out2 = pointer to pt_regs
@@ -820,6 +828,7 @@ ENTRY(interrupt)
 	srlz.i			// ensure everybody knows psr.ic is back on
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	;;
 	alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
 	mov out0=cr.ivr		// pass cr.ivr as first arg
@@ -1066,6 +1075,7 @@ ENTRY(non_syscall)
 	movl r15=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r15
 	;;
 	br.call.sptk.many b6=ia64_bad_break	// avoid WAW on CFM and ignore return addr
@@ -1099,6 +1109,7 @@ ENTRY(dispatch_unaligned_handler)
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
@@ -1141,6 +1152,10 @@ ENTRY(dispatch_to_fault_handler)
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
 	;;
 	SAVE_REST
+	cmp.eq p6,p0=29,out0
+(p6)	br.cond.spnt 1f;;			// debug_vector
+	KGDB_ENABLE_PSR_DB
+1:
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
diff -puN /dev/null arch/ia64/kernel/kgdb.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/kgdb.c	2005-08-08 12:18:23.000000000 -0700
@@ -0,0 +1,1038 @@
+/*
+ *
+ * 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) 2000-2001 VERITAS Software Corporation.
+ */
+/*
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ */
+
+#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 <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/unwind.h>
+#include <asm/rse.h>
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <asm/cacheflush.h>
+
+#define NUM_REGS 590
+#define REGISTER_BYTES (NUM_REGS*8+128*8)
+#define REGISTER_BYTE(N) (((N) * 8) \
+  + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM)))
+#define	REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8)
+#define IA64_GR0_REGNUM         0
+#define IA64_FR0_REGNUM         128
+#define IA64_FR127_REGNUM       (IA64_FR0_REGNUM+127)
+#define IA64_PR0_REGNUM         256
+#define IA64_BR0_REGNUM         320
+#define IA64_VFP_REGNUM         328
+#define IA64_PR_REGNUM          330
+#define IA64_IP_REGNUM          331
+#define IA64_PSR_REGNUM         332
+#define IA64_CFM_REGNUM         333
+#define IA64_AR0_REGNUM         334
+#define IA64_NAT0_REGNUM        462
+#define IA64_NAT31_REGNUM       (IA64_NAT0_REGNUM+31)
+#define IA64_NAT32_REGNUM       (IA64_NAT0_REGNUM+32)
+#define IA64_RSC_REGNUM		(IA64_AR0_REGNUM+16)
+#define IA64_BSP_REGNUM		(IA64_AR0_REGNUM+17)
+#define IA64_BSPSTORE_REGNUM	(IA64_AR0_REGNUM+18)
+#define IA64_RNAT_REGNUM	(IA64_AR0_REGNUM+19)
+#define IA64_FCR_REGNUM		(IA64_AR0_REGNUM+21)
+#define IA64_EFLAG_REGNUM	(IA64_AR0_REGNUM+24)
+#define IA64_CSD_REGNUM		(IA64_AR0_REGNUM+25)
+#define IA64_SSD_REGNUM		(IA64_AR0_REGNUM+26)
+#define IA64_CFLG_REGNUM	(IA64_AR0_REGNUM+27)
+#define IA64_FSR_REGNUM		(IA64_AR0_REGNUM+28)
+#define IA64_FIR_REGNUM		(IA64_AR0_REGNUM+29)
+#define IA64_FDR_REGNUM		(IA64_AR0_REGNUM+30)
+#define IA64_CCV_REGNUM		(IA64_AR0_REGNUM+32)
+#define IA64_UNAT_REGNUM	(IA64_AR0_REGNUM+36)
+#define IA64_FPSR_REGNUM	(IA64_AR0_REGNUM+40)
+#define IA64_ITC_REGNUM		(IA64_AR0_REGNUM+44)
+#define IA64_PFS_REGNUM		(IA64_AR0_REGNUM+64)
+#define IA64_LC_REGNUM		(IA64_AR0_REGNUM+65)
+#define IA64_EC_REGNUM		(IA64_AR0_REGNUM+66)
+
+#define	REGISTER_INDEX(N)	(REGISTER_BYTE(N) / sizeof (unsigned long))
+
+#define	ptoff(V)	((unsigned int) &((struct pt_regs *)0x0)->V)
+struct reg_to_ptreg_index {
+	unsigned int reg;
+	unsigned int ptregoff;
+};
+struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = {
+	{IA64_GR0_REGNUM + 8, ptoff(r8)},
+	{IA64_GR0_REGNUM + 9, ptoff(r9)},
+	{IA64_GR0_REGNUM + 10, ptoff(r10)},
+	{IA64_GR0_REGNUM + 11, ptoff(r11)},
+	{IA64_GR0_REGNUM + 1, ptoff(r1)},
+	{IA64_GR0_REGNUM + 12, ptoff(r12)},
+	{IA64_GR0_REGNUM + 13, ptoff(r13)},
+	{IA64_GR0_REGNUM + 14, ptoff(r14)},
+	{IA64_GR0_REGNUM + 15, ptoff(r15)},
+};
+
+struct reg_to_ptreg_index br_reg_to_ptreg_index[] = {
+	{IA64_BR0_REGNUM, ptoff(b0)},
+	{IA64_BR0_REGNUM + 6, ptoff(b6)},
+	{IA64_BR0_REGNUM + 7, ptoff(b7)},
+};
+
+extern atomic_t cpu_doing_single_step;
+
+void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info,
+		  struct pt_regs *ptregs)
+{
+	unsigned long reg, size = 0, *mem = &reg;
+	char nat;
+	struct ia64_fpreg freg;
+	int i;
+
+	if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) ||
+	    (regnum >= (IA64_GR0_REGNUM + 4) && regnum <= (IA64_GR0_REGNUM + 7))
+	    || (regnum >= (IA64_GR0_REGNUM + 16)
+		&& regnum <= (IA64_GR0_REGNUM + 31))) {
+		unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg, &nat, 0);
+		size = sizeof(reg);
+	} else
+	    if ((regnum >= (IA64_GR0_REGNUM + 2)
+		 && regnum <= (IA64_GR0_REGNUM + 3))
+		|| (regnum >= (IA64_GR0_REGNUM + 8)
+		    && regnum <= (IA64_GR0_REGNUM + 15))) {
+		if (ptregs) {
+			for (i = 0; i < (sizeof(gr_reg_to_ptreg_index) /
+					 sizeof(gr_reg_to_ptreg_index[0])); i++)
+				if (gr_reg_to_ptreg_index[0].reg == regnum) {
+					reg = *((unsigned long *)
+					    (((void *)ptregs) +
+					    gr_reg_to_ptreg_index[i].ptregoff));
+					break;
+				}
+		} else
+			unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg,
+				      &nat, 0);
+		size = sizeof(reg);
+	} else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7))
+		switch (regnum) {
+		case IA64_BR0_REGNUM:
+		case IA64_BR0_REGNUM + 6:
+		case IA64_BR0_REGNUM + 7:
+			if (ptregs) {
+				for (i = 0; i < (sizeof(br_reg_to_ptreg_index) /
+						 sizeof(br_reg_to_ptreg_index
+							[0])); i++)
+					if (br_reg_to_ptreg_index[i].reg ==
+					    regnum) {
+						reg = *((unsigned long *)
+							(((void *)ptregs) +
+							 br_reg_to_ptreg_index
+							 [i].ptregoff));
+						break;
+					}
+			} else
+				unw_access_br(info, regnum - IA64_BR0_REGNUM,
+					      &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_BR0_REGNUM + 1:
+		case IA64_BR0_REGNUM + 2:
+		case IA64_BR0_REGNUM + 3:
+		case IA64_BR0_REGNUM + 4:
+		case IA64_BR0_REGNUM + 5:
+			unw_access_br(info, regnum - IA64_BR0_REGNUM, &reg, 0);
+			size = sizeof(reg);
+			break;
+	} else if (regnum >= IA64_FR0_REGNUM
+		   && regnum <= (IA64_FR0_REGNUM + 127))
+		switch (regnum) {
+		case IA64_FR0_REGNUM + 6:
+		case IA64_FR0_REGNUM + 7:
+		case IA64_FR0_REGNUM + 8:
+		case IA64_FR0_REGNUM + 9:
+		case IA64_FR0_REGNUM + 10:
+		case IA64_FR0_REGNUM + 11:
+		case IA64_FR0_REGNUM + 12:
+			if (!ptregs)
+				unw_access_fr(info, regnum - IA64_FR0_REGNUM,
+					      &freg, 0);
+			else {
+				freg =
+				    *(&ptregs->f6 +
+				      (regnum - (IA64_FR0_REGNUM + 6)));
+			}
+			size = sizeof(freg);
+			mem = (unsigned long *)&freg;
+			break;
+		default:
+			unw_access_fr(info, regnum - IA64_FR0_REGNUM, &freg, 0);
+			break;
+	} else if (regnum == IA64_IP_REGNUM) {
+		if (!ptregs)
+			unw_get_ip(info, &reg);
+		else
+			reg = ptregs->cr_iip;
+		size = sizeof(reg);
+	} else if (regnum == IA64_CFM_REGNUM) {
+		if (!ptregs)
+			unw_get_cfm(info, &reg);
+		else
+			reg = ptregs->cr_ifs;
+		size = sizeof(reg);
+	} else if (regnum == IA64_PSR_REGNUM) {
+		if (!ptregs && kgdb_usethread)
+			ptregs = (struct pt_regs *)
+			    ((unsigned long)kgdb_usethread + IA64_STK_OFFSET) -
+			    1;
+		if (ptregs)
+			reg = ptregs->cr_ipsr;
+		size = sizeof(reg);
+	} else if (regnum == IA64_PR_REGNUM) {
+		if (ptregs)
+			reg = ptregs->pr;
+		else
+			unw_access_pr(info, &reg, 0);
+		size = sizeof(reg);
+	} else if (regnum == IA64_BSP_REGNUM) {
+		unw_get_bsp(info, &reg);
+		size = sizeof(reg);
+	} else if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM)
+		switch (regnum) {
+		case IA64_CSD_REGNUM:
+			if (ptregs)
+				reg = ptregs->ar_csd;
+			else
+				unw_access_ar(info, UNW_AR_CSD, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_SSD_REGNUM:
+			if (ptregs)
+				reg = ptregs->ar_ssd;
+			else
+				unw_access_ar(info, UNW_AR_SSD, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_UNAT_REGNUM:
+			if (ptregs)
+				reg = ptregs->ar_unat;
+			else
+				unw_access_ar(info, UNW_AR_UNAT, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_RNAT_REGNUM:
+			unw_access_ar(info, UNW_AR_RNAT, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_BSPSTORE_REGNUM:
+			unw_access_ar(info, UNW_AR_BSPSTORE, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_PFS_REGNUM:
+			unw_access_ar(info, UNW_AR_PFS, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_LC_REGNUM:
+			unw_access_ar(info, UNW_AR_LC, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_EC_REGNUM:
+			unw_access_ar(info, UNW_AR_EC, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_FPSR_REGNUM:
+			if (ptregs)
+				reg = ptregs->ar_fpsr;
+			else
+				unw_access_ar(info, UNW_AR_FPSR, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_RSC_REGNUM:
+			if (ptregs)
+				reg = ptregs->ar_rsc;
+			else
+				unw_access_ar(info, UNW_AR_RNAT, &reg, 0);
+			size = sizeof(reg);
+			break;
+		case IA64_CCV_REGNUM:
+			unw_access_ar(info, UNW_AR_CCV, &reg, 0);
+			size = sizeof(reg);
+			break;
+		}
+
+	if (size) {
+		kgdb_mem2hex((char *)mem, outbuffer, size);
+		outbuffer[size * 2] = 0;
+	} else
+		strcpy(outbuffer, "E0");
+
+	return;
+}
+
+void kgdb_put_reg(char *inbuffer, char *outbuffer, int regnum,
+		  struct unw_frame_info *info, struct pt_regs *ptregs)
+{
+	unsigned long reg;
+	char nat = 0;
+	struct ia64_fpreg freg;
+	int i;
+	char *ptr;
+
+	ptr = inbuffer;
+	kgdb_hex2long(&ptr, &reg);
+	strcpy(outbuffer, "OK");
+
+	if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) ||
+	    (regnum >= (IA64_GR0_REGNUM + 4) && regnum <= (IA64_GR0_REGNUM + 7))
+	    || (regnum >= (IA64_GR0_REGNUM + 16)
+		&& regnum <= (IA64_GR0_REGNUM + 31))) {
+		unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg, &nat, 1);
+	} else
+	    if ((regnum >= (IA64_GR0_REGNUM + 2)
+		 && regnum <= (IA64_GR0_REGNUM + 3))
+		|| (regnum >= (IA64_GR0_REGNUM + 8)
+		    && regnum <= (IA64_GR0_REGNUM + 15))) {
+		for (i = 0;
+		     i <
+		     (sizeof(gr_reg_to_ptreg_index) /
+		      sizeof(gr_reg_to_ptreg_index[0])); i++)
+			if (gr_reg_to_ptreg_index[0].reg == regnum) {
+				*((unsigned long *)
+				  (((void *)ptregs) +
+				   gr_reg_to_ptreg_index[i].ptregoff)) = reg;
+				break;
+			}
+	} else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7))
+		switch (regnum) {
+		case IA64_BR0_REGNUM:
+		case IA64_BR0_REGNUM + 6:
+		case IA64_BR0_REGNUM + 7:
+			for (i = 0; i < (sizeof(br_reg_to_ptreg_index) /
+					 sizeof(br_reg_to_ptreg_index[0])); i++)
+				if (br_reg_to_ptreg_index[i].reg == regnum) {
+					*((unsigned long *)
+					  (((void *)ptregs) +
+					   br_reg_to_ptreg_index[i].ptregoff)) =
+			 reg;
+					break;
+				}
+			break;
+		case IA64_BR0_REGNUM + 1:
+		case IA64_BR0_REGNUM + 2:
+		case IA64_BR0_REGNUM + 3:
+		case IA64_BR0_REGNUM + 4:
+		case IA64_BR0_REGNUM + 5:
+			unw_access_br(info, regnum - IA64_BR0_REGNUM, &reg, 1);
+			break;
+	} else if (regnum >= IA64_FR0_REGNUM
+		   && regnum <= (IA64_FR0_REGNUM + 127))
+		switch (regnum) {
+		case IA64_FR0_REGNUM + 6:
+		case IA64_FR0_REGNUM + 7:
+		case IA64_FR0_REGNUM + 8:
+		case IA64_FR0_REGNUM + 9:
+		case IA64_FR0_REGNUM + 10:
+		case IA64_FR0_REGNUM + 11:
+		case IA64_FR0_REGNUM + 12:
+			freg.u.bits[0] = reg;
+			kgdb_hex2long(&ptr, &freg.u.bits[1]);
+			*(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))) =
+			    freg;
+			break;
+		default:
+			break;
+	} else if (regnum == IA64_IP_REGNUM)
+		ptregs->cr_iip = reg;
+	else if (regnum == IA64_CFM_REGNUM)
+		ptregs->cr_ifs = reg;
+	else if (regnum == IA64_PSR_REGNUM)
+		ptregs->cr_ipsr = reg;
+	else if (regnum == IA64_PR_REGNUM)
+		ptregs->pr = reg;
+	else if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM)
+		switch (regnum) {
+		case IA64_CSD_REGNUM:
+			ptregs->ar_csd = reg;
+			break;
+		case IA64_SSD_REGNUM:
+			ptregs->ar_ssd = reg;
+		case IA64_UNAT_REGNUM:
+			ptregs->ar_unat = reg;
+		case IA64_RNAT_REGNUM:
+			unw_access_ar(info, UNW_AR_RNAT, &reg, 1);
+			break;
+		case IA64_BSPSTORE_REGNUM:
+			unw_access_ar(info, UNW_AR_BSPSTORE, &reg, 1);
+			break;
+		case IA64_PFS_REGNUM:
+			unw_access_ar(info, UNW_AR_PFS, &reg, 1);
+			break;
+		case IA64_LC_REGNUM:
+			unw_access_ar(info, UNW_AR_LC, &reg, 1);
+			break;
+		case IA64_EC_REGNUM:
+			unw_access_ar(info, UNW_AR_EC, &reg, 1);
+			break;
+		case IA64_FPSR_REGNUM:
+			ptregs->ar_fpsr = reg;
+			break;
+		case IA64_RSC_REGNUM:
+			ptregs->ar_rsc = reg;
+			break;
+		case IA64_CCV_REGNUM:
+			unw_access_ar(info, UNW_AR_CCV, &reg, 1);
+			break;
+	} else
+		strcpy(outbuffer, "E01");
+
+	return;
+}
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+
+}
+
+#define	MAX_HW_BREAKPOINT	(20)
+long hw_break_total_dbr, hw_break_total_ibr;
+#define	HW_BREAKPOINT	(hw_break_total_dbr + hw_break_total_ibr)
+#define	WATCH_INSTRUCTION	0x0
+#define WATCH_WRITE		0x1
+#define	WATCH_READ		0x2
+#define	WATCH_ACCESS		0x3
+
+#define	HWCAP_DBR	((1 << WATCH_WRITE) | (1 << WATCH_READ))
+#define	HWCAP_IBR	(1 << WATCH_INSTRUCTION)
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned long capable;
+	unsigned long type;
+	unsigned long mask;
+	unsigned long addr;
+} *breakinfo;
+
+static struct hw_breakpoint hwbreaks[MAX_HW_BREAKPOINT];
+
+enum instruction_type { A, I, M, F, B, L, X, u };
+
+static enum instruction_type bundle_encoding[32][3] = {
+	{M, I, I},		/* 00 */
+	{M, I, I},		/* 01 */
+	{M, I, I},		/* 02 */
+	{M, I, I},		/* 03 */
+	{M, L, X},		/* 04 */
+	{M, L, X},		/* 05 */
+	{u, u, u},		/* 06 */
+	{u, u, u},		/* 07 */
+	{M, M, I},		/* 08 */
+	{M, M, I},		/* 09 */
+	{M, M, I},		/* 0A */
+	{M, M, I},		/* 0B */
+	{M, F, I},		/* 0C */
+	{M, F, I},		/* 0D */
+	{M, M, F},		/* 0E */
+	{M, M, F},		/* 0F */
+	{M, I, B},		/* 10 */
+	{M, I, B},		/* 11 */
+	{M, B, B},		/* 12 */
+	{M, B, B},		/* 13 */
+	{u, u, u},		/* 14 */
+	{u, u, u},		/* 15 */
+	{B, B, B},		/* 16 */
+	{B, B, B},		/* 17 */
+	{M, M, B},		/* 18 */
+	{M, M, B},		/* 19 */
+	{u, u, u},		/* 1A */
+	{u, u, u},		/* 1B */
+	{M, F, B},		/* 1C */
+	{M, F, B},		/* 1D */
+	{u, u, u},		/* 1E */
+	{u, u, u},		/* 1F */
+};
+
+static int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+	extern unsigned long _start[];
+	unsigned long slot = addr & 0xf, bundle_addr;
+	unsigned long template;
+	struct bundle {
+		struct {
+			unsigned long long template:5;
+			unsigned long long slot0:41;
+			unsigned long long slot1_p0:64 - 46;
+		} quad0;
+		struct {
+			unsigned long long slot1_p1:41 - (64 - 46);
+			unsigned long long slot2:41;
+		} quad1;
+	} bundle;
+	int ret;
+
+	bundle_addr = addr & ~0xFULL;
+
+	if (bundle_addr == (unsigned long)_start)
+		return 0;
+
+	ret = kgdb_get_mem((char *)bundle_addr, (char *)&bundle,
+			   BREAK_INSTR_SIZE);
+	if (ret < 0)
+		return ret;
+
+	if (slot > 2)
+		slot = 0;
+
+	memcpy(saved_instr, &bundle, BREAK_INSTR_SIZE);
+	template = bundle.quad0.template;
+
+	if (slot == 1 && bundle_encoding[template][1] == L)
+		slot = 2;
+
+	switch (slot) {
+	case 0:
+		bundle.quad0.slot0 = BREAKNUM;
+		break;
+	case 1:
+		bundle.quad0.slot1_p0 = BREAKNUM;
+		bundle.quad1.slot1_p1 = (BREAKNUM >> (64 - 46));
+		break;
+	case 2:
+		bundle.quad1.slot2 = BREAKNUM;
+		break;
+	}
+
+	return kgdb_set_mem((char *)bundle_addr, (char *)&bundle,
+			    BREAK_INSTR_SIZE);
+}
+
+static int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+	extern unsigned long _start[];
+
+	addr = addr & ~0xFULL;
+	if (addr == (unsigned long)_start)
+		return 0;
+	return kgdb_set_mem((char *)addr, (char *)bundle, BREAK_INSTR_SIZE);
+}
+
+static int hw_breakpoint_init;
+
+void do_init_hw_break(void)
+{
+	s64 status;
+	int i;
+
+	hw_breakpoint_init = 1;
+
+#ifdef	CONFIG_IA64_HP_SIM
+	hw_break_total_ibr = 8;
+	hw_break_total_dbr = 8;
+	status = 0;
+#else
+	status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr);
+#endif
+
+	if (status) {
+		printk(KERN_INFO "do_init_hw_break: pal call failed %d\n",
+		       (int)status);
+		return;
+	}
+
+	if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) {
+		printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n",
+		       (int)HW_BREAKPOINT, (int)MAX_HW_BREAKPOINT);
+
+		while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+		       && hw_break_total_ibr != 1)
+			hw_break_total_ibr--;
+		while (HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+			hw_break_total_dbr--;
+	}
+
+	breakinfo = hwbreaks;
+
+	memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+	for (i = 0; i < hw_break_total_dbr; i++)
+		breakinfo[i].capable = HWCAP_DBR;
+
+	for (; i < HW_BREAKPOINT; i++)
+		breakinfo[i].capable = HWCAP_IBR;
+
+	return;
+}
+
+void kgdb_correct_hw_break(void)
+{
+	int breakno;
+
+	if (!breakinfo)
+		return;
+
+	for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+		if (breakinfo[breakno].enabled) {
+			if (breakinfo[breakno].capable & HWCAP_IBR) {
+				int ibreakno = breakno - hw_break_total_dbr;
+				ia64_set_ibr(ibreakno << 1,
+					     breakinfo[breakno].addr);
+				ia64_set_ibr((ibreakno << 1) + 1,
+					     (~breakinfo[breakno].mask &
+					      ((1UL << 56UL) - 1)) |
+					      (1UL << 56UL) | (1UL << 63UL));
+			} else {
+				ia64_set_dbr(breakno << 1,
+					     breakinfo[breakno].addr);
+				ia64_set_dbr((breakno << 1) + 1,
+					     (~breakinfo[breakno].
+					      mask & ((1UL << 56UL) - 1)) |
+					     (1UL << 56UL) |
+					     (breakinfo[breakno].type << 62UL));
+			}
+		} else {
+			if (breakinfo[breakno].capable & HWCAP_IBR)
+				ia64_set_ibr(((breakno -
+					       hw_break_total_dbr) << 1) + 1,
+					     0);
+			else
+				ia64_set_dbr((breakno << 1) + 1, 0);
+		}
+	}
+
+	return;
+}
+
+int hardware_breakpoint(unsigned long addr, int length, int type, int action)
+{
+	int breakno, found, watch;
+	unsigned long mask;
+	extern unsigned long _start[];
+
+	if (!hw_breakpoint_init)
+		do_init_hw_break();
+
+	if (!breakinfo)
+		return 0;
+	else if (addr == (unsigned long)_start)
+		return 1;
+
+	if (type == WATCH_ACCESS)
+		mask = HWCAP_DBR;
+	else
+		mask = 1UL << type;
+
+	for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT;
+	     breakno++) {
+		if (action) {
+			if (breakinfo[breakno].enabled
+			    || !(breakinfo[breakno].capable & mask))
+				continue;
+			breakinfo[breakno].enabled = 1;
+			breakinfo[breakno].type = type;
+			breakinfo[breakno].mask = length - 1;
+			breakinfo[breakno].addr = addr;
+			watch = breakno;
+		} else if (breakinfo[breakno].enabled &&
+			   ((length < 0 && breakinfo[breakno].addr == addr) ||
+			    ((breakinfo[breakno].capable & mask) &&
+			     (breakinfo[breakno].mask == (length - 1)) &&
+			     (breakinfo[breakno].addr == addr)))) {
+			breakinfo[breakno].enabled = 0;
+			breakinfo[breakno].type = 0UL;
+		} else
+			continue;
+		found++;
+		if (type != WATCH_ACCESS)
+			break;
+		else if (found == 2)
+			break;
+		else
+			mask = HWCAP_IBR;
+	}
+
+	if (type == WATCH_ACCESS && found == 1) {
+		breakinfo[watch].enabled = 0;
+		found = 0;
+	}
+
+	mb();
+	return found;
+}
+
+int kgdb_arch_set_hw_breakpoint(unsigned long addr, int len,
+				enum kgdb_bptype type)
+{
+	return hardware_breakpoint(addr, len, type - '1', 1);
+}
+
+int kgdb_arch_remove_hw_breakpoint(unsigned long addr, int len,
+				   enum kgdb_bptype type)
+{
+	return hardware_breakpoint(addr, len, type - '1', 0);
+}
+
+int kgdb_remove_hw_break(unsigned long addr)
+{
+	return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 0);
+
+}
+
+void kgdb_remove_all_hw_break(void)
+{
+	int i;
+
+	for (i = 0; i < HW_BREAKPOINT; i++)
+		memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
+}
+
+int kgdb_set_hw_break(unsigned long addr)
+{
+	return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 1);
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+	unsigned long hw_breakpoint_status;
+
+	hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+	if (hw_breakpoint_status & IA64_PSR_DB)
+		ia64_setreg(_IA64_REG_PSR_L,
+			    hw_breakpoint_status ^ IA64_PSR_DB);
+}
+
+volatile static struct smp_unw {
+	struct unw_frame_info *unw;
+	struct task_struct *task;
+} smp_unw[NR_CPUS];
+
+static int inline kgdb_get_blocked_state(struct task_struct *p,
+					 struct unw_frame_info *unw)
+{
+	unsigned long ip;
+	int count = 0;
+
+	unw_init_from_blocked_task(unw, p);
+	ip = 0UL;
+	do {
+		if (unw_unwind(unw) < 0)
+			return -1;
+		unw_get_ip(unw, &ip);
+		if (!in_sched_functions(ip))
+			break;
+	} while (count++ < 16);
+
+	if (!ip)
+		return -1;
+	else
+		return 0;
+}
+
+static void inline kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+	if (hw_breakpoint_status & IA64_PSR_DB)
+		ia64_setreg(_IA64_REG_PSR_L,
+			    hw_breakpoint_status ^ IA64_PSR_DB);
+	kgdb_nmihook(smp_processor_id(), regs);
+	if (hw_breakpoint_status & IA64_PSR_DB)
+		ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status);
+	return;
+}
+
+static void inline normalize(struct unw_frame_info *running,
+			     struct pt_regs *regs)
+{
+	unsigned long sp;
+
+	do {
+		unw_get_sp(running, &sp);
+		if ((sp + 0x10) >= (unsigned long)regs)
+			break;
+	} while (unw_unwind(running) >= 0);
+
+	return;
+}
+
+static void kgdb_init_running(struct unw_frame_info *unw, void *data)
+{
+	struct pt_regs *regs;
+
+	regs = data;
+	normalize(unw, regs);
+	smp_unw[smp_processor_id()].unw = unw;
+	kgdb_wait(regs);
+}
+
+void kgdb_wait_ipi(struct pt_regs *regs)
+{
+	struct unw_frame_info unw;
+
+	smp_unw[smp_processor_id()].task = current;
+
+	if (user_mode(regs)) {
+		smp_unw[smp_processor_id()].unw = (struct unw_frame_info *)1;
+		kgdb_wait(regs);
+	} else {
+		if (current->state == TASK_RUNNING)
+			unw_init_running(kgdb_init_running, regs);
+		else {
+			if (kgdb_get_blocked_state(current, &unw))
+				smp_unw[smp_processor_id()].unw =
+				    (struct unw_frame_info *)1;
+			else
+				smp_unw[smp_processor_id()].unw = &unw;
+			kgdb_wait(regs);
+		}
+	}
+
+	smp_unw[smp_processor_id()].unw = NULL;
+	return;
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	if (num_online_cpus() > 1)
+		smp_send_nmi_allbutself();
+}
+
+static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);
+
+struct kgdb_state {
+	int e_vector;
+	int signo;
+	unsigned long err_code;
+	struct pt_regs *regs;
+	struct unw_frame_info *unw;
+	char *inbuf;
+	char *outbuf;
+	int unwind;
+	int ret;
+};
+
+static void inline kgdb_pc(struct pt_regs *regs, unsigned long pc)
+{
+	regs->cr_iip = pc & ~0xf;
+	ia64_psr(regs)->ri = pc & 0x3;
+	return;
+}
+
+volatile int kgdb_hwbreak_sstep[NR_CPUS];
+
+int kgdb_arch_handle_exception(int e_vector, int signo,
+			       int err_code, char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	struct kgdb_state info;
+
+	info.e_vector = e_vector;
+	info.signo = signo;
+	info.err_code = err_code;
+	info.unw = (void *)0;
+	info.inbuf = remcom_in_buffer;
+	info.outbuf = remcom_out_buffer;
+	info.unwind = 0;
+	info.ret = -1;
+
+	if (remcom_in_buffer[0] == 'c' || remcom_in_buffer[0] == 's') {
+		info.regs = linux_regs;
+		do_kgdb_handle_exception(NULL, &info);
+	} else if (kgdb_usethread == current) {
+		info.regs = linux_regs;
+		/*
+		 * If we were invoked by init handler, then
+		 * the unwind must be handled as an interruption.
+		 */
+		if (e_vector == -1) {
+			struct unw_frame_info unw_info;
+
+			unw_init_from_interruption(&unw_info, current,
+						   linux_regs,
+						   (struct switch_stack *)
+						   (((char *)linux_regs) -
+						    sizeof(struct
+							   switch_stack)));
+			do_kgdb_handle_exception(&unw_info, &info);
+		} else {
+			info.unwind = 1;
+			unw_init_running(do_kgdb_handle_exception, &info);
+		}
+	} else if (kgdb_usethread->state != TASK_RUNNING) {
+		struct unw_frame_info unw_info;
+
+		if (kgdb_get_blocked_state(kgdb_usethread, &unw_info)) {
+			info.ret = 1;
+			goto bad;
+		}
+		info.regs = NULL;
+		do_kgdb_handle_exception(&unw_info, &info);
+	} else {
+		int i;
+
+		for (i = 0; i < NR_CPUS; i++)
+			if (smp_unw[i].task == kgdb_usethread && smp_unw[i].unw
+			    && smp_unw[i].unw != (struct unw_frame_info *)1) {
+				info.regs = NULL;
+				do_kgdb_handle_exception(smp_unw[i].unw, &info);
+				break;
+			} else {
+				info.ret = 1;
+				goto bad;
+			}
+	}
+
+      bad:
+	if (info.ret != -1 && remcom_in_buffer[0] == 'p') {
+		unsigned long bad = 0xbad4badbadbadbadUL;
+
+		printk("kgdb_arch_handle_exception: p packet bad (%s)\n",
+		       remcom_in_buffer);
+		kgdb_mem2hex((char *)&bad, remcom_out_buffer, sizeof(bad));
+		remcom_out_buffer[sizeof(bad) * 2] = 0;
+		info.ret = -1;
+	}
+	return info.ret;
+}
+
+static void do_kgdb_handle_exception(struct unw_frame_info *unw_info,
+				     void *data)
+{
+	long addr;
+	char *ptr;
+	unsigned long newPC;
+	int e_vector, signo;
+	unsigned long err_code;
+	struct pt_regs *linux_regs;
+	struct kgdb_state *info;
+	char *remcom_in_buffer, *remcom_out_buffer;
+
+	info = data;
+	info->unw = unw_info;
+	e_vector = info->e_vector;
+	signo = info->signo;
+	err_code = info->err_code;
+	remcom_in_buffer = info->inbuf;
+	remcom_out_buffer = info->outbuf;
+	linux_regs = info->regs;
+
+	if (info->unwind)
+		normalize(unw_info, linux_regs);
+
+	switch (remcom_in_buffer[0]) {
+	case 'p':
+		{
+			int regnum;
+
+			kgdb_hex2mem(&remcom_in_buffer[1], (char *)&regnum,
+				     sizeof(regnum));
+			if (regnum >= NUM_REGS) {
+				remcom_out_buffer[0] = 'E';
+				remcom_out_buffer[1] = 0;
+			} else
+				kgdb_get_reg(remcom_out_buffer, regnum,
+					     unw_info, linux_regs);
+			break;
+		}
+	case 'P':
+		{
+			int regno;
+			long v;
+			char *ptr;
+
+			ptr = &remcom_in_buffer[1];
+			if ((!kgdb_usethread || kgdb_usethread == current) &&
+			    kgdb_hex2long(&ptr, &v) &&
+			    *ptr++ == '=' && (v >= 0)) {
+				regno = (int)v;
+				regno = (regno >= NUM_REGS ? 0 : regno);
+				kgdb_put_reg(ptr, remcom_out_buffer, regno,
+					     unw_info, linux_regs);
+			} else
+				strcpy(remcom_out_buffer, "E01");
+			break;
+		}
+	case 'c':
+	case 's':
+		if (e_vector == 11 && err_code == KGDBBREAKNUM) {
+			if (ia64_psr(linux_regs)->ri < 2)
+				kgdb_pc(linux_regs, linux_regs->cr_iip +
+					ia64_psr(linux_regs)->ri + 1);
+			else
+				kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+		}
+
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->cr_iip = addr;
+		}
+		newPC = linux_regs->cr_iip;
+
+		/* clear the trace bit */
+		linux_regs->cr_ipsr &= ~IA64_PSR_SS;
+
+		atomic_set(&cpu_doing_single_step, -1);
+
+		/* set the trace bit if we're stepping or took a hardware break */
+		if (remcom_in_buffer[0] == 's' || e_vector == 29) {
+			linux_regs->cr_ipsr |= IA64_PSR_SS;
+			debugger_step = 1;
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+		}
+
+		kgdb_correct_hw_break();
+
+		/* if not hardware breakpoint, then reenable them */
+		if (e_vector != 29)
+			linux_regs->cr_ipsr |= IA64_PSR_DB;
+		else {
+			kgdb_hwbreak_sstep[smp_processor_id()] = 1;
+			linux_regs->cr_ipsr &= ~IA64_PSR_DB;
+		}
+
+		info->ret = 0;
+		break;
+	default:
+		break;
+	}
+
+	return;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	.set_breakpoint = kgdb_arch_set_breakpoint,
+	.remove_breakpoint = kgdb_arch_remove_breakpoint,
+	.set_hw_breakpoint = kgdb_arch_set_hw_breakpoint,
+	.remove_hw_breakpoint = kgdb_arch_remove_hw_breakpoint,
+	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
+};
diff -puN /dev/null arch/ia64/kernel/kgdb-jmp.S
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/kgdb-jmp.S	2005-08-08 12:18:23.000000000 -0700
@@ -0,0 +1,238 @@
+/* setjmp() and longjmp() assembler support for kdb on ia64.
+
+   This code was copied from glibc CVS as of 2001-06-27 and modified where
+   necessary to fit the kernel.
+   Keith Owens <kaos@melbourne.sgi.com> 2001-06-27
+ */
+
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <asm/asmmacro.h>
+GLOBAL_ENTRY(kgdb_fault_setjmp)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+	alloc loc1=ar.pfs,2,2,2,0
+	mov r16=ar.unat
+	;;
+	mov r17=ar.fpsr
+	mov r2=in0
+	add r3=8,in0
+	;;
+.mem.offset 0,0;
+	st8.spill.nta [r2]=sp,16	// r12 (sp)
+.mem.offset 8,0;
+	st8.spill.nta [r3]=gp,16	// r1 (gp)
+	;;
+	st8.nta [r2]=r16,16		// save caller's unat
+	st8.nta [r3]=r17,16		// save fpsr
+	add r8=0xa0,in0
+	;;
+.mem.offset 160,0;
+	st8.spill.nta [r2]=r4,16	// r4
+.mem.offset 168,0;
+	st8.spill.nta [r3]=r5,16	// r5
+	add r9=0xb0,in0
+	;;
+	stf.spill.nta [r8]=f2,32
+	stf.spill.nta [r9]=f3,32
+	mov loc0=rp
+	.body
+	;;
+	stf.spill.nta [r8]=f4,32
+	stf.spill.nta [r9]=f5,32
+	mov r17=b1
+	;;
+	stf.spill.nta [r8]=f16,32
+	stf.spill.nta [r9]=f17,32
+	mov r18=b2
+	;;
+	stf.spill.nta [r8]=f18,32
+	stf.spill.nta [r9]=f19,32
+	mov r19=b3
+	;;
+	stf.spill.nta [r8]=f20,32
+	stf.spill.nta [r9]=f21,32
+	mov r20=b4
+	;;
+	stf.spill.nta [r8]=f22,32
+	stf.spill.nta [r9]=f23,32
+	mov r21=b5
+	;;
+	stf.spill.nta [r8]=f24,32
+	stf.spill.nta [r9]=f25,32
+	mov r22=ar.lc
+	;;
+	stf.spill.nta [r8]=f26,32
+	stf.spill.nta [r9]=f27,32
+	mov r24=pr
+	;;
+	stf.spill.nta [r8]=f28,32
+	stf.spill.nta [r9]=f29,32
+	;;
+	stf.spill.nta [r8]=f30
+	stf.spill.nta [r9]=f31
+
+.mem.offset 0,0;
+	st8.spill.nta [r2]=r6,16	// r6
+.mem.offset 8,0;
+	st8.spill.nta [r3]=r7,16	// r7
+	;;
+	mov r23=ar.bsp
+	mov r25=ar.unat
+	st8.nta [r2]=loc0,16		// b0
+	st8.nta [r3]=r17,16		// b1
+	;;
+	st8.nta [r2]=r18,16		// b2
+	st8.nta [r3]=r19,16		// b3
+	;;
+	st8.nta [r2]=r20,16		// b4
+	st8.nta [r3]=r21,16		// b5
+	;;
+	st8.nta [r2]=loc1,16		// ar.pfs
+	st8.nta [r3]=r22,16		// ar.lc
+	;;
+	st8.nta [r2]=r24,16		// pr
+	st8.nta [r3]=r23,16		// ar.bsp
+	;;
+	st8.nta [r2]=r25		// ar.unat
+	st8.nta [r3]=in0		// &__jmp_buf
+	mov r8=0
+	mov rp=loc0
+	mov ar.pfs=loc1
+	br.ret.sptk.few rp
+END(kdba_setjmp)
+#define	pPos	p6	/* is rotate count positive? */
+#define	pNeg	p7	/* is rotate count negative? */
+GLOBAL_ENTRY(kgdb_fault_longjmp)
+	alloc r8=ar.pfs,2,1,0,0
+	mov r27=ar.rsc
+	add r2=0x98,in0		// r2 <- &jmpbuf.orig_jmp_buf_addr
+	;;
+	ld8 r8=[r2],-16		// r8 <- orig_jmp_buf_addr
+	mov r10=ar.bsp
+	and r11=~0x3,r27	// clear ar.rsc.mode
+	;;
+	flushrs			// flush dirty regs to backing store (must be first in insn grp)
+	ld8 r23=[r2],8		// r23 <- jmpbuf.ar_bsp
+	sub r8=r8,in0		// r8 <- &orig_jmpbuf - &jmpbuf
+	;;
+	ld8 r25=[r2]		// r25 <- jmpbuf.ar_unat
+	extr.u r8=r8,3,6	// r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
+	;;
+	cmp.lt pNeg,pPos=r8,r0
+	mov r2=in0
+	;;
+(pPos)	mov r16=r8
+(pNeg)	add r16=64,r8
+(pPos)	sub r17=64,r8
+(pNeg)	sub r17=r0,r8
+	;;
+	mov ar.rsc=r11		// put RSE in enforced lazy mode
+	shr.u r8=r25,r16
+	add r3=8,in0		// r3 <- &jmpbuf.r1
+	shl r9=r25,r17
+	;;
+	or r25=r8,r9
+	;;
+	mov r26=ar.rnat
+	mov ar.unat=r25		// setup ar.unat (NaT bits for r1, r4-r7, and r12)
+	;;
+	ld8.fill.nta sp=[r2],16	// r12 (sp)
+	ld8.fill.nta gp=[r3],16		// r1 (gp)
+	dep r11=-1,r23,3,6	// r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+	;;
+	ld8.nta r16=[r2],16		// caller's unat
+	ld8.nta r17=[r3],16		// fpsr
+	;;
+	ld8.fill.nta r4=[r2],16	// r4
+	ld8.fill.nta r5=[r3],16		// r5 (gp)
+	cmp.geu p8,p0=r10,r11	// p8 <- (ar.bsp >= jmpbuf.ar_bsp)
+	;;
+	ld8.fill.nta r6=[r2],16	// r6
+	ld8.fill.nta r7=[r3],16		// r7
+	;;
+	mov ar.unat=r16			// restore caller's unat
+	mov ar.fpsr=r17			// restore fpsr
+	;;
+	ld8.nta r16=[r2],16		// b0
+	ld8.nta r17=[r3],16		// b1
+	;;
+(p8)	ld8 r26=[r11]		// r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+	mov ar.bspstore=r23	// restore ar.bspstore
+	;;
+	ld8.nta r18=[r2],16		// b2
+	ld8.nta r19=[r3],16		// b3
+	;;
+	ld8.nta r20=[r2],16		// b4
+	ld8.nta r21=[r3],16		// b5
+	;;
+	ld8.nta r11=[r2],16		// ar.pfs
+	ld8.nta r22=[r3],56		// ar.lc
+	;;
+	ld8.nta r24=[r2],32		// pr
+	mov b0=r16
+	;;
+	ldf.fill.nta f2=[r2],32
+	ldf.fill.nta f3=[r3],32
+	mov b1=r17
+	;;
+	ldf.fill.nta f4=[r2],32
+	ldf.fill.nta f5=[r3],32
+	mov b2=r18
+	;;
+	ldf.fill.nta f16=[r2],32
+	ldf.fill.nta f17=[r3],32
+	mov b3=r19
+	;;
+	ldf.fill.nta f18=[r2],32
+	ldf.fill.nta f19=[r3],32
+	mov b4=r20
+	;;
+	ldf.fill.nta f20=[r2],32
+	ldf.fill.nta f21=[r3],32
+	mov b5=r21
+	;;
+	ldf.fill.nta f22=[r2],32
+	ldf.fill.nta f23=[r3],32
+	mov ar.lc=r22
+	;;
+	ldf.fill.nta f24=[r2],32
+	ldf.fill.nta f25=[r3],32
+	cmp.eq p8,p9=0,in1
+	;;
+	ldf.fill.nta f26=[r2],32
+	ldf.fill.nta f27=[r3],32
+	mov ar.pfs=r11
+	;;
+	ldf.fill.nta f28=[r2],32
+	ldf.fill.nta f29=[r3],32
+	;;
+	ldf.fill.nta f30=[r2]
+	ldf.fill.nta f31=[r3]
+(p8)	mov r8=1
+
+	mov ar.rnat=r26		// restore ar.rnat
+	;;
+	mov ar.rsc=r27		// restore ar.rsc
+(p9)	mov r8=in1
+
+	invala			// virt. -> phys. regnum mapping may change
+	mov pr=r24,-1
+	br.ret.sptk.few rp
+END(kgdb_fault_longjmp)
diff -puN arch/ia64/kernel/Makefile~ia64-lite arch/ia64/kernel/Makefile
--- linux-2.6.13/arch/ia64/kernel/Makefile~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/Makefile	2005-08-08 12:18:23.000000000 -0700
@@ -24,6 +24,7 @@ obj-$(CONFIG_IA64_MCA_RECOVERY)	+= mca_r
 obj-$(CONFIG_KPROBES)		+= kprobes.o jprobes.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+= uncached.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 
 # The gate DSO image is built using a special linker script.
 targets += gate.so gate-syms.o
diff -puN arch/ia64/kernel/mca.c~ia64-lite arch/ia64/kernel/mca.c
--- linux-2.6.13/arch/ia64/kernel/mca.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/mca.c	2005-08-08 12:18:23.000000000 -0700
@@ -472,9 +472,18 @@ static void
 init_handler_platform (pal_min_state_area_t *ms,
 		       struct pt_regs *pt, struct switch_stack *sw)
 {
+#ifndef	CONFIG_KGDB
 	struct unw_frame_info info;
+#endif
 
 	/* if a kernel debugger is available call it here else just dump the registers */
+#ifdef	CONFIG_KGDB
+	fetch_min_state(ms, pt, sw);
+	/*
+	 * switch_stack is at ((char *) pt) - sizeof (struct switch_stack)
+	 */
+	kgdb_handle_exception(-1, SIGTRAP, 0, pt);
+#else
 
 	/*
 	 * Wait for a bit.  On some machines (e.g., HP's zx2000 and zx6000, INIT can be
@@ -510,6 +519,7 @@ init_handler_platform (pal_min_state_are
 	if (!tasklist_lock.write_lock)
 		read_unlock(&tasklist_lock);
 #endif
+#endif
 
 	printk("\nINIT dump complete.  Please reboot now.\n");
 	while (1);			/* hang city if no debugger */
diff -puN arch/ia64/kernel/process.c~ia64-lite arch/ia64/kernel/process.c
--- linux-2.6.13/arch/ia64/kernel/process.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/process.c	2005-08-08 12:18:23.000000000 -0700
@@ -451,6 +451,9 @@ copy_thread (int nr, unsigned long clone
 	 */
 	child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
 				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+#ifdef	CONFIG_KGDB
+	child_ptregs->cr_ipsr |= IA64_PSR_DB;
+#endif
 
 	/*
 	 * NOTE: The calling convention considers all floating point
@@ -679,6 +682,9 @@ kernel_thread (int (*fn)(void *), void *
 	regs.pt.r11 = (unsigned long) arg;	/* 2nd argument */
 	/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read.  */
 	regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+#ifdef	CONFIG_KGDB
+	regs.pt.cr_ipsr |= IA64_PSR_DB;
+#endif
 	regs.pt.cr_ifs = 1UL << 63;		/* mark as valid, empty frame */
 	regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
 	regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
diff -puN arch/ia64/kernel/smp.c~ia64-lite arch/ia64/kernel/smp.c
--- linux-2.6.13/arch/ia64/kernel/smp.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/smp.c	2005-08-08 12:18:23.000000000 -0700
@@ -47,6 +47,7 @@
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <linux/kgdb.h>
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
@@ -66,6 +67,9 @@ static volatile struct call_data_struct 
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
+#ifdef	CONFIG_KGDB
+#define	IPI_KGDB_INTERRUPT	2
+#endif
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
 static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -155,6 +159,11 @@ handle_IPI (int irq, void *dev_id, struc
 			      case IPI_CPU_STOP:
 				stop_this_cpu();
 				break;
+#ifdef	CONFIG_KGDB
+			      case IPI_KGDB_INTERRUPT:
+				kgdb_wait_ipi(regs);
+				break;
+#endif
 
 			      default:
 				printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
@@ -305,6 +314,14 @@ smp_call_function_single (int cpuid, voi
 }
 EXPORT_SYMBOL(smp_call_function_single);
 
+#ifdef	CONFIG_KGDB
+void
+smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(IPI_KGDB_INTERRUPT);
+}
+#endif
+
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
diff -puN arch/ia64/kernel/traps.c~ia64-lite arch/ia64/kernel/traps.c
--- linux-2.6.13/arch/ia64/kernel/traps.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/traps.c	2005-08-08 12:18:23.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/module.h>       /* for EXPORT_SYMBOL */
 #include <linux/hardirq.h>
+#include <linux/kgdb.h>
 
 #include <asm/fpswa.h>
 #include <asm/ia32.h>
@@ -108,6 +109,10 @@ die (const char *str, struct pt_regs *re
   	} else
 		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
 
+#ifdef CONFIG_KGDB
+	kgdb_handle_exception(1, SIGTRAP, err, regs);
+#endif
+
 	bust_spinlocks(0);
 	die.lock_owner = -1;
 	spin_unlock_irq(&die.lock);
@@ -157,7 +162,9 @@ ia64_bad_break (unsigned long break_num,
 			       	== NOTIFY_STOP) {
 			return;
 		}
+#ifndef	CONFIG_KGDB
 		die_if_kernel("bugcheck!", regs, break_num);
+#endif
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
@@ -219,8 +226,10 @@ ia64_bad_break (unsigned long break_num,
 		break;
 
 	      default:
+#ifndef	CONFIG_KGDB
 		if (break_num < 0x40000 || break_num > 0x100000)
 			die_if_kernel("Bad break", regs, break_num);
+#endif
 
 		if (break_num < 0x80000) {
 			sig = SIGILL; code = __ILL_BREAK;
@@ -228,6 +237,15 @@ ia64_bad_break (unsigned long break_num,
 			sig = SIGTRAP; code = TRAP_BRKPT;
 		}
 	}
+#ifdef	CONFIG_KGDB
+	/*
+	 * We don't want to trap simulator system calls.
+	 */
+	if (break_num != 0x80001) {
+		kgdb_handle_exception(11, sig, break_num, regs);
+		return;
+	}
+#endif
 	siginfo.si_signo = sig;
 	siginfo.si_errno = 0;
 	siginfo.si_code = code;
@@ -543,10 +561,21 @@ ia64_fault (unsigned long vector, unsign
 		}
 		sprintf(buf, "Unsupported data reference");
 		break;
-
 	      case 29: /* Debug */
-	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
+#ifdef CONFIG_KGDB
+		if (vector == 36 && !user_mode(&regs) &&
+			kgdb_hwbreak_sstep[smp_processor_id()]) {
+			kgdb_hwbreak_sstep[smp_processor_id()] = 0;
+			regs.cr_ipsr &= ~IA64_PSR_SS;
+			return;
+		} else if (!user_mode(&regs)) {
+			kgdb_handle_exception(vector, SIGTRAP, isr, &regs);
+			return;
+		}
+#endif
+		/* Fall */
+	      case 35: /* Taken Branch Trap */
 		if (fsys_mode(current, &regs)) {
 			extern char __kernel_syscall_via_break[];
 			/*
@@ -664,6 +693,9 @@ ia64_fault (unsigned long vector, unsign
 		sprintf(buf, "Fault %lu", vector);
 		break;
 	}
+#ifdef CONFIG_KGDB
+	kgdb_handle_exception(vector, SIGTRAP, isr, &regs);
+#endif
 	die_if_kernel(buf, &regs, error);
 	force_sig(SIGILL, current);
 }
diff -puN arch/ia64/kernel/unwind.c~ia64-lite arch/ia64/kernel/unwind.c
--- linux-2.6.13/arch/ia64/kernel/unwind.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/kernel/unwind.c	2005-08-08 12:18:23.000000000 -0700
@@ -72,10 +72,68 @@
 # define STAT(x...)
 #endif
 
+#ifdef	CONFIG_KGDB
+#define	KGDB_EARLY_SIZE	100
+static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE];
+static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE];
+void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free;
+
+static void __init
+kgdb_malloc_init(void)
+{
+	int i;
+
+	kgdb_reg_state_free = kgdb_reg_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free;
+		kgdb_reg_state_free = &kgdb_reg_state[i];
+	}
+
+	kgdb_labeled_state_free = kgdb_labeled_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_labeled_state[i]) =
+			(unsigned long) kgdb_labeled_state_free;
+		kgdb_labeled_state_free = &kgdb_labeled_state[i];
+	}
+
+}
+
+static void * __init
+kgdb_malloc(void **mem)
+{
+	void *p;
+
+	p = *mem;
+	*mem = *((void **) p);
+	return p;
+}
+
+static void __init
+kgdb_free(void **mem, void *p)
+{
+	*((void **)p) = *mem;
+	*mem = p;
+}
+
+#define alloc_reg_state()	(!malloc_sizes[0].cs_cachep ? 		\
+		kgdb_malloc(&kgdb_reg_state_free) : 			\
+		kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC))
+#define free_reg_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_reg_state_free, usr) :			\
+		kfree(usr))
+#define alloc_labeled_state()	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_malloc(&kgdb_labeled_state_free) :			\
+		kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC))
+#define free_labeled_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_labeled_state_free, usr) :		\
+		kfree(usr))
+
+#else
 #define alloc_reg_state()	kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)
 #define free_reg_state(usr)	kfree(usr)
 #define alloc_labeled_state()	kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)
 #define free_labeled_state(usr)	kfree(usr)
+#endif
 
 typedef unsigned long unw_word;
 typedef unsigned char unw_hash_index_t;
@@ -238,6 +296,24 @@ static struct {
 #endif
 };
 
+#ifdef	CONFIG_KGDB
+/*
+ * This makes it safe to call breakpoint() very early
+ * in setup_arch providing:
+ *	1) breakpoint isn't called between lines in cpu_init
+ *	   where init_mm.mm_count is incremented and ia64_mmu_init
+ *	   is called.  Otherwise the test below is invalid.
+ *	2) the memory examined doesn't result in tlbmiss.
+ */
+static unsigned long inline kgdb_unimpl_va_mask(void)
+{
+	if (atomic_read(&init_mm.mm_count) > 1)
+		return local_cpu_data->unimpl_va_mask;
+	else
+		return 0UL;
+}
+#endif
+
 static inline int
 read_only (void *addr)
 {
@@ -1786,7 +1862,11 @@ run_script (struct unw_script *script, s
 
 		      case UNW_INSN_LOAD:
 #ifdef UNW_DEBUG
+#ifdef	CONFIG_KGDB
+			if ((s[val] & (kgdb_unimpl_va_mask() | 0x7)) != 0
+#else
 			if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0
+#endif
 			    || s[val] < TASK_SIZE)
 			{
 				UNW_DPRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n",
@@ -1821,7 +1901,11 @@ find_save_locs (struct unw_frame_info *i
 	struct unw_script *scr;
 	unsigned long flags = 0;
 
+#ifdef	CONFIG_KGDB
+	if ((info->ip & (kgdb_unimpl_va_mask() | 0xf)) || info->ip < TASK_SIZE) {
+#else
 	if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
+#endif
 		/* don't let obviously bad addresses pollute the cache */
 		/* FIXME: should really be level 0 but it occurs too often. KAO */
 		UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip);
@@ -2271,6 +2355,9 @@ unw_init (void)
 
 	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp,
 			  __start_unwind, __end_unwind);
+#ifdef	CONFIG_KGDB
+	kgdb_malloc_init();
+#endif
 }
 
 /*
diff -puN arch/ia64/mm/extable.c~ia64-lite arch/ia64/mm/extable.c
--- linux-2.6.13/arch/ia64/mm/extable.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/mm/extable.c	2005-08-08 12:18:23.000000000 -0700
@@ -7,6 +7,7 @@
 
 #include <linux/config.h>
 #include <linux/sort.h>
+#include <linux/kgdb.h>
 
 #include <asm/uaccess.h>
 #include <asm/module.h>
@@ -74,6 +75,11 @@ search_extable (const struct exception_t
                 else
                         last = mid - 1;
         }
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+#endif
         return NULL;
 }
 
diff -puN arch/ia64/mm/fault.c~ia64-lite arch/ia64/mm/fault.c
--- linux-2.6.13/arch/ia64/mm/fault.c~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/arch/ia64/mm/fault.c	2005-08-08 12:18:23.000000000 -0700
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/kgdb.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -248,6 +249,10 @@ ia64_do_page_fault (unsigned long addres
 	 */
 	bust_spinlocks(1);
 
+#ifdef CONFIG_KGDB
+	kgdb_handle_exception(14, SIGSEGV, isr, regs);
+#endif
+
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address);
 	else
diff -puN /dev/null include/asm-ia64/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-ia64/kgdb.h	2005-08-08 12:18:23.000000000 -0700
@@ -0,0 +1,37 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/threads.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
+
+/* Number of bytes of registers.  We set this to 0 so that certain GDB
+ * packets will fail, forcing the use of others, which are more friendly
+ * on ia64. */
+#define NUMREGBYTES		0
+
+#define NUMCRITREGBYTES		(70*8)
+#define JMP_REGS_ALIGNMENT	__attribute__ ((aligned (16)))
+
+#define BREAKNUM		0x00003333300LL
+#define KGDBBREAKNUM		0x6665UL
+#define BREAKPOINT()		asm volatile ("break.m 0x6665")
+#define BREAK_INSTR_SIZE	16
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
+
+struct pt_regs;
+extern volatile int kgdb_hwbreak_sstep[NR_CPUS];
+extern void smp_send_nmi_allbutself(void);
+extern void kgdb_wait_ipi(struct pt_regs *);
+#endif				/* _ASM_KGDB_H_ */
+#endif				/* __KERNEL__ */
diff -puN lib/Kconfig.debug~ia64-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~ia64-lite	2005-08-08 12:18:23.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-10 10:54:53.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || MIPS32 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (X86 || MIPS32 || IA64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
_

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

* [patch 07/16] x86_64: Rename KDB_VECTOR to DEBUGGER_VECTOR
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (4 preceding siblings ...)
  2005-08-29 16:10   ` [patch 06/16] Add support for IA64 " Tom Rini
@ 2005-08-29 16:10   ` Tom Rini
  2005-08-29 16:10   ` [patch 08/16] Add support for X86_64 platforms to KGDB Tom Rini
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:10 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, ak, kaos


CC: Andi Kleen <ak@suse.de>, Keith Owens <kaos@sgi.com>
The existing hook from KDB in the IPI code is really just a hook for the
NMI vector.  We rename the vector thusly and then it's up to the
debugger to handle things from do_default_nmi().

---

 linux-2.6.13-trini/arch/x86_64/kernel/i8259.c  |    3 +--
 linux-2.6.13-trini/arch/x86_64/kernel/smp.c    |    2 +-
 linux-2.6.13-trini/arch/x86_64/kernel/traps.c  |    2 +-
 linux-2.6.13-trini/include/asm-x86_64/hw_irq.h |    2 +-
 linux-2.6.13-trini/include/asm-x86_64/ipi.h    |    2 +-
 5 files changed, 5 insertions(+), 6 deletions(-)

diff -puN arch/x86_64/kernel/i8259.c~x86_64-rename_kdb_vector arch/x86_64/kernel/i8259.c
--- linux-2.6.13/arch/x86_64/kernel/i8259.c~x86_64-rename_kdb_vector	2005-08-10 10:54:58.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/i8259.c	2005-08-10 10:54:58.000000000 -0700
@@ -544,10 +544,9 @@ void __init init_IRQ(void)
 		int vector = FIRST_EXTERNAL_VECTOR + i;
 		if (i >= NR_IRQS)
 			break;
-		if (vector != IA32_SYSCALL_VECTOR && vector != KDB_VECTOR) { 
+		if (vector != IA32_SYSCALL_VECTOR && vector != NMI_VECTOR)
 			set_intr_gate(vector, interrupt[i]);
 	}
-	}
 
 #ifdef CONFIG_SMP
 	/*
diff -puN arch/x86_64/kernel/smp.c~x86_64-rename_kdb_vector arch/x86_64/kernel/smp.c
--- linux-2.6.13/arch/x86_64/kernel/smp.c~x86_64-rename_kdb_vector	2005-08-10 10:54:58.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/smp.c	2005-08-10 10:54:58.000000000 -0700
@@ -252,7 +252,7 @@ void flush_tlb_all(void)
 
 void smp_kdb_stop(void)
 {
-	send_IPI_allbutself(KDB_VECTOR);
+	send_IPI_allbutself(NMI_VECTOR);
 }
 
 /*
diff -puN arch/x86_64/kernel/traps.c~x86_64-rename_kdb_vector arch/x86_64/kernel/traps.c
--- linux-2.6.13/arch/x86_64/kernel/traps.c~x86_64-rename_kdb_vector	2005-08-10 10:54:58.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/traps.c	2005-08-10 10:54:58.000000000 -0700
@@ -931,7 +931,7 @@ void __init trap_init(void)
 	set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
        
-	set_intr_gate(KDB_VECTOR, call_debug);
+	set_intr_gate(NMI_VECTOR, call_debug);
        
 	/*
 	 * Should be a barrier for any external CPU state.
diff -puN include/asm-x86_64/hw_irq.h~x86_64-rename_kdb_vector include/asm-x86_64/hw_irq.h
--- linux-2.6.13/include/asm-x86_64/hw_irq.h~x86_64-rename_kdb_vector	2005-08-10 10:54:58.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/hw_irq.h	2005-08-10 10:54:58.000000000 -0700
@@ -54,7 +54,7 @@ struct hw_interrupt_type;
 #define RESCHEDULE_VECTOR	0xfc
 #define TASK_MIGRATION_VECTOR	0xfb
 #define CALL_FUNCTION_VECTOR	0xfa
-#define KDB_VECTOR	0xf9
+#define NMI_VECTOR	0xf9
 
 #define THERMAL_APIC_VECTOR	0xf0
 
diff -puN include/asm-x86_64/ipi.h~x86_64-rename_kdb_vector include/asm-x86_64/ipi.h
--- linux-2.6.13/include/asm-x86_64/ipi.h~x86_64-rename_kdb_vector	2005-08-10 10:54:58.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/ipi.h	2005-08-10 10:54:58.000000000 -0700
@@ -32,7 +32,7 @@
 static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest)
 {
 	unsigned int icr =  APIC_DM_FIXED | shortcut | vector | dest;
-	if (vector == KDB_VECTOR)
+	if (vector == NMI_VECTOR)
 		icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI;
 	return icr;
 }
_

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

* [patch 08/16] Add support for X86_64 platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (5 preceding siblings ...)
  2005-08-29 16:10   ` [patch 07/16] x86_64: Rename KDB_VECTOR to DEBUGGER_VECTOR Tom Rini
@ 2005-08-29 16:10   ` Tom Rini
  2005-08-29 17:13     ` Andi Kleen
  2005-08-29 16:10   ` [patch 09/16] Add support for SuperH " Tom Rini
                     ` (7 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:10 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, ak, amitkale


This adds support for the x86_64 architecture.  In addition to what was noted
in the core-lite patch about stuff outside of new files, we add -g0 to
compiling of syscalls.o as otherwise we run into problems when debugging
modules, and like i386 annotate switch_to().

---

 linux-2.6.13-trini/arch/x86_64/Kconfig.debug     |    3 
 linux-2.6.13-trini/arch/x86_64/kernel/Makefile   |    2 
 linux-2.6.13-trini/arch/x86_64/kernel/kgdb-jmp.S |   65 ++
 linux-2.6.13-trini/arch/x86_64/kernel/kgdb.c     |  460 +++++++++++++++++++
 linux-2.6.13-trini/arch/x86_64/kernel/setup.c    |    3 
 linux-2.6.13-trini/arch/x86_64/kernel/setup64.c  |   14 
 linux-2.6.13-trini/arch/x86_64/kernel/traps.c    |   24 
 linux-2.6.13-trini/arch/x86_64/mm/fault.c        |    4 
 linux-2.6.13-trini/include/asm-x86_64/kgdb.h     |   50 ++
 linux-2.6.13-trini/include/asm-x86_64/proto.h    |    2 
 linux-2.6.13-trini/include/asm-x86_64/system.h   |    6 
 linux-2.6.13-trini/lib/Kconfig.debug             |    2 
 12 files changed, 617 insertions(+), 18 deletions(-)

diff -puN arch/x86_64/Kconfig.debug~x86_64-lite arch/x86_64/Kconfig.debug
--- linux-2.6.13/arch/x86_64/Kconfig.debug~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/Kconfig.debug	2005-08-10 16:27:31.000000000 -0700
@@ -51,7 +51,4 @@ config IOMMU_LEAK
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
 
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
-
 endmenu
diff -puN /dev/null arch/x86_64/kernel/kgdb.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/kgdb.c	2005-08-12 08:28:29.000000000 -0700
@@ -0,0 +1,460 @@
+/*
+ *
+ * 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.
+ */
+/****************************************************************************
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.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 <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <asm/apicdef.h>
+#include <asm/mach_apic.h>
+#include <asm/kdebug.h>
+#include <asm/debugreg.h>
+
+/* Put the error code here just in case the user cares.  */
+int gdb_x86_64errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+int gdb_x86_64vector = -1;
+
+extern atomic_t cpu_doing_single_step;
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_RAX] = regs->rax;
+	gdb_regs[_RBX] = regs->rbx;
+	gdb_regs[_RCX] = regs->rcx;
+	gdb_regs[_RDX] = regs->rdx;
+	gdb_regs[_RSI] = regs->rsi;
+	gdb_regs[_RDI] = regs->rdi;
+	gdb_regs[_RBP] = regs->rbp;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_PC] = regs->rip;
+	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[_RSP] = regs->rsp;
+}
+
+extern void thread_return(void);
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	gdb_regs[_RAX] = 0;
+	gdb_regs[_RBX] = 0;
+	gdb_regs[_RCX] = 0;
+	gdb_regs[_RDX] = 0;
+	gdb_regs[_RSI] = 0;
+	gdb_regs[_RDI] = 0;
+	gdb_regs[_RBP] = *(unsigned long *)p->thread.rsp;
+	gdb_regs[_PS] = *(unsigned long *)(p->thread.rsp + 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;
+	gdb_regs[_RSP] = p->thread.rsp;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->rax = gdb_regs[_RAX];
+	regs->rbx = gdb_regs[_RBX];
+	regs->rcx = gdb_regs[_RCX];
+	regs->rdx = gdb_regs[_RDX];
+	regs->rsi = gdb_regs[_RSI];
+	regs->rdi = gdb_regs[_RDI];
+	regs->rbp = gdb_regs[_RBP];
+	regs->eflags = gdb_regs[_PS];
+	regs->rip = gdb_regs[_PC];
+	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];
+#if 0				/* can't change these */
+	regs->rsp = gdb_regs[_RSP];
+	regs->ss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = { {
+enabled:0}, {
+enabled:0}, {
+enabled:0}, {
+enabled:0}};
+
+void kgdb_correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned long dr7;
+
+	asm volatile ("movq %%db7, %0\n":"=r" (dr7):);
+	do {
+		unsigned long addr0, addr1, addr2, addr3;
+		asm volatile ("movq %%db0, %0\n"
+			      "movq %%db1, %1\n"
+			      "movq %%db2, %2\n"
+			      "movq %%db3, %3\n":"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3):);
+	} while (0);
+	correctit = 0;
+	for (breakno = 0; breakno < 3; 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) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movq %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movq %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movq %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movq %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movq %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int kgdb_remove_hw_break(unsigned long addr)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 0;
+	return 0;
+}
+
+int kgdb_set_hw_break(unsigned long addr)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (!breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 1;
+	breakinfo[idx].type = 1;
+	breakinfo[idx].len = 1;
+	breakinfo[idx].addr = addr;
+	return 0;
+}
+
+int remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+	/* Disable hardware debugging while we are in kgdb */
+	asm volatile ("movq %0,%%db7": /* no output */ :"r" (0UL));
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_x86_64vector = e_vector;
+	gdb_x86_64errcode = err_code;
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+
+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, length;
+	unsigned long breakno, breaktype;
+	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->rip = addr;
+		newPC = linux_regs->rip;
+
+		/* clear the trace bit */
+		linux_regs->eflags &= ~TF_MASK;
+
+		atomic_set(&cpu_doing_single_step, -1);
+		/* set the trace bit if we're stepping */
+		if (remcomInBuffer[0] == 's') {
+			linux_regs->eflags |= TF_MASK;
+			debugger_step = 1;
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+
+		}
+
+		asm volatile ("movq %%db6, %0\n":"=r" (dr6));
+		if (!(dr6 & 0x4000)) {
+			for (breakno = 0; breakno < 4; ++breakno) {
+				if (dr6 & (1 << breakno)) {
+					if (breakinfo[breakno].type == 0) {
+						/* Set restore flag */
+						linux_regs->eflags |=
+						    X86_EFLAGS_RF;
+						break;
+					}
+				}
+			}
+		}
+		kgdb_correct_hw_break();
+		asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+
+		return (0);
+
+	case 'Y':
+		ptr = &remcomInBuffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		ptr++;
+		kgdb_hex2long(&ptr, &breaktype);
+		ptr++;
+		kgdb_hex2long(&ptr, &length);
+		ptr++;
+		kgdb_hex2long(&ptr, &addr);
+		if (set_hw_break(breakno & 0x3, breaktype & 0x3,
+				 length & 0x3, addr) == 0)
+			strcpy(remcomOutBuffer, "OK");
+		else
+			strcpy(remcomOutBuffer, "ERROR");
+		break;
+
+		/* Remove hardware breakpoint */
+	case 'y':
+		ptr = &remcomInBuffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		if (remove_hw_break(breakno & 0x3) == 0)
+			strcpy(remcomOutBuffer, "OK");
+		else
+			strcpy(remcomOutBuffer, "ERROR");
+		break;
+
+	}			/* switch */
+	return -1;
+}
+
+static struct pt_regs *in_interrupt_stack(unsigned long rsp, int cpu)
+{
+	struct pt_regs *regs;
+	unsigned long end = (unsigned long)cpu_pda[cpu].irqstackptr;
+	if (rsp <= end && rsp >= end - IRQSTACKSIZE + 8) {
+		regs = *(((struct pt_regs **)end) - 1);
+		return regs;
+	}
+	return NULL;
+}
+
+static struct pt_regs *in_exception_stack(unsigned long rsp, int cpu)
+{
+	int i;
+	struct tss_struct *init_tss = &__get_cpu_var(init_tss);
+	for (i = 0; i < N_EXCEPTION_STACKS; i++)
+		if (rsp >= init_tss[cpu].ist[i] &&
+		    rsp <= init_tss[cpu].ist[i] + EXCEPTION_STKSZ) {
+			struct pt_regs *r =
+			    (void *)init_tss[cpu].ist[i] + EXCEPTION_STKSZ;
+			return r - 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 = hard_smp_processor_id();
+
+	if ((stregs = in_interrupt_stack(regs->rsp, cpu)))
+		kgdb_mem2hex(intr_desc, buffer, strlen(intr_desc));
+	else if ((stregs = in_exception_stack(regs->rsp, cpu)))
+		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 = hard_smp_processor_id();
+
+	if ((stregs = in_interrupt_stack(regs->rsp, cpu)))
+		return current;
+	else if ((stregs = in_exception_stack(regs->rsp, cpu)))
+		return current;
+
+	return NULL;
+}
+
+struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	struct pt_regs *stregs;
+	int cpu = hard_smp_processor_id();
+
+	if ((stregs = in_interrupt_stack(regs->rsp, cpu)))
+		return stregs;
+	else if ((stregs = in_exception_stack(regs->rsp, cpu)))
+		return stregs;
+
+	return NULL;
+}
+
+/* Register KGDB with the die_chain so that we hook into all of the right
+ * spots. */
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd,
+		       void *ptr)
+{
+	struct die_args *args = ptr;
+	struct pt_regs *regs = args->regs;
+
+	if (cmd == DIE_PAGE_FAULT && strcmp(args->str, "no context") == 0 &&
+	    atomic_read(&debugger_active) && kgdb_may_fault) {
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		return NOTIFY_STOP;
+	/* CPU roundup? */
+	} else if (atomic_read(&debugger_active) && cmd == DIE_NMI_IPI) {
+		kgdb_nmihook(smp_processor_id(), regs);
+		return NOTIFY_STOP;
+		/* See if KGDB is interested. */
+	} else if (cmd == DIE_PAGE_FAULT || user_mode(regs) ||
+		   cmd == DIE_NMI_IPI || (cmd == DIE_DEBUG &&
+					  atomic_read(&debugger_active)))
+		/* Userpace events, normal watchdog event, or spurious
+		 * debug exception.  Ignore. */
+		return NOTIFY_DONE;
+
+	kgdb_handle_exception(args->trapnr, args->signr, args->err, regs);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0x7fffffff,	/* we need to notified first */
+};
+
+int kgdb_arch_init(void)
+{
+	notifier_chain_register(&die_chain, &kgdb_notifier);
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
+	.shadowth = 1,
+};
diff -puN /dev/null arch/x86_64/kernel/kgdb-jmp.S
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/kgdb-jmp.S	2005-08-10 16:27:31.000000000 -0700
@@ -0,0 +1,65 @@
+/*
+ * arch/x86_64/kernel/kgdb-jmp.S
+ *
+ * Save and restore system registers so that within a limited frame we
+ * may have a fault and "jump back" to a known safe location.
+ *
+ * Author: Tom Rini <trini@kernel.crashing.org>
+ *
+ * Cribbed from glibc, which carries the following:
+ * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2005 by MontaVista Software.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <linux/linkage.h>
+
+#define JB_RBX		0
+#define JB_RBP		1
+#define JB_R12		2
+#define JB_R13		3
+#define JB_R14		4
+#define JB_R15		5
+#define JB_RSP		6
+#define JB_PC		7
+
+	.code64
+
+/* This must be called prior to kgdb_fault_longjmp and
+ * kgdb_fault_longjmp must not be called outside of the context of the
+ * last call to kgdb_fault_setjmp.
+ */
+ENTRY(kgdb_fault_setjmp)
+	/* Save registers. */
+	movq %rbx, (JB_RBX*8)(%rdi)
+	movq %rbp, (JB_RBP*8)(%rdi)
+	movq %r12, (JB_R12*8)(%rdi)
+	movq %r13, (JB_R13*8)(%rdi)
+	movq %r14, (JB_R14*8)(%rdi)
+	movq %r15, (JB_R15*8)(%rdi)
+	leaq 8(%rsp), %rdx	/* Save SP as it will be after we return. */
+	movq %rdx, (JB_RSP*8)(%rdi)
+	movq (%rsp), %rax	/* Save PC we are returning to now. */
+	movq %rax, (JB_PC*8)(%rdi)
+	/* Set return value for setjmp. */
+	mov $0,%eax
+	movq (JB_PC*8)(%rdi),%rdx
+	movq (JB_RSP*8)(%rdi),%rsp
+	jmpq *%rdx
+
+ENTRY(kgdb_fault_longjmp)
+	/* Restore registers. */
+	movq (JB_RBX*8)(%rdi),%rbx
+	movq (JB_RBP*8)(%rdi),%rbp
+	movq (JB_R12*8)(%rdi),%r12
+	movq (JB_R13*8)(%rdi),%r13
+	movq (JB_R14*8)(%rdi),%r14
+	movq (JB_R15*8)(%rdi),%r15
+	/* Set return value for setjmp. */
+	movq (JB_PC*8)(%rdi),%rdx
+	movq (JB_RSP*8)(%rdi),%rsp
+	mov $1,%eax
+	jmpq *%rdx
diff -puN arch/x86_64/kernel/Makefile~x86_64-lite arch/x86_64/kernel/Makefile
--- linux-2.6.13/arch/x86_64/kernel/Makefile~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/Makefile	2005-08-10 16:27:31.000000000 -0700
@@ -4,6 +4,7 @@
 
 extra-y 	:= head.o head64.o init_task.o vmlinux.lds
 EXTRA_AFLAGS	:= -traditional
+CFLAGS_vsyscall.o := -g0
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o \
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
@@ -29,6 +30,7 @@ obj-$(CONFIG_GART_IOMMU)	+= pci-gart.o a
 obj-$(CONFIG_DUMMY_IOMMU)	+= pci-nommu.o pci-dma.o
 obj-$(CONFIG_SWIOTLB)		+= swiotlb.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer.o
 
 obj-$(CONFIG_MODULES)		+= module.o
diff -puN arch/x86_64/kernel/traps.c~x86_64-lite arch/x86_64/kernel/traps.c
--- linux-2.6.13/arch/x86_64/kernel/traps.c~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/traps.c	2005-08-10 16:27:31.000000000 -0700
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/nmi.h>
+#include <linux/kgdb.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -902,12 +903,21 @@ void do_call_debug(struct pt_regs *regs)
 	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); 
 }
 
-void __init trap_init(void)
+void __init early_trap_init(void)
 {
-	set_intr_gate(0,&divide_error);
 	set_intr_gate_ist(1,&debug,DEBUG_STACK);
 	set_intr_gate_ist(2,&nmi,NMI_STACK);
 	set_system_gate(3,&int3);
+	set_intr_gate(13,&general_protection);
+	set_intr_gate(14,&page_fault);
+	set_intr_gate(11,&segment_not_present);
+	set_intr_gate(NMI_VECTOR, call_debug);
+	cpu_init();
+}
+
+void __init trap_init(void)
+{
+	set_intr_gate(0,&divide_error);
 	set_system_gate(4,&overflow);	/* int4-5 can be called from all */
 	set_system_gate(5,&bounds);
 	set_intr_gate(6,&invalid_op);
@@ -915,10 +925,7 @@ void __init trap_init(void)
 	set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
 	set_intr_gate(9,&coprocessor_segment_overrun);
 	set_intr_gate(10,&invalid_TSS);
-	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);
@@ -930,13 +937,6 @@ void __init trap_init(void)
 #ifdef CONFIG_IA32_EMULATION
 	set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
-       
-	set_intr_gate(NMI_VECTOR, call_debug);
-       
-	/*
-	 * Should be a barrier for any external CPU state.
-	 */
-	cpu_init();
 }
 
 
diff -puN include/asm-x86_64/hw_irq.h~x86_64-lite include/asm-x86_64/hw_irq.h
diff -puN include/asm-x86_64/ipi.h~x86_64-lite include/asm-x86_64/ipi.h
diff -puN /dev/null include/asm-x86_64/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/kgdb.h	2005-08-12 08:26:09.000000000 -0700
@@ -0,0 +1,50 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+/*
+ *  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.
+ */
+#define _RAX	0
+#define _RDX	1
+#define _RCX	2
+#define _RBX	3
+#define _RSI	4
+#define _RDI	5
+#define _RBP	6
+#define _RSP	7
+#define _R8	8
+#define _R9	9
+#define _R10	10
+#define _R11	11
+#define _R12	12
+#define _R13	13
+#define _R14	14
+#define _R15	15
+#define _PC	16
+#define _PS	17
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES		((_PS+1)*8)
+#define NUMCRITREGBYTES		(8 * 8)		/* 8 registers. */
+
+#ifndef __ASSEMBLY__
+/* BUFMAX defines the maximum number of characters in inbound/outbound
+ * buffers at least NUMREGBYTES*2 are needed for register packets, and
+ * a longer buffer is needed to list all threads. */
+#define BUFMAX			1024
+#define BREAKPOINT()		asm("   int $3");
+#define BREAK_INSTR_SIZE	1
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
+#endif				/* !__ASSEMBLY__ */
+#endif				/* _ASM_KGDB_H_ */
+#endif				/* __KERNEL__ */
diff -puN include/asm-x86_64/system.h~x86_64-lite include/asm-x86_64/system.h
--- linux-2.6.13/include/asm-x86_64/system.h~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/system.h	2005-08-10 16:27:31.000000000 -0700
@@ -27,7 +27,9 @@
 	,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15"
 
 #define switch_to(prev,next,last) \
-	asm volatile(SAVE_CONTEXT						    \
+       asm volatile(".globl __switch_to_begin\n\t"				    \
+		     "__switch_to_begin:\n\t"					  \
+		     SAVE_CONTEXT						  \
 		     "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */	  \
 		     "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */	  \
 		     "call __switch_to\n\t"					  \
@@ -39,6 +41,8 @@
 		     "movq %%rax,%%rdi\n\t" 					  \
 		     "jc   ret_from_fork\n\t"					  \
 		     RESTORE_CONTEXT						    \
+		     ".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.rsp)), \
diff -puN lib/Kconfig.debug~x86_64-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-12 08:27:47.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || MIPS32 || IA64 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (X86 || MIPS32 || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
diff -puN arch/x86_64/kernel/setup.c~x86_64-lite arch/x86_64/kernel/setup.c
--- linux-2.6.13/arch/x86_64/kernel/setup.c~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/setup.c	2005-08-10 16:27:31.000000000 -0700
@@ -525,6 +525,9 @@ void __init setup_arch(char **cmdline_p)
 {
 	unsigned long kernel_end;
 
+	early_setup_per_cpu_area();
+	early_trap_init();
+
  	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
diff -puN arch/x86_64/kernel/setup64.c~x86_64-lite arch/x86_64/kernel/setup64.c
--- linux-2.6.13/arch/x86_64/kernel/setup64.c~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/setup64.c	2005-08-10 16:27:31.000000000 -0700
@@ -77,6 +77,16 @@ static int __init nonx32_setup(char *str
 }
 __setup("noexec32=", nonx32_setup);
 
+void __init early_setup_per_cpu_area(void)
+{
+	static char cpu0[PERCPU_ENOUGH_ROOM]
+		__attribute__ ((aligned (SMP_CACHE_BYTES)));
+	char *ptr = cpu0;
+
+	cpu_pda[0].data_offset = ptr - __per_cpu_start;
+	memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+}
+
 /*
  * Great future plan:
  * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
@@ -97,7 +107,9 @@ void __init setup_per_cpu_areas(void)
 	for (i = 0; i < NR_CPUS; i++) { 
 		char *ptr;
 
-		if (!NODE_DATA(cpu_to_node(i))) {
+		if (cpu_pda[i].data_offset)
+			continue;
+		else if (!NODE_DATA(cpu_to_node(i))) {
 			printk("cpu with no node %d, num_online_nodes %d\n",
 			       i, num_online_nodes());
 			ptr = alloc_bootmem(size);
diff -puN include/asm-x86_64/proto.h~x86_64-lite include/asm-x86_64/proto.h
--- linux-2.6.13/include/asm-x86_64/proto.h~x86_64-lite	2005-08-10 16:27:31.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/proto.h	2005-08-10 16:27:31.000000000 -0700
@@ -10,6 +10,8 @@ struct pt_regs;
 
 extern void get_cpu_vendor(struct cpuinfo_x86*);
 extern void start_kernel(void);
+extern void early_trap_init(void);
+extern void early_setup_per_cpu_area(void);
 extern void pda_init(int); 
 
 extern void early_idt_handler(void);
diff -puN arch/x86_64/mm/fault.c~x86_64-lite arch/x86_64/mm/fault.c
--- linux-2.6.13/arch/x86_64/mm/fault.c~x86_64-lite	2005-08-12 08:28:51.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/mm/fault.c	2005-08-12 08:30:00.000000000 -0700
@@ -516,6 +516,10 @@ no_context:
 	if (is_errata93(regs, address))
 		return; 
 
+	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
+				SIGSEGV) == NOTIFY_STOP)
+		return;
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
_

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

* [patch 09/16] Add support for SuperH platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (6 preceding siblings ...)
  2005-08-29 16:10   ` [patch 08/16] Add support for X86_64 platforms to KGDB Tom Rini
@ 2005-08-29 16:10   ` Tom Rini
  2005-08-29 16:10   ` [patch 10/16] Add support for ARM " Tom Rini
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:10 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, lethal, kkojima


This adds basic support for KGDB on SuperH as well as adding some architecture
specific notes to the DocBook file and converting the 7751 to use this.  I
have tested all combinations of 8250 and SCI(F) ports being used as KGDB and
console that I could (one of each usable to me).

Index: linux-2.6.13/arch/sh/boards/se/7751/setup.c
===================================================================
--- linux-2.6.13.orig/arch/sh/boards/se/7751/setup.c
+++ linux-2.6.13/arch/sh/boards/se/7751/setup.c
@@ -18,10 +18,6 @@
 #include <asm/io.h>
 #include <asm/se7751/se7751.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#endif
-
 /*
  * Configure the Super I/O chip
  */
@@ -83,12 +79,6 @@ const char *get_system_type(void)
 	return "7751 SolutionEngine";
 }
 
-#ifdef CONFIG_SH_KGDB
-static int kgdb_uart_setup(void);
-static struct kgdb_sermap kgdb_uart_sermap = 
-{ "ttyS", 0, kgdb_uart_setup, NULL };
-#endif
- 
 /*
  * Initialize the board
  */
@@ -96,133 +86,4 @@ void __init platform_setup(void)
 {
 	/* Call init_smsc() replacement to set up SuperIO. */
 	/* XXX: RTC setting comes here */
-#ifdef CONFIG_SH_KGDB
-	kgdb_register_sermap(&kgdb_uart_sermap);
-#endif
-}
-
-/*********************************************************************
- * Currently a hack (e.g. does not interact well w/serial.c, lots of *
- * hardcoded stuff) but may be useful if SCI/F needs debugging.      *
- * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and  *
- * arch/i386/lib/kgdb_serial.c).                                     *
- *********************************************************************/
-
-#ifdef CONFIG_SH_KGDB
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-
-#define COM1_PORT 0x3f8  /* Base I/O address */
-#define COM1_IRQ  4      /* IRQ not used yet */
-#define COM2_PORT 0x2f8  /* Base I/O address */
-#define COM2_IRQ  3      /* IRQ not used yet */
-
-#define SB_CLOCK 1843200 /* Serial baud clock */
-#define SB_BASE (SB_CLOCK/16)
-#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
-
-struct uart_port {
-	int base;
-};
-#define UART_NPORTS 2
-struct uart_port uart_ports[] = {
-	{ COM1_PORT },
-	{ COM2_PORT },
-};
-struct uart_port *kgdb_uart_port;
-
-#define UART_IN(reg)	inb_p(kgdb_uart_port->base + reg)
-#define UART_OUT(reg,v)	outb_p((v), kgdb_uart_port->base + reg)
-
-/* Basic read/write functions for the UART */
-#define UART_LSR_RXCERR    (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
-static int kgdb_uart_getchar(void)
-{
-	int lsr;
-	int c = -1;
-
-	while (c == -1) {
-		lsr = UART_IN(UART_LSR);
-		if (lsr & UART_LSR_DR) 
-			c = UART_IN(UART_RX);
-		if ((lsr & UART_LSR_RXCERR))
-			c = -1;
-	}
-	return c;
-}
-
-static void kgdb_uart_putchar(int c)
-{
-	while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
-		;
-	UART_OUT(UART_TX, c);
-}
-
-/*
- * Initialize UART to configured/requested values.
- * (But we don't interrupts yet, or interact w/serial.c)
- */
-static int kgdb_uart_setup(void)
-{
-	int port;
-	int lcr = 0;
-	int bdiv = 0;
-
-	if (kgdb_portnum >= UART_NPORTS) {
-		KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
-		return -1;
-	}
-
-	kgdb_uart_port = &uart_ports[kgdb_portnum];
-
-	/* Init sequence from gdb_hook_interrupt */
-	UART_IN(UART_RX);
-	UART_OUT(UART_IER, 0);
-
-	UART_IN(UART_RX);	/* Serial driver comments say */
-	UART_IN(UART_IIR);	/* this clears interrupt regs */
-	UART_IN(UART_MSR);
-
-	/* Figure basic LCR values */
-	switch (kgdb_bits) {
-	case '7':
-		lcr |= UART_LCR_WLEN7;
-		break;
-	default: case '8': 
-		lcr |= UART_LCR_WLEN8;
-		break;
-	}
-	switch (kgdb_parity) {
-	case 'O':
-		lcr |= UART_LCR_PARITY;
-		break;
-	case 'E':
-		lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
-		break;
-	default: break;
-	}
-
-	/* Figure the baud rate divisor */
-	bdiv = (SB_BASE/kgdb_baud);
-	
-	/* Set the baud rate and LCR values */
-	UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
-	UART_OUT(UART_DLL, (bdiv & 0xff));
-	UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
-	UART_OUT(UART_LCR, lcr);
-
-	/* Set the MCR */
-	UART_OUT(UART_MCR, SB_MCR);
-
-	/* Turn off FIFOs for now */
-	UART_OUT(UART_FCR, 0);
-
-	/* Setup complete: initialize function pointers */
-	kgdb_getchar = kgdb_uart_getchar;
-	kgdb_putchar = kgdb_uart_putchar;
-
-	return 0;
 }
-#endif /* CONFIG_SH_KGDB */
Index: linux-2.6.13/arch/sh/Kconfig.debug
===================================================================
--- linux-2.6.13.orig/arch/sh/Kconfig.debug
+++ linux-2.6.13/arch/sh/Kconfig.debug
@@ -29,96 +29,4 @@ config EARLY_PRINTK
 	  This option is only useful porting the kernel to a new machine,
 	  when the kernel may crash or hang before the serial console is
 	  initialised. If unsure, say N.
-
-config KGDB
-	bool "Include KGDB kernel debugger"
-	help
-	  Include in-kernel hooks for kgdb, the Linux kernel source level
-	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
-	  Unless you are intending to debug the kernel, say N here.
-
-menu "KGDB configuration options"
-	depends on KGDB
-
-config MORE_COMPILE_OPTIONS
-	bool "Add any additional compile options"
-	help
-	  If you want to add additional CFLAGS to the kernel build, enable this
-	  option and then enter what you would like to add in the next question.
-	  Note however that -g is already appended with the selection of KGDB.
-
-config COMPILE_OPTIONS
-	string "Additional compile arguments"
-	depends on MORE_COMPILE_OPTIONS
-
-config KGDB_NMI
-	bool "Enter KGDB on NMI"
-	default n
-
-config KGDB_THREAD
-	bool "Include KGDB thread support"
-	default y
-
-config SH_KGDB_CONSOLE
-	bool "Console messages through GDB"
-	default n
-
-config KGDB_SYSRQ
-	bool "Allow SysRq 'G' to enter KGDB"
-	default y
-
-config KGDB_KERNEL_ASSERTS
-	bool "Include KGDB kernel assertions"
-	default n
-
-comment "Serial port setup"
-
-config KGDB_DEFPORT
-	int "Port number (ttySCn)"
-	default "1"
-
-config KGDB_DEFBAUD
-	int "Baud rate"
-	default "115200"
-
-choice
-	prompt "Parity"
-	depends on KGDB
-	default KGDB_DEFPARITY_N
-
-config KGDB_DEFPARITY_N
-	bool "None"
-
-config KGDB_DEFPARITY_E
-	bool "Even"
-
-config KGDB_DEFPARITY_O
-	bool "Odd"
-
-endchoice
-
-choice
-	prompt "Data bits"
-	depends on KGDB
-	default KGDB_DEFBITS_8
-
-config KGDB_DEFBITS_8
-	bool "8"
-
-config KGDB_DEFBITS_7
-	bool "7"
-
-endchoice
-
-endmenu
-
-config FRAME_POINTER
-	bool "Compile the kernel with frame pointers"
-	default y if KGDB
-	help
-	  If you say Y here the resulting kernel image will be slightly larger
-	  and slower, but it will give very useful debugging information.
-	  If you don't debug the kernel, you can say N, but we may not be able
-	  to solve problems without frame pointers.
-
 endmenu
Index: linux-2.6.13/arch/sh/kernel/cpu/sh3/ex.S
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/cpu/sh3/ex.S
+++ linux-2.6.13/arch/sh/kernel/cpu/sh3/ex.S
@@ -43,7 +43,7 @@ ENTRY(exception_handling_table)
 	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
 	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
 ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
+#if defined (CONFIG_KGDB)
 	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
 #else
 	.long	exception_none	/* 1C0 */	! Not implemented yet
Index: linux-2.6.13/arch/sh/kernel/cpu/sh4/ex.S
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/cpu/sh4/ex.S
+++ linux-2.6.13/arch/sh/kernel/cpu/sh4/ex.S
@@ -47,7 +47,7 @@ ENTRY(exception_handling_table)
 	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
 	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
 ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
+#if defined (CONFIG_KGDB)
 	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
 #else
 	.long	exception_none	/* 1C0 */	! Not implemented yet
Index: linux-2.6.13/arch/sh/kernel/entry.S
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/entry.S
+++ linux-2.6.13/arch/sh/kernel/entry.S
@@ -92,7 +92,7 @@ INTEVT  = 0xff000028
 MMU_TEA = 0xff00000c		! TLB Exception Address Register
 #endif
 
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 NMI_VEC = 0x1c0			! Must catch early for debounce
 #endif
 
@@ -244,31 +244,33 @@ call_dae:
 2:	.long   do_address_error
 #endif /* CONFIG_MMU */
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB)
 ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
 ! If both are configured, handle the debug traps (breakpoints) in SW,
 ! but still allow BIOS traps to FW.
 
 	.align	2
 debug_kernel:
-#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
+#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_KGDB)
 	/* Force BIOS call to FW (debug_trap put TRA in r8) */
 	mov	r8,r0
 	shlr2	r0
 	cmp/eq	#0x3f,r0
 	bt	debug_kernel_fw
-#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_KGDB */
 
-debug_enter:		
-#if defined(CONFIG_SH_KGDB)
+	.align 2
+	.globl debug_enter
+debug_enter:
+#if defined(CONFIG_KGDB)
 	/* Jump to kgdb, pass stacked regs as arg */
 debug_kernel_sw:
 	mov.l	3f, r0
 	jmp	@r0
 	 mov	r15, r4
 	.align	2
-3:	.long	kgdb_handle_exception
-#endif /* CONFIG_SH_KGDB */
+3:	.long	kgdb_exception_handler
+#endif /* CONFIG_KGDB */
 
 #if defined(CONFIG_SH_STANDARD_BIOS)
 	/* Unwind the stack and jmp to the debug entry */
@@ -310,12 +312,12 @@ debug_kernel_fw:
 2:	.long	gdb_vbr_vector
 #endif /* CONFIG_SH_STANDARD_BIOS */
 
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB */
 
 
 	.align	2
-debug_trap:	
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+debug_trap:
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB)
 	mov	#OFF_SR, r0
 	mov.l	@(r0,r15), r0		! get status register
 	shll	r0
@@ -659,7 +661,7 @@ skip_restore:
 6:	or	k0, k2			! Set the IMASK-bits
 	ldc	k2, ssr
 	!
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 	! Clear in_nmi
 	mov.l	4f, k0
 	mov	#0, k1
@@ -711,7 +713,7 @@ tlb_miss:
 interrupt:
 	mov.l	2f, k2
 	mov.l	3f, k3
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 	! Debounce (filter nested NMI)
 	mov.l	@k2, k0
 	mov.l	5f, k1
@@ -726,7 +728,7 @@ interrupt:
 5:	.long	NMI_VEC
 6:	.long	in_nmi
 0:
-#endif /* defined(CONFIG_KGDB_NMI) */
+#endif /* defined(CONFIG_KGDB) */
 	bra	handle_exception
 	 mov.l	@k2, k2
 
Index: linux-2.6.13/arch/sh/kernel/kgdb.c
===================================================================
--- /dev/null
+++ linux-2.6.13/arch/sh/kernel/kgdb.c
@@ -0,0 +1,363 @@
+/*
+ * arch/sh/kernel/kgdb.c
+ *
+ * Contains SH-specific low-level support for KGDB.
+ *
+ * Containes extracts from code by Glenn Engel, Jim Kingdon,
+ * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
+ * Amit S. Kale <akale@veritas.com>,  William Gatliff <bgat@open-widgets.com>,
+ * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>,
+ * Henry Bell <henry.bell@st.com> and Jeremy Siegel <jsiegel@mvista.com>
+ *
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2004 (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.
+ */
+
+#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 <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+extern void per_cpu_trap_init(void);
+extern atomic_t cpu_doing_single_step;
+
+/* Function pointers for linkage */
+static struct kgdb_regs trap_registers;
+
+/* Globals. */
+char in_nmi;			/* Set during NMI to prevent reentry */
+
+/* TRA differs sh3/4 */
+#if defined(CONFIG_CPU_SH3)
+#define TRA 0xffffffd0
+#elif defined(CONFIG_CPU_SH4)
+#define TRA 0xff000020
+#endif
+
+/* Macros for single step instruction identification */
+#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
+#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
+#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
+			      (((op) & 0x7f ) << 1))
+#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
+#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
+#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
+#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
+#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
+#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
+#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
+#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
+#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
+#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
+#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_RTS(op)        ((op) == 0xb)
+#define OPCODE_RTE(op)        ((op) == 0x2b)
+
+#define SR_T_BIT_MASK           0x1
+#define STEP_OPCODE             0xc320
+#define BIOS_CALL_TRAP          0x3f
+
+/* Exception codes as per SH-4 core manual */
+#define ADDRESS_ERROR_LOAD_VEC   7
+#define ADDRESS_ERROR_STORE_VEC  8
+#define TRAP_VEC                 11
+#define INVALID_INSN_VEC         12
+#define INVALID_SLOT_VEC         13
+#define NMI_VEC                  14
+#define SERIAL_BREAK_VEC         58
+
+/* Misc static */
+static int stepped_address;
+static short stepped_opcode;
+
+/* Translate SH-3/4 exception numbers to unix-like signal values */
+static int compute_signal(const int excep_code)
+{
+	switch (excep_code) {
+	case INVALID_INSN_VEC:
+	case INVALID_SLOT_VEC:
+		return SIGILL;
+	case ADDRESS_ERROR_LOAD_VEC:
+	case ADDRESS_ERROR_STORE_VEC:
+		return SIGSEGV;
+	case SERIAL_BREAK_VEC:
+	case NMI_VEC:
+		return SIGINT;
+	default:
+		/* Act like it was a break/trap. */
+		return SIGTRAP;
+	}
+}
+
+/*
+ * Translate the registers of the system into the format that GDB wants.  Since
+ * we use a local structure to store things, instead of getting them out
+ * of pt_regs, we can just do a memcpy.
+ */
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *ign)
+{
+	memcpy(gdb_regs, &trap_registers, sizeof(trap_registers));
+}
+
+/*
+ * On SH we save: r1 (prev->thread.sp) r2 (prev->thread.pc) r4 (prev) r5 (next)
+ * r6 (next->thread.sp) r7 (next->thread.pc)
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	int count;
+
+	for (count = 0; count < 16; count++)
+		*(gdb_regs++) = 0;
+	*(gdb_regs++) = p->thread.pc;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+}
+
+/*
+ * Translate the registers values that GDB has given us back into the
+ * format of the system.  See the comment above about memcpy.
+ */
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *ign)
+{
+	memcpy(&trap_registers, gdb_regs, sizeof(trap_registers));
+}
+
+/* Calculate the new address for after a step */
+static short *get_step_address(void)
+{
+	short op = *(short *)trap_registers.pc;
+	long addr;
+
+	/* BT */
+	if (OPCODE_BT(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BTS */
+	else if (OPCODE_BTS(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BF */
+	else if (OPCODE_BF(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BFS */
+	else if (OPCODE_BFS(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BRA */
+	else if (OPCODE_BRA(op))
+		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
+
+	/* BRAF */
+	else if (OPCODE_BRAF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
+
+	/* BSR */
+	else if (OPCODE_BSR(op))
+		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
+
+	/* BSRF */
+	else if (OPCODE_BSRF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
+
+	/* JMP */
+	else if (OPCODE_JMP(op))
+		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
+
+	/* JSR */
+	else if (OPCODE_JSR(op))
+		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
+
+	/* RTS */
+	else if (OPCODE_RTS(op))
+		addr = trap_registers.pr;
+
+	/* RTE */
+	else if (OPCODE_RTE(op))
+		addr = trap_registers.regs[15];
+
+	/* Other */
+	else
+		addr = trap_registers.pc + 2;
+
+	kgdb_flush_icache_range(addr, addr + 2);
+	return (short *)addr;
+}
+
+/* The command loop, read and act on requests */
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+			       char *remcom_in_buffer, char *remcom_out_buffer,
+			       struct pt_regs *ign)
+{
+	unsigned long addr;
+	char *ptr = &remcom_in_buffer[1];
+
+	/* Examine first char of buffer to see what we need to do */
+	switch (remcom_in_buffer[0]) {
+	case 'c':		/* Continue at address AA..AA (optional) */
+	case 's':		/* Step one instruction from AA..AA */
+		/* Try to read optional parameter, PC unchanged if none */
+		if (kgdb_hex2long(&ptr, &addr))
+			trap_registers.pc = addr;
+
+		atomic_set(&cpu_doing_single_step, -1);
+		if (remcom_in_buffer[0] == 's') {
+			/* Replace the instruction immediately after the
+			 * current instruction (i.e. next in the expected
+			 * flow of control) with a trap instruction, so that
+			 * returning will cause only a single instruction to
+			 * be executed. Note that this model is slightly
+			 * broken for instructions with delay slots
+			 * (e.g. B[TF]S, BSR, BRA etc), where both the branch
+			 * and the instruction in the delay slot will be
+			 * executed.
+			 */
+			/* Determine where the target instruction will send
+			 * us to */
+			unsigned short *next_addr = get_step_address();
+			stepped_address = (int)next_addr;
+
+			/* Replace it */
+			stepped_opcode = *(short *)next_addr;
+			*next_addr = STEP_OPCODE;
+
+			/* Flush and return */
+			kgdb_flush_icache_range((long)next_addr,
+						(long)next_addr + 2);
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+		}
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * When an exception has occured, we are called.  We need to set things
+ * up so that we can call kgdb_handle_exception to handle requests from
+ * the remote GDB.
+ */
+void kgdb_exception_handler(struct pt_regs *regs)
+{
+	int excep_code, vbr_val;
+	int count;
+
+	/* Copy kernel regs (from stack) */
+	for (count = 0; count < 16; count++)
+		trap_registers.regs[count] = regs->regs[count];
+	trap_registers.pc = regs->pc;
+	trap_registers.pr = regs->pr;
+	trap_registers.sr = regs->sr;
+	trap_registers.gbr = regs->gbr;
+	trap_registers.mach = regs->mach;
+	trap_registers.macl = regs->macl;
+
+	__asm__ __volatile__("stc vbr, %0":"=r"(vbr_val));
+	trap_registers.vbr = vbr_val;
+
+	/* Get the execption code. */
+	__asm__ __volatile__("stc r2_bank, %0":"=r"(excep_code));
+
+	excep_code >>= 5;
+
+	/* If we got an NMI, and KGDB is not yet initialized, call
+	 * breakpoint() to try and initialize everything for us. */
+	if (excep_code == NMI_VEC && !kgdb_initialized) {
+		breakpoint();
+		return;
+	}
+
+	/* TRAP_VEC exception indicates a software trap inserted in place of
+	 * code by GDB so back up PC by one instruction, as this instruction
+	 * will later be replaced by its original one.  Do NOT do this for
+	 * trap 0xff, since that indicates a compiled-in breakpoint which
+	 * will not be replaced (and we would retake the trap forever) */
+	if (excep_code == TRAP_VEC &&
+	    (*(volatile unsigned long *)TRA != (0xff << 2)))
+		trap_registers.pc -= 2;
+
+	/* If we have been single-stepping, put back the old instruction.
+	 * We use stepped_address in case we have stopped more than one
+	 * instruction away. */
+	if (stepped_opcode != 0) {
+		*(short *)stepped_address = stepped_opcode;
+		kgdb_flush_icache_range(stepped_address, stepped_address + 2);
+	}
+	stepped_opcode = 0;
+
+	/* Call the stub to do the processing.  Note that not everything we
+	 * need to send back and forth lives in pt_regs. */
+	kgdb_handle_exception(excep_code, compute_signal(excep_code), 0, regs);
+
+	/* Copy back the (maybe modified) registers */
+	for (count = 0; count < 16; count++)
+		regs->regs[count] = trap_registers.regs[count];
+	regs->pc = trap_registers.pc;
+	regs->pr = trap_registers.pr;
+	regs->sr = trap_registers.sr;
+	regs->gbr = trap_registers.gbr;
+	regs->mach = trap_registers.mach;
+	regs->macl = trap_registers.macl;
+
+	vbr_val = trap_registers.vbr;
+	__asm__ __volatile__("ldc %0, vbr": :"r"(vbr_val));
+}
+
+int __init kgdb_arch_init(void)
+{
+	per_cpu_trap_init();
+
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+	.gdb_bpt_instr = {0xff, 0xc3},
+#else
+	.gdb_bpt_instr = {0xc3, 0xff},
+#endif
+};
Index: linux-2.6.13/arch/sh/kernel/kgdb_jmp.S
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/kgdb_jmp.S
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/linkage.h>
-
-ENTRY(setjmp)
-	add	#(9*4), r4
-	sts.l	pr, @-r4
-	mov.l	r15, @-r4
-	mov.l	r14, @-r4
-	mov.l	r13, @-r4
-	mov.l	r12, @-r4
-	mov.l	r11, @-r4
-	mov.l	r10, @-r4
-	mov.l	r9, @-r4
-	mov.l	r8, @-r4
-	rts
-	 mov	#0, r0
-
-ENTRY(longjmp)
-	mov.l	@r4+, r8
-	mov.l	@r4+, r9
-	mov.l	@r4+, r10
-	mov.l	@r4+, r11
-	mov.l	@r4+, r12
-	mov.l	@r4+, r13
-	mov.l	@r4+, r14
-	mov.l	@r4+, r15
-	lds.l	@r4+, pr
-	mov	r5, r0
-	tst	r0, r0
-	bf	1f
-	mov	#1, r0	! in case val==0
-1:	rts
-	 nop
-
Index: linux-2.6.13/arch/sh/kernel/kgdb-jmp.S
===================================================================
--- /dev/null
+++ linux-2.6.13/arch/sh/kernel/kgdb-jmp.S
@@ -0,0 +1,32 @@
+#include <linux/linkage.h>
+
+ENTRY(kgdb_fault_setjmp)
+	add	#(9*4), r4
+	sts.l	pr, @-r4
+	mov.l	r15, @-r4
+	mov.l	r14, @-r4
+	mov.l	r13, @-r4
+	mov.l	r12, @-r4
+	mov.l	r11, @-r4
+	mov.l	r10, @-r4
+	mov.l	r9, @-r4
+	mov.l	r8, @-r4
+	rts
+	 mov	#0, r0
+
+ENTRY(kgdb_fault_longjmp)
+	mov.l	@r4+, r8
+	mov.l	@r4+, r9
+	mov.l	@r4+, r10
+	mov.l	@r4+, r11
+	mov.l	@r4+, r12
+	mov.l	@r4+, r13
+	mov.l	@r4+, r14
+	mov.l	@r4+, r15
+	lds.l	@r4+, pr
+	mov	r5, r0
+	tst	r0, r0
+	bf	1f
+	mov	#1, r0
+1:	rts
+	 nop
Index: linux-2.6.13/arch/sh/kernel/kgdb_stub.c
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/kgdb_stub.c
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * Containes extracts from code by Glenn Engel, Jim Kingdon,
- * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
- * Amit S. Kale <akale@veritas.com>,  William Gatliff <bgat@open-widgets.com>,
- * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
- * 
- * This version by Henry Bell <henry.bell@st.com>
- * Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
- * 
- * Contains low-level support for remote debug using GDB. 
- *
- * To enable debugger support, two things need to happen. A call to
- * set_debug_traps() is necessary in order to allow any breakpoints
- * or error conditions to be properly intercepted and reported to gdb.
- * A breakpoint also needs to be generated to begin communication.  This
- * is most easily accomplished by a call to breakpoint() which does
- * a trapa if the initialisation phase has been successfully completed.
- *
- * In this case, set_debug_traps() is not used to "take over" exceptions;
- * other kernel code is modified instead to enter the kgdb functions here
- * when appropriate (see entry.S for breakpoint traps and NMI interrupts,
- * see traps.c for kernel error exceptions).
- *
- * The following gdb commands are supported:
- *
- *    Command       Function                               Return value
- *
- *    g             return the value of the CPU registers  hex data or ENN
- *    G             set the value of the CPU registers     OK or ENN
- *
- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
- *    XAA..AA,LLLL: Same, but data is binary (not hex)     OK or ENN
- *
- *    c             Resume at current address              SNN   ( signal NN)
- *    cAA..AA       Continue at address AA..AA             SNN
- *    CNN;          Resume at current address with signal  SNN
- *    CNN;AA..AA    Resume at address AA..AA with signal   SNN
- *
- *    s             Step one instruction                   SNN
- *    sAA..AA       Step one instruction from AA..AA       SNN
- *    SNN;          Step one instruction with signal       SNN
- *    SNNAA..AA     Step one instruction from AA..AA w/NN  SNN
- *
- *    k             kill (Detach GDB)
- *
- *    d             Toggle debug flag
- *    D             Detach GDB 
- *
- *    Hct           Set thread t for operations,           OK or ENN
- *                  c = 'c' (step, cont), c = 'g' (other
- *                  operations)
- *
- *    qC            Query current thread ID                QCpid
- *    qfThreadInfo  Get list of current threads (first)    m<id>
- *    qsThreadInfo   "    "  "     "      "   (subsequent)
- *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z
- * 
- *    TXX           Find if thread XX is alive             OK or ENN
- *    ?             What was the last sigval ?             SNN   (signal NN)
- *    O             Output to GDB console
- *
- * Remote communication protocol.
- *
- *    A debug packet whose contents are <data> is encapsulated for
- *    transmission in the form:
- *
- *       $ <data> # CSUM1 CSUM2
- *
- *       <data> must be ASCII alphanumeric and cannot include characters
- *       '$' or '#'.  If <data> starts with two characters followed by
- *       ':', then the existing stubs interpret this as a sequence number.
- *
- *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
- *       checksum of <data>, the most significant nibble is sent first.
- *       the hex digits 0-9,a-f are used.
- *
- *    Receiver responds with:
- *
- *       +       - if CSUM is correct and ready for next packet
- *       -       - if CSUM is incorrect
- *
- * Responses can be run-length encoded to save space.  A '*' means that
- * the next character is an ASCII encoding giving a repeat count which
- * stands for that many repititions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3 
- * (which is where RLE starts to win).  Don't use an n > 126. 
- *
- * So "0* " means the same as "0000".
- */
-
-#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 <linux/linkage.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/current.h>
-#include <asm/signal.h>
-#include <asm/pgtable.h>
-#include <asm/ptrace.h>
-#include <asm/kgdb.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-#include <linux/console.h>
-#endif
-
-/* Function pointers for linkage */
-kgdb_debug_hook_t *kgdb_debug_hook;
-kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-int (*kgdb_getchar)(void);
-void (*kgdb_putchar)(int);
-
-static void put_debug_char(int c)
-{
-	if (!kgdb_putchar)
-		return;
-	(*kgdb_putchar)(c);
-}
-static int get_debug_char(void)
-{
-	if (!kgdb_getchar)
-		return -1;
-	return (*kgdb_getchar)();
-}
-
-/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */
-#define BUFMAX 1024
-#define NUMREGBYTES (MAXREG*4)
-#define OUTBUFMAX (NUMREGBYTES*2+512)
-
-enum regs {
-	R0 = 0, R1,  R2,  R3,   R4,   R5,  R6, R7,
-	R8, R9, R10, R11, R12,  R13,  R14, R15,
-	PC, PR, GBR, VBR, MACH, MACL, SR,
-	/*  */
-	MAXREG
-};
-
-static unsigned int registers[MAXREG];
-struct kgdb_regs trap_registers;
-
-char kgdb_in_gdb_mode;
-char in_nmi;			/* Set during NMI to prevent reentry */
-int kgdb_nofault;		/* Boolean to ignore bus errs (i.e. in GDB) */
-int kgdb_enabled = 1;		/* Default to enabled, cmdline can disable */
-int kgdb_halt;
-
-/* Exposed for user access */
-struct task_struct *kgdb_current;
-unsigned int kgdb_g_imask;
-int kgdb_trapa_val;
-int kgdb_excode;
-
-/* Default values for SCI (can override via kernel args in setup.c) */
-#ifndef CONFIG_KGDB_DEFPORT
-#define CONFIG_KGDB_DEFPORT 1
-#endif
-
-#ifndef CONFIG_KGDB_DEFBAUD
-#define CONFIG_KGDB_DEFBAUD 115200
-#endif
-
-#if defined(CONFIG_KGDB_DEFPARITY_E)
-#define CONFIG_KGDB_DEFPARITY 'E'
-#elif defined(CONFIG_KGDB_DEFPARITY_O)
-#define CONFIG_KGDB_DEFPARITY 'O'
-#else /* CONFIG_KGDB_DEFPARITY_N */
-#define CONFIG_KGDB_DEFPARITY 'N'
-#endif
-
-#ifdef CONFIG_KGDB_DEFBITS_7
-#define CONFIG_KGDB_DEFBITS '7'
-#else /* CONFIG_KGDB_DEFBITS_8 */
-#define CONFIG_KGDB_DEFBITS '8'
-#endif
-
-/* SCI/UART settings, used in kgdb_console_setup() */
-int  kgdb_portnum = CONFIG_KGDB_DEFPORT;
-int  kgdb_baud = CONFIG_KGDB_DEFBAUD;
-char kgdb_parity = CONFIG_KGDB_DEFPARITY;
-char kgdb_bits = CONFIG_KGDB_DEFBITS;
-
-/* Jump buffer for setjmp/longjmp */
-static jmp_buf rem_com_env;
-
-/* TRA differs sh3/4 */
-#if defined(CONFIG_CPU_SH3)
-#define TRA 0xffffffd0
-#elif defined(CONFIG_CPU_SH4)
-#define TRA 0xff000020
-#endif
-
-/* Macros for single step instruction identification */
-#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
-#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
-#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
-			      (((op) & 0x7f ) << 1))
-#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
-#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
-#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
-#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
-#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
-#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
-#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
-#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
-#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
-#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
-#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_RTS(op)        ((op) == 0xb)
-#define OPCODE_RTE(op)        ((op) == 0x2b)
-
-#define SR_T_BIT_MASK           0x1
-#define STEP_OPCODE             0xc320
-#define BIOS_CALL_TRAP          0x3f
-
-/* Exception codes as per SH-4 core manual */
-#define ADDRESS_ERROR_LOAD_VEC   7
-#define ADDRESS_ERROR_STORE_VEC  8
-#define TRAP_VEC                 11
-#define INVALID_INSN_VEC         12
-#define INVALID_SLOT_VEC         13
-#define NMI_VEC                  14
-#define USER_BREAK_VEC           15
-#define SERIAL_BREAK_VEC         58
-
-/* Misc static */
-static int stepped_address;
-static short stepped_opcode;
-static const char hexchars[] = "0123456789abcdef";
-static char in_buffer[BUFMAX];
-static char out_buffer[OUTBUFMAX];
-
-static void kgdb_to_gdb(const char *s);
-
-#ifdef CONFIG_KGDB_THREAD
-static struct task_struct *trapped_thread;
-static struct task_struct *current_thread;
-typedef unsigned char threadref[8];
-#define BUF_THREAD_ID_SIZE 16
-#endif
-
-/* Return addr as a real volatile address */
-static inline unsigned int ctrl_inl(const unsigned long addr)
-{
-	return *(volatile unsigned long *) addr;
-}
-
-/* Correctly set *addr using volatile */
-static inline void ctrl_outl(const unsigned int b, unsigned long addr)
-{
-	*(volatile unsigned long *) addr = b;
-}
-
-/* Get high hex bits */
-static char highhex(const int x)
-{
-	return hexchars[(x >> 4) & 0xf];
-}
-
-/* Get low hex bits */
-static char lowhex(const int x)
-{
-	return hexchars[x & 0xf];
-}
-
-/* Convert ch to hex */
-static int hex(const 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);
-}
-
-/* Convert the memory pointed to by mem into hex, placing result in buf.
-   Returns a pointer to the last char put in buf (null) */
-static char *mem_to_hex(const char *mem, char *buf, const int count)
-{
-	int i;
-	int ch;
-	unsigned short s_val;
-	unsigned long l_val;
-
-	/* Check for 16 or 32 */
-	if (count == 2 && ((long) mem & 1) == 0) {
-		s_val = *(unsigned short *) mem;
-		mem = (char *) &s_val;
-	} else if (count == 4 && ((long) mem & 3) == 0) {
-		l_val = *(unsigned long *) mem;
-		mem = (char *) &l_val;
-	}
-	for (i = 0; i < count; i++) {
-		ch = *mem++;
-		*buf++ = highhex(ch);
-		*buf++ = lowhex(ch);
-	}
-	*buf = 0;
-	return (buf);
-}
-
-/* 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 */
-static char *hex_to_mem(const char *buf, char *mem, const int count)
-{
-	int i;
-	unsigned char ch;
-
-	for (i = 0; i < count; i++) {
-		ch = hex(*buf++) << 4;
-		ch = ch + hex(*buf++);
-		*mem++ = ch;
-	}
-	return (mem);
-}
-
-/* While finding valid hex chars, convert to an integer, then return it */
-static int hex_to_int(char **ptr, int *int_value)
-{
-	int num_chars = 0;
-	int hex_value;
-
-	*int_value = 0;
-
-	while (**ptr) {
-		hex_value = hex(**ptr);
-		if (hex_value >= 0) {
-			*int_value = (*int_value << 4) | hex_value;
-			num_chars++;
-		} else
-			break;
-		(*ptr)++;
-	}
-	return num_chars;
-}
-
-/*  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 *ebin_to_mem(const char *buf, char *mem, int count)
-{
-	for (; count > 0; count--, buf++) {
-		if (*buf == 0x7d)
-			*mem++ = *(++buf) ^ 0x20;
-		else
-			*mem++ = *buf;
-	}
-	return mem;
-}
-
-/* Pack a hex byte */
-static char *pack_hex_byte(char *pkt, int byte)
-{
-	*pkt++ = hexchars[(byte >> 4) & 0xf];
-	*pkt++ = hexchars[(byte & 0xf)];
-	return pkt;
-}
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Pack a thread ID */
-static char *pack_threadid(char *pkt, threadref * id)
-{
-	char *limit;
-	unsigned char *altid;
-
-	altid = (unsigned char *) id;
-
-	limit = pkt + BUF_THREAD_ID_SIZE;
-	while (pkt < limit)
-		pkt = pack_hex_byte(pkt, *altid++);
-	return pkt;
-}
-
-/* Convert an integer into our threadref */
-static void int_to_threadref(threadref * id, const int value)
-{
-	unsigned char *scan = (unsigned char *) id;
-	int i = 4;
-
-	while (i--)
-		*scan++ = 0;
-
-	*scan++ = (value >> 24) & 0xff;
-	*scan++ = (value >> 16) & 0xff;
-	*scan++ = (value >> 8) & 0xff;
-	*scan++ = (value & 0xff);
-}
-
-/* Return a task structure ptr for a particular pid */
-static struct task_struct *get_thread(int pid)
-{
-	struct task_struct *thread;
-
-	/* Use PID_MAX w/gdb for pid 0 */
-	if (pid == PID_MAX) pid = 0;
-
-	/* First check via PID */
-	thread = find_task_by_pid(pid);
-
-	if (thread)
-		return thread;
-
-	/* Start at the start */
-	thread = init_tasks[0];
-
-	/* Walk along the linked list of tasks */
-	do {
-		if (thread->pid == pid)
-			return thread;
-		thread = thread->next_task;
-	} while (thread != init_tasks[0]);
-
-	return NULL;
-}
-
-#endif /* CONFIG_KGDB_THREAD */
-
-/* Scan for the start char '$', read the packet and check the checksum */
-static void get_packet(char *buffer, int buflen)
-{
-	unsigned char checksum;
-	unsigned char xmitcsum;
-	int i;
-	int count;
-	char ch;
-
-	do {
-		/* Ignore everything until the start character */
-		while ((ch = get_debug_char()) != '$');
-
-		checksum = 0;
-		xmitcsum = -1;
-		count = 0;
-
-		/* Now, read until a # or end of buffer is found */
-		while (count < (buflen - 1)) {
-			ch = get_debug_char();
-
-			if (ch == '#')
-				break;
-
-			checksum = checksum + ch;
-			buffer[count] = ch;
-			count = count + 1;
-		}
-
-		buffer[count] = 0;
-
-		/* Continue to read checksum following # */
-		if (ch == '#') {
-			xmitcsum = hex(get_debug_char()) << 4;
-			xmitcsum += hex(get_debug_char());
-
-			/* Checksum */
-			if (checksum != xmitcsum)
-				put_debug_char('-');	/* Failed checksum */
-			else {
-				/* Ack successful transfer */
-				put_debug_char('+');
-
-				/* If a sequence char is present, reply 
-				   the sequence ID */
-				if (buffer[2] == ':') {
-					put_debug_char(buffer[0]);
-					put_debug_char(buffer[1]);
-
-					/* Remove sequence chars from buffer */
-					count = strlen(buffer);
-					for (i = 3; i <= count; i++)
-						buffer[i - 3] = buffer[i];
-				}
-			}
-		}
-	}
-	while (checksum != xmitcsum);	/* Keep trying while we fail */
-}
-
-/* Send the packet in the buffer with run-length encoding */
-static void put_packet(char *buffer)
-{
-	int checksum;
-	char *src;
-	int runlen;
-	int encode;
-
-	do {
-		src = buffer;
-		put_debug_char('$');
-		checksum = 0;
-
-		/* Continue while we still have chars left */
-		while (*src) {
-			/* Check for runs up to 99 chars long */
-			for (runlen = 1; runlen < 99; runlen++) {
-				if (src[0] != src[runlen])
-					break;
-			}
-
-			if (runlen > 3) {
-				/* Got a useful amount, send encoding */
-				encode = runlen + ' ' - 4;
-				put_debug_char(*src);   checksum += *src;
-				put_debug_char('*');    checksum += '*';
-				put_debug_char(encode); checksum += encode;
-				src += runlen;
-			} else {
-				/* Otherwise just send the current char */
-				put_debug_char(*src);   checksum += *src;
-				src += 1;
-			}
-		}
-
-		/* '#' Separator, put high and low components of checksum */
-		put_debug_char('#');
-		put_debug_char(highhex(checksum));
-		put_debug_char(lowhex(checksum));
-	}
-	while ((get_debug_char()) != '+');	/* While no ack */
-}
-
-/* A bus error has occurred - perform a longjmp to return execution and
-   allow handling of the error */
-static void kgdb_handle_bus_error(void)
-{
-	longjmp(rem_com_env, 1);
-}
-
-/* Translate SH-3/4 exception numbers to unix-like signal values */
-static int compute_signal(const int excep_code)
-{
-	int sigval;
-
-	switch (excep_code) {
-
-	case INVALID_INSN_VEC:
-	case INVALID_SLOT_VEC:
-		sigval = SIGILL;
-		break;
-	case ADDRESS_ERROR_LOAD_VEC:
-	case ADDRESS_ERROR_STORE_VEC:
-		sigval = SIGSEGV;
-		break;
-
-	case SERIAL_BREAK_VEC:
-	case NMI_VEC:
-		sigval = SIGINT;
-		break;
-
-	case USER_BREAK_VEC:
-	case TRAP_VEC:
-		sigval = SIGTRAP;
-		break;
-
-	default:
-		sigval = SIGBUS;	/* "software generated" */
-		break;
-	}
-
-	return (sigval);
-}
-
-/* Make a local copy of the registers passed into the handler (bletch) */
-static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs,
-				  int *gdb_regs)
-{
-	gdb_regs[R0] = regs->regs[R0];
-	gdb_regs[R1] = regs->regs[R1];
-	gdb_regs[R2] = regs->regs[R2];
-	gdb_regs[R3] = regs->regs[R3];
-	gdb_regs[R4] = regs->regs[R4];
-	gdb_regs[R5] = regs->regs[R5];
-	gdb_regs[R6] = regs->regs[R6];
-	gdb_regs[R7] = regs->regs[R7];
-	gdb_regs[R8] = regs->regs[R8];
-	gdb_regs[R9] = regs->regs[R9];
-	gdb_regs[R10] = regs->regs[R10];
-	gdb_regs[R11] = regs->regs[R11];
-	gdb_regs[R12] = regs->regs[R12];
-	gdb_regs[R13] = regs->regs[R13];
-	gdb_regs[R14] = regs->regs[R14];
-	gdb_regs[R15] = regs->regs[R15];
-	gdb_regs[PC] = regs->pc;
-	gdb_regs[PR] = regs->pr;
-	gdb_regs[GBR] = regs->gbr;
-	gdb_regs[MACH] = regs->mach;
-	gdb_regs[MACL] = regs->macl;
-	gdb_regs[SR] = regs->sr;
-	gdb_regs[VBR] = regs->vbr;
-}
-
-/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
-static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
-				  struct kgdb_regs *regs)
-{
-	regs->regs[R0] = gdb_regs[R0];
-	regs->regs[R1] = gdb_regs[R1];
-	regs->regs[R2] = gdb_regs[R2];
-	regs->regs[R3] = gdb_regs[R3];
-	regs->regs[R4] = gdb_regs[R4];
-	regs->regs[R5] = gdb_regs[R5];
-	regs->regs[R6] = gdb_regs[R6];
-	regs->regs[R7] = gdb_regs[R7];
-	regs->regs[R8] = gdb_regs[R8];
-	regs->regs[R9] = gdb_regs[R9];
-	regs->regs[R10] = gdb_regs[R10];
-	regs->regs[R11] = gdb_regs[R11];
-	regs->regs[R12] = gdb_regs[R12];
-	regs->regs[R13] = gdb_regs[R13];
-	regs->regs[R14] = gdb_regs[R14];
-	regs->regs[R15] = gdb_regs[R15];
-	regs->pc = gdb_regs[PC];
-	regs->pr = gdb_regs[PR];
-	regs->gbr = gdb_regs[GBR];
-	regs->mach = gdb_regs[MACH];
-	regs->macl = gdb_regs[MACL];
-	regs->sr = gdb_regs[SR];
-	regs->vbr = gdb_regs[VBR];
-}
-
-#ifdef CONFIG_KGDB_THREAD
-/* Make a local copy of registers from the specified thread */
-asmlinkage void ret_from_fork(void);
-static void thread_regs_to_gdb_regs(const struct task_struct *thread,
-				    int *gdb_regs)
-{
-	int regno;
-	int *tregs;
-
-	/* Initialize to zero */
-	for (regno = 0; regno < MAXREG; regno++)
-		gdb_regs[regno] = 0;
-
-	/* Just making sure... */
-	if (thread == NULL)
-		return;
-
-	/* A new fork has pt_regs on the stack from a fork() call */
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-
-		int vbr_val;
-		struct pt_regs *kregs;
-		kregs = (struct pt_regs*)thread->thread.sp;
-
-		gdb_regs[R0] = kregs->regs[R0];
-		gdb_regs[R1] = kregs->regs[R1];
-		gdb_regs[R2] = kregs->regs[R2];
-		gdb_regs[R3] = kregs->regs[R3];
-		gdb_regs[R4] = kregs->regs[R4];
-		gdb_regs[R5] = kregs->regs[R5];
-		gdb_regs[R6] = kregs->regs[R6];
-		gdb_regs[R7] = kregs->regs[R7];
-		gdb_regs[R8] = kregs->regs[R8];
-		gdb_regs[R9] = kregs->regs[R9];
-		gdb_regs[R10] = kregs->regs[R10];
-		gdb_regs[R11] = kregs->regs[R11];
-		gdb_regs[R12] = kregs->regs[R12];
-		gdb_regs[R13] = kregs->regs[R13];
-		gdb_regs[R14] = kregs->regs[R14];
-		gdb_regs[R15] = kregs->regs[R15];
-		gdb_regs[PC] = kregs->pc;
-		gdb_regs[PR] = kregs->pr;
-		gdb_regs[GBR] = kregs->gbr;
-		gdb_regs[MACH] = kregs->mach;
-		gdb_regs[MACL] = kregs->macl;
-		gdb_regs[SR] = kregs->sr;
-
-		asm("stc vbr, %0":"=r"(vbr_val));
-		gdb_regs[VBR] = vbr_val;
-		return;
-	}
-
-	/* Otherwise, we have only some registers from switch_to() */
-	tregs = (int *)thread->thread.sp;
-	gdb_regs[R15] = (int)tregs;
-	gdb_regs[R14] = *tregs++;
-	gdb_regs[R13] = *tregs++;
-	gdb_regs[R12] = *tregs++;
-	gdb_regs[R11] = *tregs++;
-	gdb_regs[R10] = *tregs++;
-	gdb_regs[R9] = *tregs++;
-	gdb_regs[R8] = *tregs++;
-	gdb_regs[PR] = *tregs++;
-	gdb_regs[GBR] = *tregs++;
-	gdb_regs[PC] = thread->thread.pc;
-}
-#endif /* CONFIG_KGDB_THREAD */
-
-/* Calculate the new address for after a step */
-static short *get_step_address(void)
-{
-	short op = *(short *) trap_registers.pc;
-	long addr;
-
-	/* BT */
-	if (OPCODE_BT(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BTS */
-	else if (OPCODE_BTS(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BF */
-	else if (OPCODE_BF(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BFS */
-	else if (OPCODE_BFS(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BRA */
-	else if (OPCODE_BRA(op))
-		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
-
-	/* BRAF */
-	else if (OPCODE_BRAF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
-
-	/* BSR */
-	else if (OPCODE_BSR(op))
-		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
-
-	/* BSRF */
-	else if (OPCODE_BSRF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
-
-	/* JMP */
-	else if (OPCODE_JMP(op))
-		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
-
-	/* JSR */
-	else if (OPCODE_JSR(op))
-		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
-
-	/* RTS */
-	else if (OPCODE_RTS(op))
-		addr = trap_registers.pr;
-
-	/* RTE */
-	else if (OPCODE_RTE(op))
-		addr = trap_registers.regs[15];
-
-	/* Other */
-	else
-		addr = trap_registers.pc + 2;
-
-	kgdb_flush_icache_range(addr, addr + 2);
-	return (short *) addr;
-}
-
-/* Set up a single-step.  Replace the instruction immediately after the 
-   current instruction (i.e. next in the expected flow of control) with a
-   trap instruction, so that returning will cause only a single instruction
-   to be executed. Note that this model is slightly broken for instructions
-   with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch
-   and the instruction in the delay slot will be executed. */
-static void do_single_step(void)
-{
-	unsigned short *addr = 0;
-
-	/* Determine where the target instruction will send us to */
-	addr = get_step_address();
-	stepped_address = (int)addr;
-
-	/* Replace it */
-	stepped_opcode = *(short *)addr;
-	*addr = STEP_OPCODE;
-
-	/* Flush and return */
-	kgdb_flush_icache_range((long) addr, (long) addr + 2);
-	return;
-}
-
-/* Undo a single step */
-static void undo_single_step(void)
-{
-	/* If we have stepped, put back the old instruction */
-	/* Use stepped_address in case we stopped elsewhere */
-	if (stepped_opcode != 0) {
-		*(short*)stepped_address = stepped_opcode;
-		kgdb_flush_icache_range(stepped_address, stepped_address + 2);
-	}
-	stepped_opcode = 0;
-}
-
-/* Send a signal message */
-static void send_signal_msg(const int signum)
-{
-#ifndef CONFIG_KGDB_THREAD
-	out_buffer[0] = 'S';
-	out_buffer[1] = highhex(signum);
-	out_buffer[2] = lowhex(signum);
-	out_buffer[3] = 0;
-	put_packet(out_buffer);
-#else /* CONFIG_KGDB_THREAD */
-	int threadid;
-	threadref thref;
-	char *out = out_buffer;
-	const char *tstring = "thread";
-
-	*out++ = 'T';
-	*out++ = highhex(signum);
-	*out++ = lowhex(signum);
-
-	while (*tstring) {
-		*out++ = *tstring++;
-	}
-	*out++ = ':';
-
-	threadid = trapped_thread->pid;
-	if (threadid == 0) threadid = PID_MAX;
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out, &thref);
-	out += BUF_THREAD_ID_SIZE;
-	*out++ = ';';
-
-	*out = 0;
-	put_packet(out_buffer);
-#endif /* CONFIG_KGDB_THREAD */
-}
-
-/* Reply that all was well */
-static void send_ok_msg(void)
-{
-	strcpy(out_buffer, "OK");
-	put_packet(out_buffer);
-}
-
-/* Reply that an error occurred */
-static void send_err_msg(void)
-{
-	strcpy(out_buffer, "E01");
-	put_packet(out_buffer);
-}
-
-/* Empty message indicates unrecognised command */
-static void send_empty_msg(void)
-{
-	put_packet("");
-}
-
-/* Read memory due to 'm' message */
-static void read_mem_msg(void)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	/* Jmp, disable bus error handler */
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have m<addr>,<length> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length)) {
-				ptr = 0;
-				if (length * 2 > OUTBUFMAX)
-					length = OUTBUFMAX / 2;
-				mem_to_hex((char *) addr, out_buffer, length);
-			}
-		if (ptr)
-			send_err_msg();
-		else
-			put_packet(out_buffer);
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Write memory due to 'M' or 'X' message */
-static void write_mem_msg(int binary)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have M<addr>,<length>:<data> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) {
-				if (binary)
-					ebin_to_mem(ptr, (char*)addr, length);
-				else
-					hex_to_mem(ptr, (char*)addr, length);
-				kgdb_flush_icache_range(addr, addr + length);
-				ptr = 0;
-				send_ok_msg();
-			}
-		if (ptr)
-			send_err_msg();
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Continue message  */
-static void continue_msg(void)
-{
-	/* Try to read optional parameter, PC unchanged if none */
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Continue message with signal */
-static void continue_with_sig_msg(void)
-{
-	int signal;
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	/* Report limitation */
-	kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n");
-
-	/* Signal */
-	hex_to_int(&ptr, &signal);
-	if (*ptr == ';')
-		ptr++;
-
-	/* Optional address */
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Step message */
-static void step_msg(void)
-{
-	continue_msg();
-	do_single_step();
-}
-
-/* Step message with signal */
-static void step_with_sig_msg(void)
-{
-	continue_with_sig_msg();
-	do_single_step();
-}
-
-/* Send register contents */
-static void send_regs_msg(void)
-{
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread)
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-	else
-		thread_regs_to_gdb_regs(current_thread, registers);
-#else
-	kgdb_regs_to_gdb_regs(&trap_registers, registers);
-#endif
-
-	mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
-	put_packet(out_buffer);
-}
-
-/* Set register contents - currently can't set other thread's registers */
-static void set_regs_msg(void)
-{
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread) {
-#endif
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-		hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
-		gdb_regs_to_kgdb_regs(registers, &trap_registers);
-		send_ok_msg();
-#ifdef CONFIG_KGDB_THREAD
-	} else
-		send_err_msg();
-#endif
-}
-
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Set the status for a thread */
-void set_thread_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char *ptr;
-
-	switch (in_buffer[1]) {
-
-       	/* To select which thread for gG etc messages, i.e. supported */
-	case 'g':
-
-		ptr = &in_buffer[2];
-		hex_to_int(&ptr, &threadid);
-		thread = get_thread(threadid);
-
-		/* If we haven't found it */
-		if (!thread) {
-			send_err_msg();
-			break;
-		}
-
-		/* Set current_thread (or not) */
-		if (thread == trapped_thread)
-			current_thread = NULL;
-		else
-			current_thread = thread;
-		send_ok_msg();
-		break;
-
-	/* To select which thread for cCsS messages, i.e. unsupported */
-	case 'c':
-		send_ok_msg();
-		break;
-
-	default:
-		send_empty_msg();
-		break;
-	}
-}
-
-/* Is a thread alive? */
-static void thread_status_msg(void)
-{
-	char *ptr;
-	int threadid;
-	struct task_struct *thread = NULL;
-
-	ptr = &in_buffer[1];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-	if (thread)
-		send_ok_msg();
-	else
-		send_err_msg();
-}
-/* Send the current thread ID */
-static void thread_id_msg(void)
-{
-	int threadid;
-	threadref thref;
-
-	out_buffer[0] = 'Q';
-	out_buffer[1] = 'C';
-
-	if (current_thread)
-		threadid = current_thread->pid;
-	else if (trapped_thread)
-		threadid = trapped_thread->pid;
-	else /* Impossible, but just in case! */
-	{
-		send_err_msg();
-		return;
-	}
-
-	/* Translate pid 0 to PID_MAX for gdb */
-	if (threadid == 0) threadid = PID_MAX;
-
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out_buffer + 2, &thref);
-	out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
-	put_packet(out_buffer);
-}
-
-/* Send thread info */
-static void thread_info_msg(void)
-{
-	struct task_struct *thread = NULL;
-	int threadid;
-	char *pos;
-	threadref thref;
-
-	/* Start with 'm' */
-	out_buffer[0] = 'm';
-	pos = &out_buffer[1];
-
-	/* For all possible thread IDs - this will overrun if > 44 threads! */
-	/* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
-	for (threadid = 1; threadid <= PID_MAX; threadid++) {
-
-		read_lock(&tasklist_lock);
-		thread = get_thread(threadid);
-		read_unlock(&tasklist_lock);
-
-		/* If it's a valid thread */
-		if (thread) {
-			int_to_threadref(&thref, threadid);
-			pack_threadid(pos, &thref);
-			pos += BUF_THREAD_ID_SIZE;
-			*pos++ = ',';
-		}
-	}
-	*--pos = 0;		/* Lose final comma */
-	put_packet(out_buffer);
-
-}
-
-/* Return printable info for gdb's 'info threads' command */
-static void thread_extra_info_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char buffer[20], *ptr;
-	int i;
-
-	/* Extract thread ID */
-	ptr = &in_buffer[17];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-
-	/* If we don't recognise it, say so */
-	if (thread == NULL)
-		strcpy(buffer, "(unknown)");
-	else
-		strcpy(buffer, thread->comm);
-
-	/* Construct packet */
-	for (i = 0, ptr = out_buffer; buffer[i]; i++)
-		ptr = pack_hex_byte(ptr, buffer[i]);
-
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-		strcpy(buffer, "<new fork>");
-		for (i = 0; buffer[i]; i++)
-			ptr = pack_hex_byte(ptr, buffer[i]);
-	}
-
-	*ptr = '\0';
-	put_packet(out_buffer);
-}
-
-/* Handle all qFooBarBaz messages - have to use an if statement as
-   opposed to a switch because q messages can have > 1 char id. */
-static void query_msg(void)
-{
-	const char *q_start = &in_buffer[1];
-
-	/* qC = return current thread ID */
-	if (strncmp(q_start, "C", 1) == 0)
-		thread_id_msg();
-
-	/* qfThreadInfo = query all threads (first) */
-	else if (strncmp(q_start, "fThreadInfo", 11) == 0)
-		thread_info_msg();
-
-	/* qsThreadInfo = query all threads (subsequent). We know we have sent
-	   them all after the qfThreadInfo message, so there are no to send */
-	else if (strncmp(q_start, "sThreadInfo", 11) == 0)
-		put_packet("l");	/* el = last */
-
-	/* qThreadExtraInfo = supply printable information per thread */
-	else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
-		thread_extra_info_msg();
-
-	/* Unsupported - empty message as per spec */
-	else
-		send_empty_msg();
-}
-#endif /* CONFIG_KGDB_THREAD */
-
-/*
- * Bring up the ports..
- */
-static int kgdb_serial_setup(void)
-{
-	extern int kgdb_console_setup(struct console *co, char *options);
-	struct console dummy;
-
-	kgdb_console_setup(&dummy, 0);
-
-	return 0;
-}
-
-/* The command loop, read and act on requests */
-static void kgdb_command_loop(const int excep_code, const int trapa_value)
-{
-	int sigval;
-
-	if (excep_code == NMI_VEC) {
-#ifndef CONFIG_KGDB_NMI
-		KGDB_PRINTK("Ignoring unexpected NMI?\n");
-		return;
-#else /* CONFIG_KGDB_NMI */
-		if (!kgdb_enabled) {
-			kgdb_enabled = 1;
-			kgdb_init();
-		}
-#endif /* CONFIG_KGDB_NMI */
-	}
-
-	/* Ignore if we're disabled */
-	if (!kgdb_enabled)
-		return;
-
-#ifdef CONFIG_KGDB_THREAD
-	/* Until GDB specifies a thread */
-	current_thread = NULL;
-	trapped_thread = current;
-#endif
-
-	/* Enter GDB mode (e.g. after detach) */
-	if (!kgdb_in_gdb_mode) {
-		/* Do serial setup, notify user, issue preemptive ack */
-		kgdb_serial_setup();
-		KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
-			    (kgdb_porttype ? kgdb_porttype->name : ""),
-			    kgdb_portnum, kgdb_baud);
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-	}
-
-	/* Reply to host that an exception has occurred */
-	sigval = compute_signal(excep_code);
-	send_signal_msg(sigval);
-
-	/* TRAP_VEC exception indicates a software trap inserted in place of
-	   code by GDB so back up PC by one instruction, as this instruction
-	   will later be replaced by its original one.  Do NOT do this for
-	   trap 0xff, since that indicates a compiled-in breakpoint which
-	   will not be replaced (and we would retake the trap forever) */
-	if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
-		trap_registers.pc -= 2;
-	}
-
-	/* Undo any stepping we may have done */
-	undo_single_step();
-
-	while (1) {
-
-		out_buffer[0] = 0;
-		get_packet(in_buffer, BUFMAX);
-
-		/* Examine first char of buffer to see what we need to do */
-		switch (in_buffer[0]) {
-
-		case '?':	/* Send which signal we've received */
-			send_signal_msg(sigval);
-			break;
-
-		case 'g':	/* Return the values of the CPU registers */
-			send_regs_msg();
-			break;
-
-		case 'G':	/* Set the value of the CPU registers */
-			set_regs_msg();
-			break;
-
-		case 'm':	/* Read LLLL bytes address AA..AA */
-			read_mem_msg();
-			break;
-
-		case 'M':	/* Write LLLL bytes address AA..AA, ret OK */
-			write_mem_msg(0);	/* 0 = data in hex */
-			break;
-
-		case 'X':	/* Write LLLL bytes esc bin address AA..AA */
-			if (kgdb_bits == '8')
-				write_mem_msg(1); /* 1 = data in binary */
-			else
-				send_empty_msg();
-			break;
-
-		case 'C':	/* Continue, signum included, we ignore it */
-			continue_with_sig_msg();
-			return;
-
-		case 'c':	/* Continue at address AA..AA (optional) */
-			continue_msg();
-			return;
-
-		case 'S':	/* Step, signum included, we ignore it */
-			step_with_sig_msg();
-			return;
-
-		case 's':	/* Step one instruction from AA..AA */
-			step_msg();
-			return;
-
-#ifdef CONFIG_KGDB_THREAD
-
-		case 'H':	/* Task related */
-			set_thread_msg();
-			break;
-
-		case 'T':	/* Query thread status */
-			thread_status_msg();
-			break;
-
-		case 'q':	/* Handle query - currently thread-related */
-			query_msg();
-			break;
-#endif
-
-		case 'k':	/* 'Kill the program' with a kernel ? */
-			break;
-
-		case 'D':	/* Detach from program, send reply OK */
-			kgdb_in_gdb_mode = 0;
-			send_ok_msg();
-			get_debug_char();
-			return;
-
-		default:
-			send_empty_msg();
-			break;
-		}
-	}
-}
-
-/* There has been an exception, most likely a breakpoint. */
-void kgdb_handle_exception(struct pt_regs *regs)
-{
-	int excep_code, vbr_val;
-	int count;
-	int trapa_value = ctrl_inl(TRA);
-
-	/* Copy kernel regs (from stack) */
-	for (count = 0; count < 16; count++)
-		trap_registers.regs[count] = regs->regs[count];
-	trap_registers.pc = regs->pc;
-	trap_registers.pr = regs->pr;
-	trap_registers.sr = regs->sr;
-	trap_registers.gbr = regs->gbr;
-	trap_registers.mach = regs->mach;
-	trap_registers.macl = regs->macl;
-
-	asm("stc vbr, %0":"=r"(vbr_val));
-	trap_registers.vbr = vbr_val;
-
-	/* Get excode for command loop call, user access */
-	asm("stc r2_bank, %0":"=r"(excep_code));
-	kgdb_excode = excep_code;
-
-	/* Other interesting environment items for reference */
-	asm("stc r6_bank, %0":"=r"(kgdb_g_imask));
-	kgdb_current = current;
-	kgdb_trapa_val = trapa_value;
-
-	/* Act on the exception */
-	kgdb_command_loop(excep_code >> 5, trapa_value);
-
-	kgdb_current = NULL;
-
-	/* Copy back the (maybe modified) registers */
-	for (count = 0; count < 16; count++)
-		regs->regs[count] = trap_registers.regs[count];
-	regs->pc = trap_registers.pc;
-	regs->pr = trap_registers.pr;
-	regs->sr = trap_registers.sr;
-	regs->gbr = trap_registers.gbr;
-	regs->mach = trap_registers.mach;
-	regs->macl = trap_registers.macl;
-
-	vbr_val = trap_registers.vbr;
-	asm("ldc %0, vbr": :"r"(vbr_val));
-
-	return;
-}
-
-/* Trigger a breakpoint by function */
-void breakpoint(void)
-{
-	if (!kgdb_enabled) {
-		kgdb_enabled = 1;
-		kgdb_init();
-	}
-	BREAKPOINT();
-}
-
-/* Initialise the KGDB data structures and serial configuration */
-int kgdb_init(void)
-{
-	if (!kgdb_enabled)
-		return 1;
-
-	in_nmi = 0;
-	kgdb_nofault = 0;
-	stepped_opcode = 0;
-	kgdb_in_gdb_mode = 0;
-
-	if (kgdb_serial_setup() != 0) {
-		KGDB_PRINTK("serial setup error\n");
-		return -1;
-	}
-
-	/* Init ptr to exception handler */
-	kgdb_debug_hook = kgdb_handle_exception;
-	kgdb_bus_err_hook = kgdb_handle_bus_error;
-
-	/* Enter kgdb now if requested, or just report init done */
-	if (kgdb_halt) {
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-		breakpoint();
-	}
-	else
-	{
-		KGDB_PRINTK("stub is initialized.\n");
-	}
-
-	return 0;
-}
-
-/* Make function available for "user messages"; console will use it too. */
-
-char gdbmsgbuf[BUFMAX];
-#define MAXOUT ((BUFMAX-2)/2)
-
-static void kgdb_msg_write(const char *s, unsigned count)
-{
-	int i;
-	int wcount;
-	char *bufptr;
-
-	/* 'O'utput */
-	gdbmsgbuf[0] = 'O';
-
-	/* Fill and send buffers... */
-	while (count > 0) {
-		bufptr = gdbmsgbuf + 1;
-
-		/* Calculate how many this time */
-		wcount = (count > MAXOUT) ? MAXOUT : count;
-		
-		/* Pack in hex chars */
-		for (i = 0; i < wcount; i++)
-			bufptr = pack_hex_byte(bufptr, s[i]);
-		*bufptr = '\0';
-
-		/* Move up */
-		s += wcount;
-		count -= wcount;
-
-		/* Write packet */
-		put_packet(gdbmsgbuf);
-	}
-}
-
-static void kgdb_to_gdb(const char *s)
-{
-	kgdb_msg_write(s, strlen(s));
-}
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-void kgdb_console_write(struct console *co, const char *s, unsigned count)
-{
-	/* Bail if we're not talking to GDB */
-	if (!kgdb_in_gdb_mode)
-		return;
-
-	kgdb_msg_write(s, count);
-}
-#endif
Index: linux-2.6.13/arch/sh/kernel/Makefile
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/Makefile
+++ linux-2.6.13/arch/sh/kernel/Makefile
@@ -13,7 +13,7 @@ obj-y				+= cpu/
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
-obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
Index: linux-2.6.13/arch/sh/kernel/setup.c
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/setup.c
+++ linux-2.6.13/arch/sh/kernel/setup.c
@@ -27,10 +27,6 @@
 #include <asm/irq.h>
 #include <asm/setup.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_parse_options(char *options);
-#endif
 extern void * __rd_start, * __rd_end;
 /*
  * Machine setup..
@@ -557,93 +553,3 @@ struct seq_operations cpuinfo_op = {
 	.show	= show_cpuinfo,
 };
 #endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_SH_KGDB
-/*
- * Parse command-line kgdb options.  By default KGDB is enabled,
- * entered on error (or other action) using default serial info.
- * The command-line option can include a serial port specification
- * and an action to override default or configured behavior.
- */
-struct kgdb_sermap kgdb_sci_sermap =
-{ "ttySC", 5, kgdb_sci_setup, NULL };
-
-struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
-struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
-
-void kgdb_register_sermap(struct kgdb_sermap *map)
-{
-	struct kgdb_sermap *last;
-
-	for (last = kgdb_serlist; last->next; last = last->next)
-		;
-	last->next = map;
-	if (!map->namelen) {
-		map->namelen = strlen(map->name);
-	}
-}
-
-static int __init kgdb_parse_options(char *options)
-{
-	char c;
-	int baud;
-
-	/* Check for port spec (or use default) */
-
-	/* Determine port type and instance */
-	if (!memcmp(options, "tty", 3)) {
-		struct kgdb_sermap *map = kgdb_serlist;
-
-		while (map && memcmp(options, map->name, map->namelen))
-			map = map->next;
-
-		if (!map) {
-			KGDB_PRINTK("unknown port spec in %s\n", options);
-			return -1;
-		}
-
-		kgdb_porttype = map;
-		kgdb_serial_setup = map->setup_fn;
-		kgdb_portnum = options[map->namelen] - '0';
-		options += map->namelen + 1;
-
-		options = (*options == ',') ? options+1 : options;
-		
-		/* Read optional parameters (baud/parity/bits) */
-		baud = simple_strtoul(options, &options, 10);
-		if (baud != 0) {
-			kgdb_baud = baud;
-
-			c = toupper(*options);
-			if (c == 'E' || c == 'O' || c == 'N') {
-				kgdb_parity = c;
-				options++;
-			}
-
-			c = *options;
-			if (c == '7' || c == '8') {
-				kgdb_bits = c;
-				options++;
-			}
-			options = (*options == ',') ? options+1 : options;
-		}
-	}
-
-	/* Check for action specification */
-	if (!memcmp(options, "halt", 4)) {
-		kgdb_halt = 1;
-		options += 4;
-	} else if (!memcmp(options, "disabled", 8)) {
-		kgdb_enabled = 0;
-		options += 8;
-	}
-
-	if (*options) {
-                KGDB_PRINTK("ignored unknown options: %s\n", options);
-		return 0;
-	}
-	return 1;
-}
-__setup("kgdb=", kgdb_parse_options);
-#endif /* CONFIG_SH_KGDB */
-
Index: linux-2.6.13/arch/sh/kernel/time.c
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/time.c
+++ linux-2.6.13/arch/sh/kernel/time.c
@@ -34,9 +34,6 @@
 #include <asm/rtc.h>
 #include <asm/freq.h>
 #include <asm/cpu/timer.h>
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#endif
 
 #include <linux/timex.h>
 #include <linux/irq.h>
@@ -646,12 +643,4 @@ void __init time_init(void)
 	ctrl_outl(interval, TMU0_TCOR);
 	ctrl_outl(interval, TMU0_TCNT);
 	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-
-#if defined(CONFIG_SH_KGDB)
-	/*
-	 * Set up kgdb as requested. We do it here because the serial
-	 * init uses the timer vars we just set up for figuring baud.
-	 */
-	kgdb_init();
-#endif
 }
Index: linux-2.6.13/arch/sh/kernel/traps.c
===================================================================
--- linux-2.6.13.orig/arch/sh/kernel/traps.c
+++ linux-2.6.13/arch/sh/kernel/traps.c
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/kgdb.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -35,17 +36,8 @@
 #include <asm/processor.h>
 #include <asm/sections.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#define CHK_REMOTE_DEBUG(regs)                                               \
-{                                                                            \
-  if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \
-  {                                                                          \
-    (*kgdb_debug_hook)(regs);                                                \
-  }                                                                          \
-}
-#else
-#define CHK_REMOTE_DEBUG(regs)
+#ifndef CONFIG_KGDB
+#define kgdb_handle_exception(t, s, e, r)
 #endif
 
 #define DO_ERROR(trapnr, signr, str, name, tsk)				\
@@ -66,7 +58,7 @@ asmlinkage void do_##name(unsigned long 
 	local_irq_enable();						\
 	tsk->thread.error_code = error_code;				\
 	tsk->thread.trap_no = trapnr;					\
-        CHK_REMOTE_DEBUG(&regs);					\
+	kgdb_handle_exception(trapnr, signr, error_code, &regs);	\
 	force_sig(signr, tsk);						\
 	die_if_no_fixup(str,&regs,error_code);				\
 }
@@ -93,10 +85,12 @@ void die(const char * str, struct pt_reg
 {
 	static int die_counter;
 
+#ifdef CONFIG_KGDB
+	kgdb_handle_exception(1, SIGTRAP, err, regs);
+#endif
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-	CHK_REMOTE_DEBUG(regs);
 	show_regs(regs);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
Index: linux-2.6.13/arch/sh/Makefile
===================================================================
--- linux-2.6.13.orig/arch/sh/Makefile
+++ linux-2.6.13/arch/sh/Makefile
@@ -23,7 +23,6 @@ cflags-$(CONFIG_CPU_SH4)		+= -m4 \
 	$(call cc-option,-mno-implicit-fp,-m4-nofpu)
 
 cflags-$(CONFIG_SH_DSP)			+= -Wa,-dsp
-cflags-$(CONFIG_SH_KGDB)		+= -g
 
 cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
 	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
Index: linux-2.6.13/arch/sh/mm/extable.c
===================================================================
--- linux-2.6.13.orig/arch/sh/mm/extable.c
+++ linux-2.6.13/arch/sh/mm/extable.c
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kgdb.h>
 #include <asm/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
@@ -17,6 +18,12 @@ int fixup_exception(struct pt_regs *regs
 		regs->pc = fixup->fixup;
 		return 1;
 	}
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Never reached. */
+#endif
 
 	return 0;
 }
Index: linux-2.6.13/arch/sh/mm/fault.c
===================================================================
--- linux-2.6.13.orig/arch/sh/mm/fault.c
+++ linux-2.6.13/arch/sh/mm/fault.c
@@ -28,7 +28,6 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
-#include <asm/kgdb.h>
 
 extern void die(const char *,struct pt_regs *,long);
 
@@ -45,11 +44,6 @@ asmlinkage void do_page_fault(struct pt_
 	struct vm_area_struct * vma;
 	unsigned long page;
 
-#ifdef CONFIG_SH_KGDB
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	tsk = current;
 	mm = tsk->mm;
 
@@ -153,6 +147,7 @@ no_context:
 	}
 	die("Oops", regs, writeaccess);
 	do_exit(SIGKILL);
+	dump_stack();
 
 /*
  * We ran out of memory, or some other thing happened to us that made
@@ -199,11 +194,6 @@ asmlinkage int __do_page_fault(struct pt
 	pte_t *pte;
 	pte_t entry;
 
-#ifdef CONFIG_SH_KGDB
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 #ifdef CONFIG_SH_STORE_QUEUES
 	addrmax = P4SEG_STORE_QUE + 0x04000000;
 #endif
Index: linux-2.6.13/arch/sh/mm/fault-nommu.c
===================================================================
--- linux-2.6.13.orig/arch/sh/mm/fault-nommu.c
+++ linux-2.6.13/arch/sh/mm/fault-nommu.c
@@ -29,10 +29,6 @@
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 
-#if defined(CONFIG_SH_KGDB)
-#include <asm/kgdb.h>
-#endif
-
 extern void die(const char *,struct pt_regs *,long);
 
 /*
@@ -43,11 +39,6 @@ extern void die(const char *,struct pt_r
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
 			      unsigned long address)
 {
-#if defined(CONFIG_SH_KGDB)
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice.
@@ -69,11 +60,6 @@ asmlinkage void do_page_fault(struct pt_
 asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
 			       unsigned long address)
 {
-#if defined(CONFIG_SH_KGDB)
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	if (address >= TASK_SIZE)
 		return 1;
 
Index: linux-2.6.13/Documentation/DocBook/kgdb.tmpl
===================================================================
--- linux-2.6.13.orig/Documentation/DocBook/kgdb.tmpl
+++ linux-2.6.13/Documentation/DocBook/kgdb.tmpl
@@ -127,6 +127,10 @@
     <constant>kgdbwait</constant> after this arguement.
     </para>
     <para>
+    To specify the values of the SH SCI(F) serial port at boot:
+    <constant>kgdbsci=0,115200</constant>.
+    </para>
+    <para>
     To configure the <symbol>CONFIG_KGDB_ETH</symbol> driver, pass in
     <constant>kgdboe=[src-port]@&lt;src-ip&gt;/[dev],[tgt-port]@&lt;tgt-ip&gt;/[tgt-macaddr]</constant>
     where:
@@ -168,6 +172,18 @@
     application program.
     </para>
   </chapter>
+  <chapter id="ArchitectureNotes">
+    <title>Architecture specific notes</title>
+      <para>
+      SuperH: The NMI switch found on some boards can be used to trigger an
+      initial breakpoint.  Subsequent triggers do nothing.  If console
+      is enabled on the SCI(F) serial port, and that is the port being used
+      for KGDB, then you must trigger a breakpoint via sysrq, NMI, or
+      some other method prior to connecting, or echo a control-c to the
+      serial port.  Also, to use the SCI(F) port for KGDB, the
+      <symbol>CONFIG_SERIAL_SH_SCI</symbol> driver must be enabled.
+      </para>
+  </chapter>
   <chapter id="CommonBackEndReq">
     <title>The common backend (required)</title>
       <para>
Index: linux-2.6.13/drivers/serial/sh-sci.c
===================================================================
--- linux-2.6.13.orig/drivers/serial/sh-sci.c
+++ linux-2.6.13/drivers/serial/sh-sci.c
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/console.h>
 #include <linux/bitops.h>
+#include <linux/kgdb.h>
 
 #ifdef CONFIG_CPU_FREQ
 #include <linux/notifier.h>
@@ -65,14 +66,34 @@
 
 #include "sh-sci.h"
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
+#ifdef CONFIG_KGDB_SH_SCI
+/* Speed of the UART. */
+#if defined(CONFIG_KGDB_9600BAUD)
+static int kgdbsci_baud = 9600;
+#elif defined(CONFIG_KGDB_19200BAUD)
+static int kgdbsci_baud = 19200;
+#elif defined(CONFIG_KGDB_38400BAUD)
+static int kgdbsci_baud = 38400;
+#elif defined(CONFIG_KGDB_57600BAUD)
+static int kgdbsci_baud = 57600;
+#else
+static int kgdbsci_baud = 115200;	/* Start with this if not given */
+#endif
 
-static int kgdb_get_char(struct sci_port *port);
-static void kgdb_put_char(struct sci_port *port, char c);
-static void kgdb_handle_error(struct sci_port *port);
-static struct sci_port *kgdb_sci_port;
-#endif /* CONFIG_SH_KGDB */
+/* Index of the UART, matches ttySCX naming. */
+#if defined(CONFIG_KGDB_SERIAL_PORT_1)
+static int kgdbsci_ttySC = 1;
+#elif defined(CONFIG_KGDB_SERIAL_PORT_2)
+static int kgdbsci_ttySC = 2;
+#elif defined(CONFIG_KGDB_SERIAL_PORT_3)
+static int kgdbsci_ttySC = 3;
+#else
+static int kgdbsci_ttySC = 0;		/* Start with this if not given */
+#endif
+
+/* Make life easier on us. */
+#define KGDBPORT	sci_ports[kgdbsci_ttySC]
+#endif /* CONFIG_KGDB_SH_SCI */
 
 #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 static struct sci_port *serial_console_port = 0;
@@ -85,18 +106,15 @@ static void sci_start_rx(struct uart_por
 static void sci_stop_rx(struct uart_port *port);
 static int sci_request_irq(struct sci_port *port);
 static void sci_free_irq(struct sci_port *port);
+static void sci_set_termios(struct uart_port *port, struct termios *termios,
+			    struct termios *old);
+static int kgdbsci_init(void);
 
 static struct sci_port sci_ports[SCI_NPORTS];
 static struct uart_driver sci_uart_driver;
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
-
-static void handle_error(struct uart_port *port)
-{				/* Clear error flags */
-	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-}
-
-static int get_char(struct uart_port *port)
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB_SH_SCI)
+static int get_char_for_gdb(struct uart_port *port)
 {
 	unsigned long flags;
 	unsigned short status;
@@ -106,7 +124,8 @@ static int get_char(struct uart_port *po
         do {
 		status = sci_in(port, SCxSR);
 		if (status & SCxSR_ERRORS(port)) {
-			handle_error(port);
+			/* Clear error flags. */
+			sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
 			continue;
 		}
 	} while (!(status & SCxSR_RDxF(port)));
@@ -117,21 +136,7 @@ static int get_char(struct uart_port *po
 
 	return c;
 }
-
-/* Taken from sh-stub.c of GDB 4.18 */
-static const char hexchars[] = "0123456789abcdef";
-
-static __inline__ char highhex(int  x)
-{
-	return hexchars[(x >> 4) & 0xf];
-}
-
-static __inline__ char lowhex(int  x)
-{
-	return hexchars[x & 0xf];
-}
-
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB_SH_SCI */
 
 /*
  * Send the packet in buffer.  The host gets one chance to read it.
@@ -163,21 +168,14 @@ static void put_string(struct sci_port *
 	const unsigned char *p = buffer;
 	int i;
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+#ifdef CONFIG_SH_STANDARD_BIOS
 	int checksum;
-	int usegdb=0;
+	const char hexchars[] = "0123456789abcdef";
 
-#ifdef CONFIG_SH_STANDARD_BIOS
     	/* This call only does a trap the first time it is
 	 * called, and so is safe to do here unconditionally
 	 */
-	usegdb |= sh_bios_in_gdb_mode();
-#endif
-#ifdef CONFIG_SH_KGDB
-	usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
-#endif
-
-	if (usegdb) {
+	if (sh_bios_in_gdb_mode()) {
 	    /*  $<packet info>#<checksum>. */
 	    do {
 		unsigned char c;
@@ -189,18 +187,18 @@ static void put_string(struct sci_port *
 			int h, l;
 
 			c = *p++;
-			h = highhex(c);
-			l = lowhex(c);
+			h = hexchars[c >> 4];
+			l = hexchars[c % 16];
 			put_char(port, h);
 			put_char(port, l);
 			checksum += h + l;
 		}
 		put_char(port, '#');
-		put_char(port, highhex(checksum));
-		put_char(port, lowhex(checksum));
+		put_char(port, hexchars[checksum >> 4]);
+		put_char(port, hexchars[checksum & 16]);
 	    } while  (get_char(port) != '+');
 	} else
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS */
 	for (i=0; i<count; i++) {
 		if (*p == 10)
 			put_char(port, '\r');
@@ -210,90 +208,163 @@ static void put_string(struct sci_port *
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 
-#ifdef CONFIG_SH_KGDB
-
-/* Is the SCI ready, ie is there a char waiting? */
-static int kgdb_is_char_ready(struct sci_port *port)
+#ifdef CONFIG_KGDB_SH_SCI
+static int kgdbsci_read_char(void)
 {
-        unsigned short status = sci_in(port, SCxSR);
-
-        if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
-                kgdb_handle_error(port);
-
-        return (status & SCxSR_RDxF(port));
+	return get_char_for_gdb(&KGDBPORT.port);
 }
 
-/* Write a char */
-static void kgdb_put_char(struct sci_port *port, char c)
+/* Called from kgdbstub.c to put a character, just a wrapper */
+static void kgdbsci_write_char(int c)
 {
-        unsigned short status;
-
-        do
-                status = sci_in(port, SCxSR);
-        while (!(status & SCxSR_TDxE(port)));
+	unsigned short status;
 
-        sci_out(port, SCxTDR, c);
-        sci_in(port, SCxSR);    /* Dummy read */
-        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+	do
+		status = sci_in(&KGDBPORT.port, SCxSR);
+	while (!(status & SCxSR_TDxE(&KGDBPORT.port)));
+
+	sci_out(&KGDBPORT.port, SCxTDR, c);
+	sci_in(&KGDBPORT.port, SCxSR);	/* Dummy read */
+	sci_out(&KGDBPORT.port, SCxSR, SCxSR_TDxE_CLEAR(&KGDBPORT.port));
 }
 
-/* Get a char if there is one, else ret -1 */
-static int kgdb_get_char(struct sci_port *port)
+#ifndef CONFIG_SERIAL_SH_SCI_CONSOLE
+/* If we don't have console, we never hookup IRQs.  But we need to
+ * hookup one so that we can interrupt the system.
+ */
+static irqreturn_t kgdbsci_rx_interrupt(int irq, void *ptr,
+		struct pt_regs *regs)
 {
-        int c;
-
-        if (kgdb_is_char_ready(port) == 0)
-                c = -1;
-        else {
-                c = sci_in(port, SCxRDR);
-                sci_in(port, SCxSR);    /* Dummy read */
-                sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-        }
+	struct uart_port *port = ptr;
 
-        return c;
-}
+	if (!(sci_in(port, SCxSR) & SCxSR_RDxF(port)))
+		return IRQ_NONE;
 
-/* Called from kgdbstub.c to get a character, i.e. is blocking */
-static int kgdb_sci_getchar(void)
-{
-        volatile int c;
+	if (kgdb_io_ops.init != kgdbsci_init) {
+		/* Throw away the data if another I/O routine is active */
+		get_char_for_gdb(&KGDBPORT.port);
+	} else
+		/* We've got an interrupt, so go ahead and call breakpoint() */
+		breakpoint();
 
-        /* Keep trying to read a character, this could be neater */
-        while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+	sci_in(port, SCxSR); /* dummy read */
+	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
 
-        return c;
+	return IRQ_HANDLED;
 }
 
-/* Called from kgdbstub.c to put a character, just a wrapper */
-static void kgdb_sci_putchar(int c)
+static irqreturn_t kgdbsci_mpxed_interrupt(int irq, void *ptr,
+		struct pt_regs *regs)
 {
+        unsigned short ssr_status, scr_status;
+        struct uart_port *port = ptr;
+
+        ssr_status = sci_in(port,SCxSR);
+        scr_status = sci_in(port,SCSCR);
 
-        kgdb_put_char(kgdb_sci_port, c);
+	/* Rx Interrupt */
+        if ((ssr_status&0x0002) && (scr_status&0x0040))
+		kgdbsci_rx_interrupt(irq, ptr, regs);
+
+	return IRQ_HANDLED;
 }
 
-/* Clear any errors on the SCI */
-static void kgdb_handle_error(struct sci_port *port)
+static void __init kgdbsci_lateinit(void)
 {
-        sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));  /* Clear error flags */
+	if (KGDBPORT.irqs[0] == KGDBPORT.irqs[1]) {
+		if (!KGDBPORT.irqs[0]) {
+			printk(KERN_ERR "kgdbsci: Cannot allocate irq.\n");
+			return;
+		}
+		if (request_irq(KGDBPORT.irqs[0], kgdbsci_mpxed_interrupt,
+					SA_INTERRUPT, "kgdbsci",
+					&KGDBPORT.port)) {
+			printk(KERN_ERR "kgdbsci: Cannot allocate irq.\n");
+			return;
+		}
+	} else {
+		if (KGDBPORT.irqs[1])
+			request_irq(KGDBPORT.irqs[1],
+					kgdbsci_rx_interrupt, SA_INTERRUPT,
+					"kgdbsci", &KGDBPORT.port);
+	}
 }
+#endif
 
-/* Breakpoint if there's a break sent on the serial port */
-static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
+/*
+ * We use the normal init routine to setup the port, so we can't be
+ * in here too early.
+ */
+static int kgdbsci_init(void)
 {
-        struct sci_port *port = ptr;
-        unsigned short status = sci_in(port, SCxSR);
+	struct termios termios;
 
-        if (status & SCxSR_BRK(port)) {
+	memset(&termios, 0, sizeof(struct termios));
 
-                /* Break into the debugger if a break is detected */
-                BREAKPOINT();
+	termios.c_cflag = CREAD | HUPCL | CLOCAL | CS8;
+	switch (kgdbsci_baud) {
+	case 9600:
+		termios.c_cflag |= B9600;
+		break;
+	case 19200:
+		termios.c_cflag |= B19200;
+		break;
+	case 38400:
+		termios.c_cflag |= B38400;
+		break;
+	case 57600:
+		termios.c_cflag |= B57600;
+		break;
+	case 115200:
+		termios.c_cflag |= B115200;
+		break;
+	}
+	sci_set_termios(&KGDBPORT.port, &termios, NULL);
 
-                /* Clear */
-                sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
-        }
+	return 0;
 }
 
-#endif /* CONFIG_SH_KGDB */
+struct kgdb_io kgdb_io_ops = {
+	.read_char = kgdbsci_read_char,
+	.write_char = kgdbsci_write_char,
+	.init = kgdbsci_init,
+#ifndef CONFIG_SERIAL_SH_SCI_CONSOLE
+	.late_init = kgdbsci_lateinit,
+#else /* ! CONFIG_SERIAL_SH_SCI_CONSOLE */
+	.late_init = NULL,
+#endif /* ! CONFIG_SERIAL_SH_SCI_CONSOLE */
+	.pre_exception = NULL,
+	.post_exception = NULL
+};
+
+/*
+ * Syntax for this cmdline option is "kgdbsci=ttyno,baudrate".
+ */
+static int __init
+kgdbsci_opt(char *str)
+{
+	/* We might have anywhere from 1 to 3 ports. */
+	if (*str < '0' || *str > SCI_NPORTS + '0')
+		 goto errout;
+	kgdbsci_ttySC = *str - '0';
+	str++;
+	if (*str != ',')
+		 goto errout;
+	str++;
+	kgdbsci_baud = simple_strtoul(str, &str, 10);
+	if (kgdbsci_baud != 9600 && kgdbsci_baud != 19200 &&
+	    kgdbsci_baud != 38400 && kgdbsci_baud != 57600 &&
+	    kgdbsci_baud != 115200)
+		 goto errout;
+
+	return 0;
+
+errout:
+	printk(KERN_ERR "Invalid syntax for option kgdbsci=\n");
+	return 1;
+}
+__setup("kgdbsci", kgdbsci_opt);
+#endif /* CONFIG_KGDB_SH_SCI */
 
 #if defined(__H8300S__)
 enum { sci_disable, sci_enable };
@@ -541,6 +612,16 @@ static inline void sci_receive_chars(str
 					continue;
 				}
 
+#ifdef CONFIG_KGDB_SH_SCI
+				/* We assume that a ^C on the port KGDB
+				 * is using means that KGDB wants to
+				 * interrupt the running system.
+				 */
+				if (port->line == KGDBPORT.port.line &&
+						c == 3)
+					breakpoint();
+#endif
+
 				/* Store data and status */
 				tty->flip.char_buf_ptr[i] = c;
 				if (status&SCxSR_FER(port)) {
@@ -1552,6 +1633,7 @@ static int __init sci_console_init(void)
 console_initcall(sci_console_init);
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
+#if 0
 #ifdef CONFIG_SH_KGDB
 /*
  * FIXME: Most of this can go away.. at the moment, we rely on
@@ -1597,30 +1679,9 @@ int __init kgdb_console_setup(struct con
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 #endif /* CONFIG_SH_KGDB */
+#endif /* 0 */
 
-#ifdef CONFIG_SH_KGDB_CONSOLE
-static struct console kgdb_console = {
-        .name		= "ttySC",
-        .write		= kgdb_console_write,
-        .setup		= kgdb_console_setup,
-        .flags		= CON_PRINTBUFFER | CON_ENABLED,
-        .index		= -1,
-	.data		= &sci_uart_driver,
-};
-
-/* Register the KGDB console so we get messages (d'oh!) */
-static int __init kgdb_console_init(void)
-{
-	register_console(&kgdb_console);
-	return 0;
-}
-
-console_initcall(kgdb_console_init);
-#endif /* CONFIG_SH_KGDB_CONSOLE */
-
-#if defined(CONFIG_SH_KGDB_CONSOLE)
-#define SCI_CONSOLE	&kgdb_console
-#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 #define SCI_CONSOLE	&serial_console
 #else
 #define SCI_CONSOLE 	0
@@ -1689,4 +1750,3 @@ static void __exit sci_exit(void)
 
 module_init(sci_init);
 module_exit(sci_exit);
-
Index: linux-2.6.13/include/asm-sh/kgdb.h
===================================================================
--- linux-2.6.13.orig/include/asm-sh/kgdb.h
+++ linux-2.6.13/include/asm-sh/kgdb.h
@@ -2,94 +2,41 @@
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * Based on original code by Glenn Engel, Jim Kingdon,
- * David Grothe <dave@gcom.com>, Tigran Aivazian, <tigran@sco.com> and
- * Amit S. Kale <akale@veritas.com>
- * 
- * Super-H port based on sh-stub.c (Ben Lee and Steve Chamberlain) by
- * Henry Bell <henry.bell@st.com>
- * 
- * Header file for low-level support for remote debug using GDB. 
+ * Based on a file that was modified or based on files by: Glenn Engel,
+ * Jim Kingdon, David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
+ * Amit S. Kale <akale@veritas.com>, sh-stub.c from Ben Lee and
+ * Steve Chamberlain, Henry Bell <henry.bell@st.com>
+ *
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
  *
  */
 
 #ifndef __KGDB_H
 #define __KGDB_H
 
-#include <asm/ptrace.h>
-
-struct console;
+#include <asm-generic/kgdb.h>
+/* Based on sh-gdb.c from gdb-6.1, Glenn
+     Engel at HP  Ben Lee and Steve Chamberlain */
+#define NUMREGBYTES	112	/* 92 */
+#define NUMCRITREGBYTES	(9 << 2)
+#define BUFMAX		400
 
-/* Same as pt_regs but has vbr in place of syscall_nr */
+#ifndef __ASSEMBLY__
 struct kgdb_regs {
         unsigned long regs[16];
         unsigned long pc;
         unsigned long pr;
-        unsigned long sr;
         unsigned long gbr;
+        unsigned long vbr;
         unsigned long mach;
         unsigned long macl;
-        unsigned long vbr;
-};
-
-/* State info */
-extern char kgdb_in_gdb_mode;
-extern int kgdb_done_init;
-extern int kgdb_enabled;
-extern int kgdb_nofault;	/* Ignore bus errors (in gdb mem access) */
-extern int kgdb_halt;		/* Execute initial breakpoint at startup */
-extern char in_nmi;		/* Debounce flag to prevent NMI reentry*/
-
-/* SCI */
-extern int kgdb_portnum;
-extern int kgdb_baud;
-extern char kgdb_parity;
-extern char kgdb_bits;
-extern int kgdb_console_setup(struct console *, char *);
-
-/* Init and interface stuff */
-extern int kgdb_init(void);
-extern int (*kgdb_serial_setup)(void);
-extern int (*kgdb_getchar)(void);
-extern void (*kgdb_putchar)(int);
-
-struct kgdb_sermap {
-	char *name;
-	int namelen;
-	int (*setup_fn)(struct console *, char *);
-	struct kgdb_sermap *next;
+        unsigned long sr;
 };
-extern void kgdb_register_sermap(struct kgdb_sermap *map);
-extern struct kgdb_sermap *kgdb_porttype;
 
-/* Trap functions */
-typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); 
-typedef void (kgdb_bus_error_hook_t)(void);
-extern kgdb_debug_hook_t  *kgdb_debug_hook;
-extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-extern void breakpoint(void);
-
-/* Console */
-struct console;
-void kgdb_console_write(struct console *co, const char *s, unsigned count);
-void kgdb_console_init(void);
-
-/* Prototypes for jmp fns */
-#define _JBLEN 9
-typedef        int jmp_buf[_JBLEN];
-extern void    longjmp(jmp_buf __jmpb, int __retval);
-extern int     setjmp(jmp_buf __jmpb);
-
-/* Variadic macro to print our own message to the console */
-#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
-
-/* Forced breakpoint */
-#define BREAKPOINT() do {                                     \
-  if (kgdb_enabled) {                                         \
-    asm volatile("trapa   #0xff");                            \
-  }                                                           \
-} while (0)
+#define BREAKPOINT()		asm("trapa #0xff");
+#define BREAK_INSTR_SIZE	2
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
 
 /* KGDB should be able to flush all kernel text space */
 #if defined(CONFIG_CPU_SH4)
@@ -102,30 +49,5 @@ extern int     setjmp(jmp_buf __jmpb);
 #else
 #define kgdb_flush_icache_range(start, end)	do { } while (0)
 #endif
-
-/* Kernel assert macros */
-#ifdef CONFIG_KGDB_KERNEL_ASSERTS
-
-/* Predefined conditions */
-#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
-#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
-#define KA_VALID_KPTR(ptr)  (!(ptr) || \
-              ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
-               (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
-#define KA_VALID_PTRORERR(errptr) \
-               (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
-#define KA_HELD_GKL()  (current->lock_depth >= 0)
-
-/* The actual assert */
-#define KGDB_ASSERT(condition, message) do {                   \
-       if (!(condition) && (kgdb_enabled)) {                   \
-               KGDB_PRINTK("Assertion failed at %s:%d: %s\n",  \
-                                  __FILE__, __LINE__, message);\
-               BREAKPOINT();                                   \
-       }                                                       \
-} while (0)
-#else
-#define KGDB_ASSERT(condition, message)
-#endif
-
+#endif				/* !__ASSEMBLY__ */
 #endif
Index: linux-2.6.13/include/asm-sh/system.h
===================================================================
--- linux-2.6.13.orig/include/asm-sh/system.h
+++ linux-2.6.13/include/asm-sh/system.h
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <asm/types.h>
 
 /*
  *	switch_to() should switch tasks to task nr n, first
@@ -252,6 +253,45 @@ static __inline__ unsigned long __xchg(u
 	return x;
 }
 
+static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
+	unsigned long new)
+{
+	__u32 retval;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	retval = *m;
+	if (retval == old)
+		*m = new;
+	local_irq_restore(flags);       /* implies memory barrier  */
+	return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+		unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 /* XXX
  * disable hlt during certain critical i/o operations
  */
Index: linux-2.6.13/lib/Kconfig.debug
===================================================================
--- linux-2.6.13.orig/lib/Kconfig.debug
+++ linux-2.6.13/lib/Kconfig.debug
@@ -151,7 +151,7 @@ config DEBUG_FS
 
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
-	depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML)
+	depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML || SUPERH)
 	default y if DEBUG_INFO && UML
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
@@ -162,13 +162,13 @@ config FRAME_POINTER
 config WANT_EXTRA_DEBUG_INFORMATION
 	bool
 	select DEBUG_INFO
-	select FRAME_POINTER if X86 && !X86_64
+	select FRAME_POINTER if (X86 && !X86_64) || SUPERH
 	default n
 
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || MIPS32 || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (X86 || MIPS32 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
@@ -232,6 +232,12 @@ config KGDB_SIBYTE
 	bool "KGDB: On the Broadcom SWARM serial port"
 	depends on MIPS && SIBYTE_SB1xxx_SOC
 
+config KGDB_SH_SCI
+	bool "KGDB: On SH SCI(F) serial port"
+	depends on SUPERH && SERIAL_SH_SCI
+	help
+	  Uses the SCI(F) serial port found on the board.
+
 endchoice
 
 config KGDB_8250
@@ -255,7 +261,7 @@ config KGDB_SIMPLE_SERIAL
 
 choice
     	prompt "Debug serial port BAUD"
-	depends on KGDB_8250
+	depends on KGDB_8250 || KGDB_SH_SCI
 	default KGDB_115200BAUD
 	help
 	  gdb and the kernel stub need to agree on the baud rate to be
@@ -280,7 +286,7 @@ endchoice
 
 choice
 	prompt "Serial port for KGDB"
-	depends on KGDB_SIMPLE_SERIAL
+	depends on KGDB_8250 || KGDB_SH_SCI
 	default KGDB_PORT_0
 
 config KGDB_PORT_0

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

* [patch 10/16] Add support for ARM platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (7 preceding siblings ...)
  2005-08-29 16:10   ` [patch 09/16] Add support for SuperH " Tom Rini
@ 2005-08-29 16:10   ` Tom Rini
  2005-08-29 16:11   ` [patch 11/16] Add support for PowerPC64 " Tom Rini
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:10 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, rmk, dsaxena, gdavis, geoffrey.levand, nico


This adds a backend, written by Deepak Saxena <dsaxena@plexity.net> and George
Davis <gdavis@mvista.com> as well as support for the TI OMAP boards, ADI
Coyote, PXA2xx, and ARM Versatile.  Geoff Levand <geoffrey.levand@am.sony.com>
Nicolas Pitre, and Manish Lachwani have contributed various fixups here as
well.  This should only require (on boards that don't have a custom uart)
registering the uart with KGDB to add any other boards, or using kgdboe it
should Just Work.

---

 linux-2.6.13-trini/arch/arm/kernel/Makefile              |    1 
 linux-2.6.13-trini/arch/arm/kernel/kgdb-jmp.S            |   30 +
 linux-2.6.13-trini/arch/arm/kernel/kgdb.c                |  208 +++++++++++
 linux-2.6.13-trini/arch/arm/kernel/setup.c               |    5 
 linux-2.6.13-trini/arch/arm/kernel/traps.c               |   11 
 linux-2.6.13-trini/arch/arm/mach-ixp2000/core.c          |    5 
 linux-2.6.13-trini/arch/arm/mach-ixp2000/ixdp2x01.c      |    6 
 linux-2.6.13-trini/arch/arm/mach-ixp4xx/coyote-setup.c   |    5 
 linux-2.6.13-trini/arch/arm/mach-ixp4xx/ixdp425-setup.c  |   12 
 linux-2.6.13-trini/arch/arm/mach-omap1/board-osk.c       |    6 
 linux-2.6.13-trini/arch/arm/mach-omap1/serial.c          |    4 
 linux-2.6.13-trini/arch/arm/mach-pxa/Makefile            |    1 
 linux-2.6.13-trini/arch/arm/mach-pxa/kgdb-serial.c       |   98 +++++
 linux-2.6.13-trini/arch/arm/mach-versatile/kgdb_serial.c |  121 ++++++
 linux-2.6.13-trini/arch/arm/mm/extable.c                 |    7 
 linux-2.6.13-trini/drivers/serial/amba-pl011.c           |    2 
 linux-2.6.13-trini/include/asm-arm/kgdb.h                |   90 ++++
 linux-2.6.13-trini/include/asm-arm/system.h              |   41 ++
 linux-2.6.13-trini/lib/Kconfig.debug                     |   35 +
 19 files changed, 681 insertions(+), 7 deletions(-)

diff -puN /dev/null arch/arm/kernel/kgdb.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/kgdb.c	2005-08-10 16:27:32.000000000 -0700
@@ -0,0 +1,208 @@
+/*
+ * arch/arm/kernel/kgdb.c
+ *
+ * ARM KGDB support
+ *
+ * Copyright (c) 2002-2004 MontaVista Software, Inc
+ *
+ * Authors:  George Davis <davis_g@mvista.com>
+ *           Deepak Saxena <dsaxena@plexity.net>
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/personality.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+
+/* Make a local copy of the registers passed into the handler (bletch) */
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+{
+	int regno;
+
+	/* Initialize all to zero (??) */
+	for (regno = 0; regno < GDB_MAX_REGS; regno++)
+		gdb_regs[regno] = 0;
+
+	gdb_regs[_R0] = kernel_regs->ARM_r0;
+	gdb_regs[_R1] = kernel_regs->ARM_r1;
+	gdb_regs[_R2] = kernel_regs->ARM_r2;
+	gdb_regs[_R3] = kernel_regs->ARM_r3;
+	gdb_regs[_R4] = kernel_regs->ARM_r4;
+	gdb_regs[_R5] = kernel_regs->ARM_r5;
+	gdb_regs[_R6] = kernel_regs->ARM_r6;
+	gdb_regs[_R7] = kernel_regs->ARM_r7;
+	gdb_regs[_R8] = kernel_regs->ARM_r8;
+	gdb_regs[_R9] = kernel_regs->ARM_r9;
+	gdb_regs[_R10] = kernel_regs->ARM_r10;
+	gdb_regs[_FP] = kernel_regs->ARM_fp;
+	gdb_regs[_IP] = kernel_regs->ARM_ip;
+	gdb_regs[_SP] = kernel_regs->ARM_sp;
+	gdb_regs[_LR] = kernel_regs->ARM_lr;
+	gdb_regs[_PC] = kernel_regs->ARM_pc;
+	gdb_regs[_CPSR] = kernel_regs->ARM_cpsr;
+}
+
+/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+{
+	kernel_regs->ARM_r0 = gdb_regs[_R0];
+	kernel_regs->ARM_r1 = gdb_regs[_R1];
+	kernel_regs->ARM_r2 = gdb_regs[_R2];
+	kernel_regs->ARM_r3 = gdb_regs[_R3];
+	kernel_regs->ARM_r4 = gdb_regs[_R4];
+	kernel_regs->ARM_r5 = gdb_regs[_R5];
+	kernel_regs->ARM_r6 = gdb_regs[_R6];
+	kernel_regs->ARM_r7 = gdb_regs[_R7];
+	kernel_regs->ARM_r8 = gdb_regs[_R8];
+	kernel_regs->ARM_r9 = gdb_regs[_R9];
+	kernel_regs->ARM_r10 = gdb_regs[_R10];
+	kernel_regs->ARM_fp = gdb_regs[_FP];
+	kernel_regs->ARM_ip = gdb_regs[_IP];
+	kernel_regs->ARM_sp = gdb_regs[_SP];
+	kernel_regs->ARM_lr = gdb_regs[_LR];
+	kernel_regs->ARM_pc = gdb_regs[_PC];
+	kernel_regs->ARM_cpsr = gdb_regs[GDB_MAX_REGS - 1];
+}
+
+static inline struct pt_regs *kgdb_get_user_regs(struct task_struct *task)
+{
+	return (struct pt_regs *)
+	    ((unsigned long)task->thread_info + THREAD_SIZE -
+	     8 - sizeof(struct pt_regs));
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+				 struct task_struct *task)
+{
+	int regno;
+	struct pt_regs *thread_regs;
+
+	/* Just making sure... */
+	if (task == NULL)
+		return;
+
+	/* Initialize to zero */
+	for (regno = 0; regno < GDB_MAX_REGS; regno++)
+		gdb_regs[regno] = 0;
+
+	/* Otherwise, we have only some registers from switch_to() */
+	thread_regs = kgdb_get_user_regs(task);
+	gdb_regs[_R0] = thread_regs->ARM_r0;	/* Not really valid? */
+	gdb_regs[_R1] = thread_regs->ARM_r1;	/* "               " */
+	gdb_regs[_R2] = thread_regs->ARM_r2;	/* "               " */
+	gdb_regs[_R3] = thread_regs->ARM_r3;	/* "               " */
+	gdb_regs[_R4] = thread_regs->ARM_r4;
+	gdb_regs[_R5] = thread_regs->ARM_r5;
+	gdb_regs[_R6] = thread_regs->ARM_r6;
+	gdb_regs[_R7] = thread_regs->ARM_r7;
+	gdb_regs[_R8] = thread_regs->ARM_r8;
+	gdb_regs[_R9] = thread_regs->ARM_r9;
+	gdb_regs[_R10] = thread_regs->ARM_r10;
+	gdb_regs[_FP] = thread_regs->ARM_fp;
+	gdb_regs[_IP] = thread_regs->ARM_ip;
+	gdb_regs[_SP] = thread_regs->ARM_sp;
+	gdb_regs[_LR] = thread_regs->ARM_lr;
+	gdb_regs[_PC] = thread_regs->ARM_pc;
+	gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
+}
+
+static int compiled_break;
+
+int kgdb_arch_handle_exception(int exception_vector, int signo,
+			       int err_code, char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	long addr;
+	char *ptr;
+
+	switch (remcom_in_buffer[0]) {
+	case 'c':
+		kgdb_contthread = NULL;
+
+		/*
+		 * Try to read optional parameter, pc unchanged if no parm.
+		 * If this was a compiled breakpoint, we need to move
+		 * to the next instruction or we will just breakpoint
+		 * over and over again.
+		 */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->ARM_pc = addr;
+		} else if (compiled_break == 1) {
+			linux_regs->ARM_pc += 4;
+		}
+
+		compiled_break = 0;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
+{
+	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+	return 0;
+}
+
+static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
+{
+	compiled_break = 1;
+	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+	return 0;
+}
+
+static struct undef_hook kgdb_brkpt_hook = {
+	.instr_mask = 0xffffffff,
+	.instr_val = KGDB_BREAKINST,
+	.fn = kgdb_brk_fn
+};
+
+static struct undef_hook kgdb_compiled_brkpt_hook = {
+	.instr_mask = 0xffffffff,
+	.instr_val = KGDB_COMPILED_BREAK,
+	.fn = kgdb_compiled_brk_fn
+};
+
+/*
+ * Register our undef instruction hooks with ARM undef core.
+ * We regsiter a hook specifically looking for the KGB break inst
+ * and we handle the normal undef case within the do_undefinstr
+ * handler.
+ */
+int kgdb_arch_init(void)
+{
+	register_undef_hook(&kgdb_brkpt_hook);
+	register_undef_hook(&kgdb_compiled_brkpt_hook);
+
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+#ifndef __ARMEB__
+	.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
+#else
+	.gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe}
+#endif
+};
diff -puN /dev/null arch/arm/kernel/kgdb-jmp.S
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/kgdb-jmp.S	2005-08-10 16:27:32.000000000 -0700
@@ -0,0 +1,30 @@
+/*
+ * arch/arm/kernel/kgdb-jmp.S
+ *
+ * Trivial setjmp and longjmp procedures to support bus error recovery
+ * which may occur during kgdb memory read/write operations.
+ *
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ *         source@mvista.com
+ *
+ * 2002-2005 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2. This program as licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+#include <linux/linkage.h>
+
+ENTRY (kgdb_fault_setjmp)
+	/* Save registers */
+	stmia	r0, {r0-r14}
+	str	lr,[r0, #60]
+	mrs	r1,cpsr
+	str	r1,[r0,#64]
+	ldr	r1,[r0,#4]
+	mov	r0, #0
+	mov	pc,lr
+
+ENTRY (kgdb_fault_longjmp)
+	/* Restore registers */
+	mov	r1,#1
+	str	r1,[r0]
+	ldmia	r0,{r0-pc}^
diff -puN arch/arm/kernel/Makefile~arm-lite arch/arm/kernel/Makefile
--- linux-2.6.13/arch/arm/kernel/Makefile~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/Makefile	2005-08-10 16:27:32.000000000 -0700
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARTHUR)		+= arthur.o
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o
 obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
diff -puN arch/arm/kernel/setup.c~arm-lite arch/arm/kernel/setup.c
--- linux-2.6.13/arch/arm/kernel/setup.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/setup.c	2005-08-10 16:27:32.000000000 -0700
@@ -785,6 +785,11 @@ void __init setup_arch(char **cmdline_p)
 	conswitchp = &dummy_con;
 #endif
 #endif
+
+#if	defined(CONFIG_KGDB)
+	extern void __init early_trap_init(void);
+	early_trap_init();
+#endif
 }
 
 
diff -puN arch/arm/kernel/traps.c~arm-lite arch/arm/kernel/traps.c
--- linux-2.6.13/arch/arm/kernel/traps.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/traps.c	2005-08-10 16:27:32.000000000 -0700
@@ -270,6 +270,7 @@ asmlinkage void do_undefinstr(struct pt_
 	unsigned int instr;
 	struct undef_hook *hook;
 	siginfo_t info;
+	mm_segment_t fs;
 	void __user *pc;
 
 	/*
@@ -279,12 +280,15 @@ asmlinkage void do_undefinstr(struct pt_
 	 */
 	regs->ARM_pc -= correction;
 
+	fs = get_fs();
+	set_fs(KERNEL_DS);
 	pc = (void __user *)instruction_pointer(regs);
 	if (thumb_mode(regs)) {
 		get_user(instr, (u16 __user *)pc);
 	} else {
 		get_user(instr, (u32 __user *)pc);
 	}
+	set_fs(fs);
 
 	spin_lock_irq(&undef_lock);
 	list_for_each_entry(hook, &undef_hook, node) {
@@ -667,6 +671,13 @@ EXPORT_SYMBOL(abort);
 
 void __init trap_init(void)
 {
+#if	defined(CONFIG_KGDB)
+	return;
+}
+
+void __init early_trap_init(void)
+{
+#endif
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
 	extern char __kuser_helper_start[], __kuser_helper_end[];
diff -puN arch/arm/mach-ixp2000/core.c~arm-lite arch/arm/mach-ixp2000/core.c
--- linux-2.6.13/arch/arm/mach-ixp2000/core.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-ixp2000/core.c	2005-08-10 16:27:32.000000000 -0700
@@ -35,6 +35,7 @@
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#include <asm/kgdb.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -145,6 +146,10 @@ void __init ixp2000_map_io(void)
 
 	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
 
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &ixp2000_serial_port);
+#endif
+
 	/* Set slowport to 8-bit mode.  */
 	ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1);
 }
diff -puN arch/arm/mach-ixp2000/ixdp2x01.c~arm-lite arch/arm/mach-ixp2000/ixdp2x01.c
--- linux-2.6.13/arch/arm/mach-ixp2000/ixdp2x01.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-ixp2000/ixdp2x01.c	2005-08-10 16:27:32.000000000 -0700
@@ -38,6 +38,7 @@
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
+#include <asm/kgdb.h>
 
 #include <asm/mach/pci.h>
 #include <asm/mach/map.h>
@@ -175,6 +176,11 @@ static void __init ixdp2x01_map_io(void)
 
 	early_serial_setup(&ixdp2x01_serial_ports[0]);
 	early_serial_setup(&ixdp2x01_serial_ports[1]);
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &ixdp2x01_serial_ports[0]);
+	kgdb8250_add_port(1, &ixdp2x01_serial_ports[1]);
+#endif
 }
 
 
diff -puN arch/arm/mach-ixp4xx/coyote-setup.c~arm-lite arch/arm/mach-ixp4xx/coyote-setup.c
--- linux-2.6.13/arch/arm/mach-ixp4xx/coyote-setup.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-ixp4xx/coyote-setup.c	2005-08-10 16:27:32.000000000 -0700
@@ -96,9 +96,12 @@ static void __init coyote_init(void)
 		coyote_uart_data[0].irq = IRQ_IXP4XX_UART1;
 	}
 
-
 	ixp4xx_sys_init();
 	platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices));
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &coyote_serial_port);
+#endif
 }
 
 #ifdef CONFIG_ARCH_ADI_COYOTE
diff -puN arch/arm/mach-ixp4xx/ixdp425-setup.c~arm-lite arch/arm/mach-ixp4xx/ixdp425-setup.c
--- linux-2.6.13/arch/arm/mach-ixp4xx/ixdp425-setup.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-ixp4xx/ixdp425-setup.c	2005-08-10 16:27:32.000000000 -0700
@@ -23,6 +23,7 @@
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
+#include <asm/kgdb.h>
 
 void __init ixdp425_map_io(void) 
 {
@@ -82,7 +83,8 @@ static struct plat_serial8250_port ixdp4
 		.mapbase	= IXP4XX_UART1_BASE_PHYS,
 		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
 		.irq		= IRQ_IXP4XX_UART1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+					UPF_SHARE_IRQ,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= IXP4XX_UART_XTAL,
@@ -91,7 +93,8 @@ static struct plat_serial8250_port ixdp4
 		.mapbase	= IXP4XX_UART2_BASE_PHYS,
 		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
 		.irq		= IRQ_IXP4XX_UART1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+					UPF_SHARE_IRQ,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= IXP4XX_UART_XTAL,
@@ -126,6 +129,11 @@ static void __init ixdp425_init(void)
 	}
 
 	platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices));
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_port(0, &ixdp425_serial_ports[0]);
+	kgdb8250_add_port(1, &ixdp425_serial_ports[1]);
+#endif
 }
 
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
diff -puN arch/arm/mach-omap1/board-osk.c~arm-lite arch/arm/mach-omap1/board-osk.c
--- linux-2.6.13/arch/arm/mach-omap1/board-osk.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-omap1/board-osk.c	2005-08-10 16:27:32.000000000 -0700
@@ -41,12 +41,14 @@
 #include <asm/arch/tc.h>
 #include <asm/arch/common.h>
 
+#if 0
 static struct map_desc osk5912_io_desc[] __initdata = {
 { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
 	MT_DEVICE },
 };
+#endif
 
-static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
+static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
 static struct resource osk5912_smc91x_resources[] = {
 	[0] = {
@@ -153,7 +155,7 @@ static void __init osk_init(void)
 static void __init osk_map_io(void)
 {
 	omap_map_common_io();
-	iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
+	//iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
 	omap_serial_init(osk_serial_ports);
 }
 
diff -puN arch/arm/mach-omap1/serial.c~arm-lite arch/arm/mach-omap1/serial.c
--- linux-2.6.13/arch/arm/mach-omap1/serial.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-omap1/serial.c	2005-08-10 16:27:32.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
+#include <linux/kgdb.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 
@@ -190,6 +191,9 @@ void __init omap_serial_init(int ports[O
 			break;
 		}
 		omap_serial_reset(&serial_platform_data[i]);
+#ifdef CONFIG_KGDB_8250
+		kgdb8250_add_platform_port(i, &serial_platform_data[i]);
+#endif
 	}
 }
 
diff -puN /dev/null arch/arm/mach-pxa/kgdb-serial.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-pxa/kgdb-serial.c	2005-08-10 16:27:32.000000000 -0700
@@ -0,0 +1,98 @@
+/*
+ * linux/arch/arm/mach-pxa/kgdb-serial.c
+ *
+ * Provides low level kgdb serial support hooks for PXA2xx boards
+ *
+ * Author:	Nicolas Pitre
+ * Copyright:	(C) 2002-2005 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/serial_reg.h>
+#include <linux/kgdb.h>
+#include <asm/processor.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#if   defined(CONFIG_KGDB_PXA_FFUART)
+
+#define UART		FFUART
+#define CKEN_UART	CKEN6_FFUART
+#define GPIO_RX_MD	GPIO34_FFRXD_MD
+#define GPIO_TX_MD	GPIO39_FFTXD_MD
+
+#elif defined(CONFIG_KGDB_PXA_BTUART)
+
+#define UART		BTUART
+#define CKEN_UART	CKEN7_BTUART
+#define GPIO_RX_MD	GPIO42_BTRXD_MD
+#define GPIO_TX_MD	GPIO43_BTTXD_MD
+
+#elif defined(CONFIG_KGDB_PXA_STUART)
+
+#define UART		STUART
+#define CKEN_UART	CKEN5_STUART
+#define GPIO_RX_MD	GPIO46_STRXD_MD
+#define GPIO_TX_MD	GPIO47_STTXD_MD
+
+#endif
+
+#define UART_BAUDRATE	(CONFIG_KGDB_PXA_BAUDRATE)
+
+static volatile unsigned long *port = (unsigned long *)&UART;
+
+static int kgdb_serial_init(void)
+{
+	pxa_set_cken(CKEN_UART, 1);
+	pxa_gpio_mode(GPIO_RX_MD);
+	pxa_gpio_mode(GPIO_TX_MD);
+
+	port[UART_IER] = 0;
+	port[UART_LCR] = LCR_DLAB;
+	port[UART_DLL] = ((921600 / UART_BAUDRATE) & 0xff);
+	port[UART_DLM] = ((921600 / UART_BAUDRATE) >> 8);
+	port[UART_LCR] = LCR_WLS1 | LCR_WLS0;
+	port[UART_MCR] = 0;
+	port[UART_IER] = IER_UUE;
+	port[UART_FCR] = FCR_ITL_16;
+
+	return 0;
+}
+
+static void kgdb_serial_putchar(int c)
+{
+	if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE)
+		kgdb_serial_init();
+	while (!(port[UART_LSR] & LSR_TDRQ))
+		cpu_relax();
+	port[UART_TX] = c;
+}
+
+static void kgdb_serial_flush(void)
+{
+	if ((CKEN & CKEN_UART) && (port[UART_IER] & IER_UUE))
+		while (!(port[UART_LSR] & LSR_TEMT))
+			cpu_relax();
+}
+
+static int kgdb_serial_getchar(void)
+{
+	unsigned char c;
+	if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE)
+		kgdb_serial_init();
+	while (!(port[UART_LSR] & UART_LSR_DR))
+		cpu_relax();
+	c = port[UART_RX];
+	return c;
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.init = kgdb_serial_init,
+	.write_char = kgdb_serial_putchar,
+	.flush = kgdb_serial_flush,
+	.read_char = kgdb_serial_getchar,
+};
diff -puN arch/arm/mach-pxa/Makefile~arm-lite arch/arm/mach-pxa/Makefile
--- linux-2.6.13/arch/arm/mach-pxa/Makefile~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-pxa/Makefile	2005-08-10 16:27:32.000000000 -0700
@@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS) += $(led-y)
 
 # Misc features
 obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_KGDB_PXA_SERIAL) += kgdb-serial.o
 
 ifeq ($(CONFIG_PXA27x),y)
 obj-$(CONFIG_PM) += standby.o
diff -puN /dev/null arch/arm/mach-versatile/kgdb_serial.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/arm/mach-versatile/kgdb_serial.c	2005-08-10 16:27:32.000000000 -0700
@@ -0,0 +1,121 @@
+/*
+ * arch/arm/mach-versatile/kgdb_serial.c
+ *
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ *
+ * 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.
+ *
+ * Support for KGDB on ARM Versatile.
+ */
+#include <linux/config.h>
+#include <linux/serial_reg.h>
+#include <linux/kgdb.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/hardware.h>
+#include <asm/hardware/amba_serial.h>
+#include <asm/arch-versatile/hardware.h>
+
+#define ARM_BAUD_38400		23
+/*
+ * Functions that will be used later
+ */
+#define UART_GET_INT_STATUS(p)	readb((p) + UART010_IIR)
+#define UART_GET_MIS(p)		readw((p) + UART011_MIS)
+#define UART_PUT_ICR(p, c)	writel((c), (p) + UART010_ICR)
+#define UART_GET_FR(p)		readb((p) + UART01x_FR)
+#define UART_GET_CHAR(p)	readb((p) + UART01x_DR)
+#define UART_PUT_CHAR(p, c)     writel((c), (p) + UART01x_DR)
+#define UART_GET_RSR(p)		readb((p) + UART01x_RSR)
+#define UART_GET_CR(p)		readb((p) + UART010_CR)
+#define UART_PUT_CR(p,c)        writel((c), (p) + UART010_CR)
+#define UART_GET_LCRL(p)	readb((p) + UART010_LCRL)
+#define UART_PUT_LCRL(p,c)	writel((c), (p) + UART010_LCRL)
+#define UART_GET_LCRM(p)        readb((p) + UART010_LCRM)
+#define UART_PUT_LCRM(p,c)	writel((c), (p) + UART010_LCRM)
+#define UART_GET_LCRH(p)	readb((p) + UART010_LCRH)
+#define UART_PUT_LCRH(p,c)	writel((c), (p) + UART010_LCRH)
+#define UART_RX_DATA(s)		(((s) & UART01x_FR_RXFE) == 0)
+#define UART_TX_READY(s)	(((s) & UART01x_FR_TXFF) == 0)
+#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & UART01x_FR_TMSK) == 0)
+
+/*
+ * KGDB IRQ
+ */
+static int kgdb_irq = 12;
+static volatile unsigned char *port = NULL;
+
+static int kgdb_serial_init(void)
+{
+	int rate = ARM_BAUD_38400;
+
+	port = IO_ADDRESS(0x101F1000);
+	UART_PUT_CR(port, 0);
+
+	/* Set baud rate */
+	UART_PUT_LCRM(port, ((rate & 0xf00) >> 8));
+	UART_PUT_LCRL(port, (rate & 0xff));
+	UART_PUT_LCRH(port, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN);
+	UART_PUT_CR(port, UART01x_CR_UARTEN);
+
+	return 0;
+}
+
+static void kgdb_serial_putchar(int ch)
+{
+	unsigned int status;
+
+	do {
+		status = UART_GET_FR(port);
+	} while (!UART_TX_READY(status));
+
+	UART_PUT_CHAR(port, ch);
+}
+
+static int kgdb_serial_getchar(void)
+{
+	unsigned int status;
+	int ch;
+
+	do {
+		status = UART_GET_FR(port);
+	} while (!UART_RX_DATA(status));
+	ch = UART_GET_CHAR(port);
+	return ch;
+}
+
+static struct uart_port kgdb_amba_port = {
+	.irq = 12,
+	.iobase = 0,
+	.iotype = UPIO_MEM,
+	.membase = (unsigned char *)IO_ADDRESS(0x101F1000),
+};
+
+static irqreturn_t kgdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int status = UART_GET_MIS(port);
+
+	if (irq != kgdb_irq)
+		return IRQ_NONE;
+
+	if (status & 0x40)
+		breakpoint();
+
+	return IRQ_HANDLED;
+}
+
+static void __init kgdb_hookup_irq(void)
+{
+	request_irq(kgdb_irq, kgdb_interrupt, SA_SHIRQ, "GDB-stub",
+		    &kgdb_amba_port);
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.init = kgdb_serial_init,
+	.write_char = kgdb_serial_putchar,
+	.read_char = kgdb_serial_getchar,
+	.late_init = kgdb_hookup_irq,
+};
diff -puN arch/arm/mm/extable.c~arm-lite arch/arm/mm/extable.c
--- linux-2.6.13/arch/arm/mm/extable.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/mm/extable.c	2005-08-10 16:27:32.000000000 -0700
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/extable.c
  */
 #include <linux/module.h>
+#include <linux/kgdb.h>
 #include <asm/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
@@ -11,6 +12,12 @@ int fixup_exception(struct pt_regs *regs
 	fixup = search_exception_tables(instruction_pointer(regs));
 	if (fixup)
 		regs->ARM_pc = fixup->fixup;
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+#endif
 
 	return fixup != NULL;
 }
diff -puN drivers/serial/amba-pl011.c~arm-lite drivers/serial/amba-pl011.c
--- linux-2.6.13/drivers/serial/amba-pl011.c~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/drivers/serial/amba-pl011.c	2005-08-10 16:27:32.000000000 -0700
@@ -350,7 +350,7 @@ static int pl011_startup(struct uart_por
 	/*
 	 * Allocate the IRQ
 	 */
-	retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+	retval = request_irq(uap->port.irq, pl011_int, SA_SHIRQ, "uart-pl011", uap);
 	if (retval)
 		goto clk_dis;
 
diff -puN drivers/serial/kgdb_8250.c~arm-lite drivers/serial/kgdb_8250.c
diff -puN /dev/null include/asm-arm/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-arm/kgdb.h	2005-08-12 08:26:09.000000000 -0700
@@ -0,0 +1,90 @@
+/*
+ * include/asm-arm/kgdb.h
+ *
+ * ARM KGDB support
+ *
+ * Author: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ *
+ */
+
+#ifndef __ASM_KGDB_H__
+#define __ASM_KGDB_H__
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+
+
+/*
+ * GDB assumes that we're a user process being debugged, so
+ * it will send us an SWI command to write into memory as the
+ * debug trap. When an SWI occurs, the next instruction addr is
+ * placed into R14_svc before jumping to the vector trap.
+ * This doesn't work for kernel debugging as we are already in SVC
+ * we would loose the kernel's LR, which is a bad thing. This
+ * is  bad thing.
+ *
+ * By doing this as an undefined instruction trap, we force a mode
+ * switch from SVC to UND mode, allowing us to save full kernel state.
+ *
+ * We also define a KGDB_COMPILED_BREAK which can be used to compile
+ * in breakpoints. This is important for things like sysrq-G and for
+ * the initial breakpoint from trap_init().
+ *
+ * Note to ARM HW designers: Add real trap support like SH && PPC to
+ * make our lives much much simpler. :)
+ */
+#define	BREAK_INSTR_SIZE		4
+#define GDB_BREAKINST                   0xef9f0001
+#define KGDB_BREAKINST                  0xe7ffdefe
+#define KGDB_COMPILED_BREAK             0xe7ffdeff
+#define CACHE_FLUSH_IS_SAFE		1
+
+#ifndef	__ASSEMBLY__
+
+#define	BREAKPOINT()			asm(".word 	0xe7ffdeff")
+
+
+extern void kgdb_handle_bus_error(void);
+extern int kgdb_fault_expected;
+
+/*
+ * From Amit S. Kale:
+ *
+ * In the register packet, words 0-15 are R0 to R10, FP, IP, SP, LR, PC. But
+ * Register 16 isn't cpsr. GDB passes CPSR in word 25. There are 9 words in
+ * between which are unused. Passing only 26 words to gdb is sufficient.
+ * GDB can figure out that floating point registers are not passed.
+ * GDB_MAX_REGS should be 26.
+ */
+#define	GDB_MAX_REGS		(26)
+
+#define	KGDB_MAX_NO_CPUS	1
+#define	BUFMAX			400
+#define	NUMREGBYTES		(GDB_MAX_REGS << 2)
+#define	NUMCRITREGBYTES		(32 << 2)
+#define	CHECK_EXCEPTION_STACK()	1
+
+#define	_R0		0
+#define	_R1		1
+#define	_R2		2
+#define	_R3		3
+#define	_R4		4
+#define	_R5		5
+#define	_R6		6
+#define	_R7		7
+#define	_R8		8
+#define	_R9		9
+#define	_R10		10
+#define	_FP		11
+#define	_IP		12
+#define	_SP		13
+#define	_LR		14
+#define	_PC		15
+#define	_CPSR		(GDB_MAX_REGS - 1)
+
+#define	CHECK_EXCEPTION_STACK()	1
+
+#endif // !__ASSEMBLY__
+#endif // __ASM_KGDB_H__
diff -puN include/asm-arm/system.h~arm-lite include/asm-arm/system.h
--- linux-2.6.13/include/asm-arm/system.h~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/include/asm-arm/system.h	2005-08-10 16:27:32.000000000 -0700
@@ -405,6 +405,47 @@ static inline unsigned long __xchg(unsig
 	return ret;
 }
 
+#define	__HAVE_ARCH_CMPXCHG	1
+
+#include <asm/types.h>
+
+static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
+					unsigned long new)
+{
+	u32 retval;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	retval = *m;
+	if (retval == old)
+		*m = new;
+	local_irq_restore(flags);	/* implies memory barrier  */
+
+	return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+	unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
 #endif /* __ASSEMBLY__ */
 
 #define arch_align_stack(x) (x)
diff -puN lib/Kconfig.debug~arm-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~arm-lite	2005-08-10 16:27:32.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-12 08:26:10.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || MIPS32 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (ARM || X86 || MIPS32 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
@@ -189,8 +189,10 @@ choice
 	prompt "Method for KGDB communication"
 	depends on KGDB
 	default KGDB_8250_NOMODULE
+	default KGDB_ARM_VERSATILE if ARCH_VERSATILE
 	default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC
 	default KGDB_MPSC if SERIAL_MPSC
+	default KGDB_PXA_SERIAL if ARCH_PXA
 	help
 	  There are a number of different ways in which you can communicate
 	  with KGDB.  The most common is via serial, with the 8250 driver
@@ -227,6 +229,16 @@ config KGDB_SIBYTE
 	bool "KGDB: On the Broadcom SWARM serial port"
 	depends on MIPS && SIBYTE_SB1xxx_SOC
 
+config KGDB_ARM_VERSATILE
+	bool "KGDB: On ARM Versatile"
+	depends on ARM && ARCH_VERSATILE
+	help
+	  Enables the KGDB serial driver for the ARM Versatile
+
+config KGDB_PXA_SERIAL
+	bool "KGDB: On the PXA2xx serial port"
+	depends on ARCH_PXA
+
 config KGDB_SH_SCI
 	bool "KGDB: On SH SCI(F) serial port"
 	depends on SUPERH && SERIAL_SH_SCI
@@ -297,6 +309,27 @@ config KGDB_PORT_3
 	bool "Third serial port"
 endchoice
 
+choice
+	prompt "PXA serial UART for KGDB"
+	depends on KGDB_PXA_SERIAL
+	default KGDB_PXA_FFUART
+
+config KGDB_PXA_FFUART
+	bool "FFUART"
+
+config KGDB_PXA_BTUART
+	bool "BTUART"
+
+config KGDB_PXA_STUART
+	bool "STUART"
+
+endchoice
+
+config KGDB_PXA_BAUDRATE
+	int "UART baudrate for KGDB"
+	depends on KGDB_PXA_SERIAL
+	default "115200"
+
 config KGDB_PORT
 	hex "hex I/O port address of the debug serial port"
 	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
_

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

* [patch 11/16] Add support for PowerPC64 platforms to KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (8 preceding siblings ...)
  2005-08-29 16:10   ` [patch 10/16] Add support for ARM " Tom Rini
@ 2005-08-29 16:11   ` Tom Rini
  2005-08-29 16:11   ` [patch 12/16] KGDBoE I/O driver Tom Rini
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, frowand, paulus


This adds basic KGDB support to ppc64, and support for kgdb8250 on the 'Maple'
board.  All of this was done by Frank Rowand (who is on vacation right now,
but I'll try and answer for him).  This should work on any ppc64 board via
kgdboe, so long as there is an eth driver that supports netpoll.  At the
moment this is mutually exclusive with XMON.  It is probably possible to allow
them to be chained, but that sounds dangerous to me.  This is similar to
ppc32, but ppc32 does not explicitly test.

---

 linux-2.6.13-trini/arch/ppc64/Kconfig.debug        |   14 
 linux-2.6.13-trini/arch/ppc64/kernel/Makefile      |    3 
 linux-2.6.13-trini/arch/ppc64/kernel/kgdb.c        |  422 +++++++++++++++++
 linux-2.6.13-trini/arch/ppc64/kernel/maple_setup.c |    5 
 linux-2.6.13-trini/arch/ppc64/kernel/setup.c       |   14 
 linux-2.6.13-trini/arch/ppc64/mm/fault.c           |    8 
 linux-2.6.13-trini/include/asm-ppc64/kgdb.h        |   55 ++
 linux-2.6.13-trini/lib/Kconfig.debug               |    2 
 8 files changed, 513 insertions(+), 10 deletions(-)

diff -puN arch/ppc64/Kconfig.debug~ppc64-lite arch/ppc64/Kconfig.debug
--- linux-2.6.13/arch/ppc64/Kconfig.debug~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/ppc64/Kconfig.debug	2005-08-08 19:16:03.000000000 -0700
@@ -28,16 +28,9 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
-config DEBUGGER
-	bool "Enable debugger hooks"
-	depends on DEBUG_KERNEL
-	help
-	  Include in-kernel hooks for kernel debuggers. Unless you are
-	  intending to debug the kernel, say N here.
-
 config XMON
 	bool "Include xmon kernel debugger"
-	depends on DEBUGGER && !PPC_ISERIES
+	depends on DEBUG_KERNEL && !PPC_ISERIES
 	help
 	  Include in-kernel hooks for the xmon kernel monitor/debugger.
 	  Unless you are intending to debug the kernel, say N here.
@@ -46,6 +39,11 @@ config XMON_DEFAULT
 	bool "Enable xmon by default"
 	depends on XMON
 
+config DEBUGGER
+	bool
+	depends on KGDB || XMON
+	default y
+
 config PPCDBG
 	bool "Include PPCDBG realtime debugging"
 	depends on DEBUG_KERNEL
diff -puN /dev/null arch/ppc64/kernel/kgdb.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/arch/ppc64/kernel/kgdb.c	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,422 @@
+/*
+ * arch/ppc64/kernel/kgdb.c
+ *
+ * PowerPC64 backend to the KGDB stub.
+ *
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * Copied from arch/ppc/kernel/kgdb.c, updated for ppc64
+ *
+ * Copyright (C) 1996 Paul Mackerras (setjmp/longjmp)
+ * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
+ * Copyright (C) 2003 Timesys Corporation.
+ * 2004 (c) MontaVista Software, Inc.
+ * 2005 (c) MontaVista Software, Inc.
+ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <asm/current.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+
+/*
+ * This table contains the mapping between PowerPC64 hardware trap types, and
+ * signals, which are primarily what GDB understands.  GDB and the kernel
+ * don't always agree on values, so we use constants taken from gdb-6.2.
+ */
+static struct hard_trap_info
+{
+	unsigned int tt;		/* Trap type code for powerpc */
+	unsigned char signo;		/* Signal that we map this trap into */
+} hard_trap_info[] = {
+	{ 0x0100, 0x02 /* SIGINT */  },		/* system reset */
+	{ 0x0200, 0x0b /* SIGSEGV */ },		/* machine check */
+	{ 0x0300, 0x0b /* SIGSEGV */ },		/* data access */
+	{ 0x0400, 0x0a /* SIGBUS */  },		/* instruction access */
+	{ 0x0480, 0x0a /* SIGBUS */  },		/* instruction segment */
+	{ 0x0500, 0x02 /* SIGINT */  },		/* interrupt */
+	{ 0x0600, 0x0a /* SIGBUS */  },		/* alignment */
+	{ 0x0700, 0x04 /* SIGILL */  },		/* program */
+	{ 0x0800, 0x08 /* SIGFPE */  },		/* fpu unavailable */
+	{ 0x0900, 0x0e /* SIGALRM */  },	/* decrementer */
+	{ 0x0a00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0b00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0c00, 0x14 /* SIGCHLD */ },		/* syscall */
+	{ 0x0d00, 0x05 /* SIGTRAP */  },	/* single step */
+	{ 0x0e00, 0x04 /* SIGILL */  },		/* reserved */
+	{ 0x0f00, 0x04 /* SIGILL */  },		/* performance monitor */
+	{ 0x0f20, 0x08 /* SIGFPE */  },		/* altivec unavailable */
+	{ 0x1300, 0x05 /* SIGTRAP */  },	/* instruction address break */
+	{ 0x1500, 0x04 /* SIGILL */  },		/* soft patch */
+	{ 0x1600, 0x04 /* SIGILL */  },		/* maintenance */
+	{ 0x1700, 0x04 /* SIGILL */  },		/* altivec assist */
+	{ 0x1800, 0x04 /* SIGILL */  },		/* thermal */
+	{ 0x2002, 0x05 /* SIGTRAP */},		/* debug */
+	{ 0x0000, 0x000 }			/* Must be last */
+};
+
+extern atomic_t cpu_doing_single_step;
+
+static int computeSignal(unsigned int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;		/* default for things we don't know about */
+}
+
+void kgdb_call_nmi_hook(void *ignored)
+{
+	kgdb_nmihook(smp_processor_id(), (void *)0);
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	local_irq_restore(flags);
+	smp_call_function(kgdb_call_nmi_hook, 0, 0, 0);
+	local_irq_save(flags);
+}
+
+/* KGDB functions to use existing PowerPC64 hooks. */
+static int kgdb_debugger(struct pt_regs *regs)
+{
+	return kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+}
+
+static int kgdb_breakpoint(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+
+	if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
+		regs->nip += 4;
+
+	return 1;
+}
+
+static int kgdb_singlestep(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+	return 1;
+}
+
+int kgdb_iabr_match(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+	return 1;
+}
+
+int kgdb_dabr_match(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		return 0;
+
+	kgdb_handle_exception(0, computeSignal(regs->trap), 0, regs);
+	return 1;
+}
+
+#define PACK64(ptr,src) do { *(ptr++) = (src); } while(0)
+
+#define PACK32(ptr,src) do {          \
+	u32 *ptr32;                   \
+	ptr32 = (u32 *)ptr;           \
+	*(ptr32++) = (src);           \
+	ptr = (unsigned long *)ptr32; \
+	} while(0)
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg;
+	unsigned long *ptr = gdb_regs;
+
+	memset(gdb_regs, 0, NUMREGBYTES);
+
+	for (reg = 0; reg < 32; reg++)
+		PACK64(ptr, regs->gpr[reg]);
+
+	/* fp registers not used by kernel, leave zero */
+	ptr += 32;
+
+	PACK64(ptr, regs->nip);
+	PACK64(ptr, regs->msr);
+	PACK32(ptr, regs->ccr);
+	PACK64(ptr, regs->link);
+	PACK64(ptr, regs->ctr);
+	PACK32(ptr, regs->xer);
+
+#if 0
+	Following are in struct thread_struct, not struct pt_regs,
+	ignoring for now since kernel does not use them.  Would it
+	make sense to get them from the thread that kgdb is set to?
+
+	If this code is enabled, update the definition of NUMREGBYTES to
+	include the vector registers and vector state registers.
+
+	PACK32(ptr, p->thread->fpscr);
+
+	/* vr registers not used by kernel, leave zero */
+	ptr += 64;
+
+	PACK32(ptr, p->thread->vscr);
+	PACK32(ptr, p->thread->vrsave);
+#else
+	/* fpscr not used by kernel, leave zero */
+	PACK32(ptr, 0);
+#endif
+
+	BUG_ON((unsigned long)ptr >
+	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
+						  STACK_FRAME_OVERHEAD);
+	int reg;
+	unsigned long *ptr = gdb_regs;
+
+	memset(gdb_regs, 0, NUMREGBYTES);
+
+	/* Regs GPR0-2 */
+	for (reg = 0; reg < 3; reg++)
+		PACK64(ptr, regs->gpr[reg]);
+
+	/* Regs GPR3-13 are caller saved, not in regs->gpr[] */
+	for (reg = 3; reg < 14; reg++)
+		PACK64(ptr, 0);
+
+	/* Regs GPR14-31 */
+	for (reg = 14; reg < 32; reg++)
+		PACK64(ptr, regs->gpr[reg]);
+
+	/* fp registers not used by kernel, leave zero */
+	ptr += 32;
+
+	PACK64(ptr, regs->nip);
+	PACK64(ptr, regs->msr);
+	PACK32(ptr, regs->ccr);
+	PACK64(ptr, regs->link);
+	PACK64(ptr, regs->ctr);
+	PACK32(ptr, regs->xer);
+
+#if 0
+	Following are in struct thread_struct, not struct pt_regs,
+	ignoring for now since kernel does not use them.  Would it
+	make sense to get them from the thread that kgdb is set to?
+
+	If this code is enabled, update the definition of NUMREGBYTES to
+	include the vector registers and vector state registers.
+
+	PACK32(ptr, p->thread->fpscr);
+
+	/* vr registers not used by kernel, leave zero */
+	ptr += 64;
+
+	PACK32(ptr, p->thread->vscr);
+	PACK32(ptr, p->thread->vrsave);
+#else
+	/* fpscr not used by kernel, leave zero */
+	PACK32(ptr, 0);
+#endif
+
+	BUG_ON((unsigned long)ptr >
+	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+#define UNPACK64(dest,ptr) do { dest = *(ptr++); } while(0)
+
+#define UNPACK32(dest,ptr) do {       \
+	u32 *ptr32;                   \
+	ptr32 = (u32 *)ptr;           \
+	dest = *(ptr32++);            \
+	ptr = (unsigned long *)ptr32; \
+	} while(0)
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int reg;
+	unsigned long *ptr = gdb_regs;
+
+	for (reg = 0; reg < 32; reg++)
+		UNPACK64(regs->gpr[reg], ptr);
+
+	/* fp registers not used by kernel, leave zero */
+	ptr += 32;
+
+	UNPACK64(regs->nip, ptr);
+	UNPACK64(regs->msr, ptr);
+	UNPACK32(regs->ccr, ptr);
+	UNPACK64(regs->link, ptr);
+	UNPACK64(regs->ctr, ptr);
+	UNPACK32(regs->xer, ptr);
+
+#if 0
+	Following are in struct thread_struct, not struct pt_regs,
+	ignoring for now since kernel does not use them.  Would it
+	make sense to get them from the thread that kgdb is set to?
+
+	If this code is enabled, update the definition of NUMREGBYTES to
+	include the vector registers and vector state registers.
+
+	/* fpscr, vscr, vrsave not used by kernel, leave unchanged */
+
+	UNPACK32(p->thread->fpscr, ptr);
+
+	/* vr registers not used by kernel, leave zero */
+	ptr += 64;
+
+	UNPACK32(p->thread->vscr, ptr);
+	UNPACK32(p->thread->vrsave, ptr);
+#endif
+
+	BUG_ON((unsigned long)ptr >
+	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+/*
+ * This function does PowerPC64 specific procesing for interfacing to gdb.
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+			       char *remcom_in_buffer, char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	char *ptr = &remcom_in_buffer[1];
+	unsigned long addr;
+
+	switch (remcom_in_buffer[0]) {
+		/*
+		 * sAA..AA   Step one instruction from AA..AA
+		 * This will return an error to gdb ..
+		 */
+	case 's':
+	case 'c':
+		/* handle the optional parameter */
+		if (kgdb_hex2long(&ptr, &addr))
+			linux_regs->nip = addr;
+
+		atomic_set(&cpu_doing_single_step, -1);
+		/* set the trace bit if we're stepping */
+		if (remcom_in_buffer[0] == 's') {
+			linux_regs->msr |= MSR_SE;
+			debugger_step = 1;
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
+int kgdb_fault_setjmp(unsigned long *curr_context)
+{
+	__asm__ __volatile__("mflr 0; std 0,0(%0)\n\
+			      std	1,8(%0)\n\
+			      std	2,16(%0)\n\
+			      mfcr 0; std 0,24(%0)\n\
+			      std	13,32(%0)\n\
+			      std	14,40(%0)\n\
+			      std	15,48(%0)\n\
+			      std	16,56(%0)\n\
+			      std	17,64(%0)\n\
+			      std	18,72(%0)\n\
+			      std	19,80(%0)\n\
+			      std	20,88(%0)\n\
+			      std	21,96(%0)\n\
+			      std	22,104(%0)\n\
+			      std	23,112(%0)\n\
+			      std	24,120(%0)\n\
+			      std	25,128(%0)\n\
+			      std	26,136(%0)\n\
+			      std	27,144(%0)\n\
+			      std	28,152(%0)\n\
+			      std	29,160(%0)\n\
+			      std	30,168(%0)\n\
+			      std	31,176(%0)\n" : : "r" (curr_context));
+	return 0;
+}
+
+void kgdb_fault_longjmp(unsigned long *curr_context)
+{
+	__asm__ __volatile__("ld	13,32(%0)\n\
+	 		      ld	14,40(%0)\n\
+			      ld	15,48(%0)\n\
+			      ld	16,56(%0)\n\
+			      ld	17,64(%0)\n\
+			      ld	18,72(%0)\n\
+			      ld	19,80(%0)\n\
+			      ld	20,88(%0)\n\
+			      ld	21,96(%0)\n\
+			      ld	22,104(%0)\n\
+			      ld	23,112(%0)\n\
+			      ld	24,120(%0)\n\
+			      ld	25,128(%0)\n\
+			      ld	26,136(%0)\n\
+			      ld	27,144(%0)\n\
+			      ld	28,152(%0)\n\
+			      ld	29,160(%0)\n\
+			      ld	30,168(%0)\n\
+			      ld	31,176(%0)\n\
+			      ld	0,24(%0)\n\
+			      mtcrf	0x38,0\n\
+			      ld	0,0(%0)\n\
+			      ld	1,8(%0)\n\
+			      ld	2,16(%0)\n\
+			      mtlr	0\n\
+			      mr	3,1\n" : : "r" (curr_context));
+}
+
+/*
+ * Global data
+ */
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08},
+};
+
+int kgdb_not_implemented(struct pt_regs *regs)
+{
+	return 0;
+}
+
+int kgdb_arch_init(void)
+{
+#ifdef CONFIG_XMON
+#error Both XMON and KGDB selected in .config.  Unselect one of them.
+#endif
+
+	__debugger_ipi = kgdb_not_implemented;
+	__debugger = kgdb_debugger;
+	__debugger_bpt = kgdb_breakpoint;
+	__debugger_sstep = kgdb_singlestep;
+	__debugger_iabr_match = kgdb_iabr_match;
+	__debugger_dabr_match = kgdb_dabr_match;
+	__debugger_fault_handler = kgdb_not_implemented;
+
+	return 0;
+}
+
+arch_initcall(kgdb_arch_init);
diff -puN arch/ppc64/kernel/Makefile~ppc64-lite arch/ppc64/kernel/Makefile
--- linux-2.6.13/arch/ppc64/kernel/Makefile~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/ppc64/kernel/Makefile	2005-08-08 19:16:03.000000000 -0700
@@ -2,7 +2,7 @@
 # Makefile for the linux ppc64 kernel.
 #
 
-EXTRA_CFLAGS	+= -mno-minimal-toc
+#EXTRA_CFLAGS	+= -mno-minimal-toc
 extra-y		:= head.o vmlinux.lds
 
 obj-y               :=	setup.o entry.o traps.o irq.o idle.o dma.o \
@@ -53,6 +53,7 @@ obj-$(CONFIG_HVCS)		+= hvcserver.o
 obj-$(CONFIG_IBMVIO)		+= vio.o
 obj-$(CONFIG_XICS)		+= xics.o
 obj-$(CONFIG_MPIC)		+= mpic.o
+obj-$(CONFIG_KGDB)		+= kgdb.o
 
 obj-$(CONFIG_PPC_PMAC)		+= pmac_setup.o pmac_feature.o pmac_pci.o \
 				   pmac_time.o pmac_nvram.o pmac_low_i2c.o
diff -puN arch/ppc64/kernel/maple_setup.c~ppc64-lite arch/ppc64/kernel/maple_setup.c
--- linux-2.6.13/arch/ppc64/kernel/maple_setup.c~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/ppc64/kernel/maple_setup.c	2005-08-08 19:16:03.000000000 -0700
@@ -77,6 +77,7 @@ extern void maple_pcibios_fixup(void);
 extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel);
 extern void generic_find_legacy_serial_ports(u64 *physport,
 		unsigned int *default_speed);
+extern void add_kgdb_port(void);
 
 static void maple_restart(char *cmd)
 {
@@ -213,6 +214,10 @@ static void __init maple_init_early(void
 		DBG("Hello World !\n");
 	}
 
+#ifdef CONFIG_KGDB_8250
+	add_kgdb_port();
+#endif
+
 	/* Setup interrupt mapping options */
 	ppc64_interrupt_controller = IC_OPEN_PIC;
 
diff -puN arch/ppc64/kernel/setup.c~ppc64-lite arch/ppc64/kernel/setup.c
--- linux-2.6.13/arch/ppc64/kernel/setup.c~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/ppc64/kernel/setup.c	2005-08-08 19:16:03.000000000 -0700
@@ -33,6 +33,7 @@
 #include <linux/unistd.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/kgdb.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
@@ -1258,6 +1259,7 @@ void __init generic_find_legacy_serial_p
 		serial_ports[index].iobase = reg->address;
 		serial_ports[index].irq = interrupts ? interrupts[0] : 0;
 		serial_ports[index].flags = ASYNC_BOOT_AUTOCONF;
+		serial_ports[index].line = index;
 
 		DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n",
 		    index,
@@ -1311,6 +1313,18 @@ void __init generic_find_legacy_serial_p
 	DBG(" <- generic_find_legacy_serial_port()\n");
 }
 
+
+#ifdef CONFIG_KGDB_8250
+void add_kgdb_port(void)
+{
+	int ttyS;
+
+	ttyS = kgdb8250_get_ttyS();
+	if (ttyS < old_serial_count)
+		kgdb8250_add_platform_port(ttyS, &serial_ports[ttyS]);
+}
+#endif
+
 static struct platform_device serial_device = {
 	.name	= "serial8250",
 	.id	= 0,
diff -puN arch/ppc64/mm/fault.c~ppc64-lite arch/ppc64/mm/fault.c
--- linux-2.6.13/arch/ppc64/mm/fault.c~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/ppc64/mm/fault.c	2005-08-08 19:16:03.000000000 -0700
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
+#include <linux/kgdb.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -306,6 +307,13 @@ void bad_page_fault(struct pt_regs *regs
 		regs->nip = entry->fixup;
 		return;
 	}
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault) {
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+	}
+#endif
 
 	/* kernel has accessed a bad area */
 	die("Kernel access of bad area", regs, sig);
diff -puN /dev/null include/asm-ppc64/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-ppc64/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,55 @@
+/*
+ * kgdb.h: Defines and declarations for serial line source level
+ *         remote debugging of the Linux kernel using gdb.
+ *
+ * copied from include/asm-ppc, modified for ppc64
+ *
+ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
+ * PPC Mods (C) 2004 Tom Rini (trini@mvista.com)
+ * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com)
+ * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifdef __KERNEL__
+#ifndef _PPC64_KGDB_H
+#define _PPC64_KGDB_H
+
+#ifndef __ASSEMBLY__
+
+#define BREAK_INSTR_SIZE	4
+#if 1
+/*
+ * Does not include vector registers and vector state registers.
+ *
+ * 64 bit (8 byte) registers:
+ *   32 gpr, 32 fpr, nip, msr, link, ctr
+ * 32 bit (4 byte) registers:
+ *   ccr, xer, fpscr
+ */
+#define NUMREGBYTES		((68 * 8) + (3 * 4))
+#else
+/*
+ * Includes vector registers and vector state registers.
+ *
+ * 128 bit (16 byte) registers:
+ *   32 vr
+ * 64 bit (8 byte) registers:
+ *   32 gpr, 32 fpr, nip, msr, link, ctr
+ * 32 bit (4 byte) registers:
+ *   ccr, xer, fpscr, vscr, vrsave
+ */
+#define NUMREGBYTES		((128 * 16) + (68 * 8) + (5 * 4))
+#endif
+#define NUMCRITREGBYTES		184
+#define BUFMAX			((NUMREGBYTES * 2) + 512)
+#define OUTBUFMAX		((NUMREGBYTES * 2) + 512)
+#define BREAKPOINT()		asm(".long 0x7d821008"); /* twge r2, r2 */
+#define CHECK_EXCEPTION_STACK()	1
+#define CACHE_FLUSH_IS_SAFE	1
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* !(_PPC64_KGDB_H) */
+
+#endif /* __KERNEL__ */
diff -puN lib/Kconfig.debug~ppc64-lite lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~ppc64-lite	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-10 10:53:35.000000000 -0700
@@ -163,7 +163,7 @@ config FRAME_POINTER
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (ARM || X86 || MIPS32 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (ARM || X86 || MIPS32 || PPC64 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable
_

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

* [patch 12/16] KGDBoE I/O driver
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (9 preceding siblings ...)
  2005-08-29 16:11   ` [patch 11/16] Add support for PowerPC64 " Tom Rini
@ 2005-08-29 16:11   ` Tom Rini
  2005-08-29 16:11   ` [patch 13/16] Add CFI DWARF2 annotation support Tom Rini
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini


This is the simple KGDB over Ethernet I/O driver that uses netpoll for all of
the heavy lifting.  At one point this was very similar to the version Matt
Mackall wrote and is currently in Andrew's tree.  Since then it has been
reworked to fit into our model.

---

 linux-2.6.13-trini/drivers/net/Makefile |    1 
 linux-2.6.13-trini/drivers/net/kgdboe.c |  208 ++++++++++++++++++++++++++++
 linux-2.6.13-trini/lib/Kconfig.debug    |   24 +++
 3 files changed, 233 insertions(+)

diff -puN /dev/null drivers/net/kgdboe.c
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/drivers/net/kgdboe.c	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,208 @@
+/*
+ * drivers/net/kgdboe.c
+ *
+ * A network interface for GDB.
+ * Based upon 'gdbserial' by David Grothe <dave@gcom.com>
+ * and Scott Foehner <sfoehner@engr.sgi.com>
+ *
+ * Maintainers: Amit S. Kale <amitkale@linsyssoft.com> and
+ * 		Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2004 (c) Amit S. Kale <amitkale@linsyssoft.com>
+ * 2004-2005 (c) MontaVista Software, Inc.
+ * 2005 (c) Wind River Systems, Inc.
+ *
+ * Other folks:
+ * San Mehat <nettwerk@biodome.org>
+ * Robert Walsh <rjwalsh@durables.org>
+ * wangdi <wangdi@clusterfs.com>.
+ * Matt Mackall <mpm@selenic.com>
+ * Pavel Machek <pavel@suse.cz>
+ * Jason Wessel <jason.wessel@windriver.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.
+ *
+ * Changes:
+ * 3/10/05 - Jason Wessel <jason.wessel@windriver.com>
+ * - Added ability to compile/load as module
+ *
+ * Known problems:
+ * - There is no way to deny the unloading of the module
+ *   if KGDB is connected, but an attempt is made to handle it
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/kgdb.h>
+#include <linux/netpoll.h>
+#include <linux/init.h>
+
+#include <asm/atomic.h>
+
+#define IN_BUF_SIZE 512		/* power of 2, please */
+#define OUT_BUF_SIZE 30		/* We don't want to send too big of a packet. */
+
+static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE];
+static int in_head, in_tail, out_count;
+static atomic_t in_count;
+/* 0 = unconfigured, 1 = netpoll options parsed, 2 = fully configured. */
+static int configured;
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len);
+static void eth_pre_exception_handler(void);
+static void eth_post_exception_handler(void);
+static int eth_get_char(void);
+static void eth_flush_buf(void);
+static void eth_put_char(int chr);
+int init_kgdboe(void);
+
+static struct netpoll np = {
+	.name = "kgdboe",
+	.dev_name = "eth0",
+	.rx_hook = rx_hook,
+	.local_port = 6443,
+	.remote_port = 6442,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+
+MODULE_DESCRIPTION("KGDB driver for network interfaces");
+MODULE_LICENSE("GPL");
+static char config[256];
+module_param_string(kgdboe, config, 256, 0);
+MODULE_PARM_DESC(kgdboe, " kgdboe=[src-port]@[src-ip]/[dev],"
+		 "[tgt-port]@<tgt-ip>/<tgt-macaddr>\n");
+
+static struct kgdb_io local_kgdb_io_ops = {
+	.read_char = eth_get_char,
+	.write_char = eth_put_char,
+	.init = init_kgdboe,
+	.flush = eth_flush_buf,
+	.pre_exception = eth_pre_exception_handler,
+	.post_exception = eth_post_exception_handler
+};
+
+static void eth_pre_exception_handler(void)
+{
+	netpoll_set_trap(1);
+}
+
+static void eth_post_exception_handler(void)
+{
+	netpoll_set_trap(0);
+}
+
+static int eth_get_char(void)
+{
+	int chr;
+
+	while (atomic_read(&in_count) == 0)
+		netpoll_poll(&np);
+
+	chr = in_buf[in_tail++];
+	in_tail &= (IN_BUF_SIZE - 1);
+	atomic_dec(&in_count);
+	return chr;
+}
+
+static void eth_flush_buf(void)
+{
+	if (out_count && np.dev) {
+		netpoll_send_udp(&np, out_buf, out_count);
+		memset(out_buf, 0, sizeof(out_buf));
+		out_count = 0;
+	}
+}
+
+static void eth_put_char(int chr)
+{
+	out_buf[out_count++] = chr;
+	if (out_count == OUT_BUF_SIZE)
+		eth_flush_buf();
+}
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len)
+{
+	int i;
+
+	np->remote_port = port;
+
+	/*
+	 * This could be GDB trying to attach.  But it could also be GDB
+	 * finishing up a session, with kgdb_connected=0 but GDB sending
+	 * an ACK for the final packet.  To make sure we don't try and
+	 * make a breakpoint when GDB is leaving, make sure that if
+	 * !kgdb_connected the only len == 1 packet we allow is ^C.
+	 */
+	if (!kgdb_connected && (len != 1 || msg[0] == 3) &&
+	    !atomic_read(&kgdb_setting_breakpoint))
+		tasklet_schedule(&kgdb_tasklet_breakpoint);
+
+	for (i = 0; i < len; i++) {
+		if (msg[i] == 3)
+			tasklet_schedule(&kgdb_tasklet_breakpoint);
+
+		if (atomic_read(&in_count) >= IN_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			in_head = in_tail = 0;
+			atomic_set(&in_count, 0);
+			break;
+		}
+		in_buf[in_head++] = msg[i];
+		in_head &= (IN_BUF_SIZE - 1);
+		atomic_inc(&in_count);
+	}
+}
+
+static int option_setup(char *opt)
+{
+	configured = !netpoll_parse_options(&np, opt);
+	return 0;
+}
+
+__setup("kgdboe=", option_setup);
+
+int init_kgdboe(void)
+{
+	/* Already done? */
+	if (configured == 2)
+		return 0;
+
+	if (strlen(config))
+		option_setup(config);
+
+	if (!configured) {
+		printk("kgdboe: configuration incorrect - kgdboe not "
+		       "loaded.\n");
+		printk("  Usage: kgdboe=[src-port]@[src-ip]/[dev],[tgt-port]"
+		       "@<tgt-ip>/[tgt-macaddr]\n");
+		return -EINVAL;
+	}
+
+	if (netpoll_setup(&np)) {
+		printk("kgdboe: netpoll_setup failed kgdboe failed\n");
+		return -EINVAL;
+	}
+
+	if (kgdb_register_io_module(&local_kgdb_io_ops))
+		return -EINVAL;
+
+	printk(KERN_INFO "kgdboe: debugging over ethernet enabled\n");
+
+	configured = 2;
+
+	return 0;
+}
+
+static void cleanup_kgdboe(void)
+{
+	netpoll_cleanup(&np);
+	configured = 0;
+
+	kgdb_unregister_io_module(&local_kgdb_io_ops);
+}
+
+module_init(init_kgdboe);
+module_exit(cleanup_kgdboe);
diff -puN drivers/net/Makefile~eth drivers/net/Makefile
--- linux-2.6.13/drivers/net/Makefile~eth	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/drivers/net/Makefile	2005-08-08 19:16:03.000000000 -0700
@@ -195,3 +195,4 @@ obj-$(CONFIG_IRDA) += irda/
 obj-$(CONFIG_ETRAX_ETHERNET) += cris/
 
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_KGDBOE) += kgdboe.o
diff -puN lib/Kconfig.debug~eth lib/Kconfig.debug
--- linux-2.6.13/lib/Kconfig.debug~eth	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/lib/Kconfig.debug	2005-08-08 19:16:03.000000000 -0700
@@ -217,6 +217,18 @@ config KGDB_8250_NOMODULE
 	  GDB.  This is independent of the normal (SERIAL_8250) driver
 	  for this chipset.
 
+config KGDBOE_NOMODULE
+	bool "KGDB: On ethernet - in kernel"
+	select KGDBOE
+	select NETPOLL
+	select NETPOLL_TRAP
+	select NETPOLL_RX
+	help
+	  Uses the NETPOLL API to communicate with the host GDB via UDP.
+	  In order for this to work, the ethernet interface specified must
+	  support the NETPOLL API, and this must be initialized at boot.
+	  See the documentation for syntax.
+
 config KGDB_MPSC
 	bool "KGDB on MV64x60 MPSC"
 	depends on SERIAL_MPSC
@@ -247,6 +259,18 @@ config KGDB_SH_SCI
 
 endchoice
 
+config KGDBOE
+	tristate "KGDB: On ethernet" if !KGDBOE_NOMODULE
+	depends on m && KGDB_ONLY_MODULES
+	select NETPOLL
+	select NETPOLL_TRAP
+	select NETPOLL_RX
+	help
+	  Uses the NETPOLL API to communicate with the host GDB via UDP.
+	  In order for this to work, the ethernet interface specified must
+	  support the NETPOLL API, and this must be initialized at boot.
+	  See the documentation for syntax.
+
 config KGDB_8250
 	tristate "KGDB: On generic serial port (8250)" if !KGDB_8250_NOMODULE
 	depends on m && KGDB_ONLY_MODULES
_

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

* [patch 13/16] Add CFI DWARF2 annotation support
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (10 preceding siblings ...)
  2005-08-29 16:11   ` [patch 12/16] KGDBoE I/O driver Tom Rini
@ 2005-08-29 16:11   ` Tom Rini
  2005-08-29 16:11   ` [patch 14/16] Minor SysRq keyboard bugfix for KGDB Tom Rini
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, ganzginer


There are some parts of the kernel where you simply cannot unwind past.  This
does not, however, stop GDB from trying, and getting stuck in an infinite loop
(it will get garbage back, try and unwind that, repeat).  The way to fix this
is to manually insert some DWARF2 information into the kernel so that GDB will
cleanly (or almost cleanly, it will get the same frame twice, and stop) stop.
George wrote much of the IMHO hard part here (i386 & the macros) and I
expanded this to all of the other arches.  This adds a small amount to the
DEBUG_INFO=y kernel size, but that's not unexpected.

---

 linux-2.6.13-trini/Makefile                     |    5 
 linux-2.6.13-trini/arch/arm/kernel/entry-armv.S |    2 
 linux-2.6.13-trini/arch/i386/kernel/entry.S     |  105 ++
 linux-2.6.13-trini/arch/i386/kernel/head.S      |    5 
 linux-2.6.13-trini/arch/i386/kernel/process.c   |   20 
 linux-2.6.13-trini/arch/i386/kernel/smpboot.c   |    3 
 linux-2.6.13-trini/arch/x86_64/kernel/entry.S   |    2 
 linux-2.6.13-trini/include/asm-arm/kgdb.h       |    7 
 linux-2.6.13-trini/include/asm-generic/kgdb.h   |   34 
 linux-2.6.13-trini/include/asm-i386/kgdb.h      |   60 -
 linux-2.6.13-trini/include/asm-mips/kgdb.h      |    4 
 linux-2.6.13-trini/include/asm-ppc/kgdb.h       |    1 
 linux-2.6.13-trini/include/asm-sh/kgdb.h        |    1 
 linux-2.6.13-trini/include/asm-x86_64/kgdb.h    |    4 
 linux-2.6.13-trini/include/linux/dwarf2-lang.h  |  301 +++++++
 linux-2.6.13-trini/include/linux/dwarf2.h       |  775 ++++++++++++++++++++
 linux-2.6.13-trini/scripts/dwarfh.awk           |   19 
 17 files changed, 1319 insertions(+), 29 deletions(-)

diff -puN arch/arm/kernel/entry-armv.S~cfi_annotations arch/arm/kernel/entry-armv.S
--- linux-2.6.13/arch/arm/kernel/entry-armv.S~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/arm/kernel/entry-armv.S	2005-08-08 19:16:03.000000000 -0700
@@ -15,6 +15,7 @@
  */
 #include <linux/config.h>
 
+#include <asm/kgdb.h>
 #include <asm/glue.h>
 #include <asm/vfpmacros.h>
 #include <asm/hardware.h>		/* should be moved into entry-macro.S */
@@ -215,6 +216,7 @@ svc_preempt:
 	beq	preempt_return			@ go again
 	b	1b
 #endif
+	CFI_END_FRAME(__irq_svc)
 
 	.align	5
 __und_svc:
diff -puN arch/i386/kernel/entry.S~cfi_annotations arch/i386/kernel/entry.S
--- linux-2.6.13/arch/i386/kernel/entry.S~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/entry.S	2005-08-08 19:16:03.000000000 -0700
@@ -655,3 +655,108 @@ ENTRY(spurious_interrupt_bug)
 #include "syscall_table.S"
 
 syscall_table_size=(.-sys_call_table)
+
+#	Here we do call frames.  We cheat a bit as we only really need
+#	correct frames at locations we can actually look at from a
+#	debugger.  Since the break instruction trap actually goes thru
+#	some of this code, we don't really need info on those areas, but
+#	only after the fact.  I.e. if we can not step or break in a
+#	location or end up with a return address pointing at the
+#	location, we don't need a correct call frame for it.
+
+#ifdef CONFIG_KGDB
+
+#include <linux/dwarf2-lang.h>
+/*
+ * The register numbers as known by gdb
+ */
+
+#define _EAX 0
+#define _ECX 1
+#define _EDX 2
+#define _EBX 3
+#define _ESP 4
+#define _EBP 5
+#define _ESI 6
+#define _EDI 7
+#define _PC  8
+#define _EIP 8
+#define _PS  9
+#define _EFLAGS  9
+#define _CS 10
+#define _SS 11
+#define _DS 12
+#define _ES 13
+#define _FS 14
+#define _GS 15
+	/*
+	 * This code uses macros defined in linux/dwarf2-lang.h
+	 * They attempt to follow the dwarf2 naming conventions... sort of..
+	 */
+ENTRY(end_of_stack_stop_unwind_function)
+	.long 	end_of_stack_stop_unwind_function+1
+
+	.text
+
+	CFI_preamble(c1,_PC,1,1)
+	CFA_define_reference(_ESP,OLDESP)	/* Stack pointer */
+	CFA_expression(_EIP)
+	   CFA_exp_OP_dup			/* copy old esp */
+ 	   CFA_exp_OP_consts(CS-OLDESP)		/* offset to CS address */
+ 	   CFA_exp_OP_plus			/* should be CS address */
+	   CFA_exp_OP_deref			/* get the CS */
+	   CFA_exp_OP_const4s(VM_MASK|3)	/* prepare to mask it */
+	   CFA_exp_OP_and			/* mask it, zero means kernel */
+	   CFA_exp_OP_bra(eip_user_rtn)		/* branch if user */
+	   CFA_exp_OP_const4s(EIP-OLDESP)	/* offset to return address */
+	   CFA_exp_OP_plus			/* add that in */
+	   CFA_exp_OP_skip(eip_end)		/* done if kernel, skip out */
+eip_user_rtn:
+	   CFA_exp_OP_addr(end_of_stack_stop_unwind_function)/*dummy function */
+eip_end:
+	   CFA_expression_end
+	CFA_define_offset(_EBX,EBX-OLDESP)
+	CFA_define_offset(_ECX,ECX-OLDESP)
+	CFA_define_offset(_EDX,EDX-OLDESP)
+	CFA_define_offset(_ESI,ESI-OLDESP)
+	CFA_define_offset(_EDI,EDI-OLDESP)
+	CFA_define_offset(_EBP,EBP-OLDESP)
+	CFA_define_offset(_EAX,EAX-OLDESP)
+	CFA_define_offset(_EFLAGS,EFLAGS-OLDESP)
+	CFI_postamble()
+
+/*
+ * This provides an uwind for our dummy end of unwind function.
+ * Current convention is to provied an undefined return address.
+ */
+	CFI_preamble(c2,_PC,1,1)
+	CFA_define_reference(_ESP,0)	/* Stack pointer */
+	CFA_undefine_reg(_EIP)
+	CFI_postamble()
+
+	FDE_preamble(c2,end_of_stack_stop_unwind_function,	\
+	                end_of_stack_stop_unwind_function+5)
+	FDE_postamble()
+	/*
+         * This is VERY sloppy.  At this point all we want to do is get
+         * the frame right for back tracing.  It will not be good if
+         * you try to single step.  We use already defined labels.
+         * We want to cover all call outs.
+         * We could also recode this as just one FDE, but this works and
+         * I want to get it out.
+	 */
+	FDE_preamble(c1,ret_from_fork,ret_from_exception)
+	CFA_define_cfa_offset(4)		/* one extra word on stack */
+	FDE_postamble()
+
+	FDE_preamble(c1,ret_from_exception,device_not_available_emulate)
+	FDE_postamble()
+
+		FDE_preamble(c1,device_not_available_emulate,debug)
+	CFA_define_cfa_offset(4)		/* one extra word on stack */
+	FDE_postamble()
+
+	FDE_preamble(c1, debug,spurious_interrupt_bug)
+	FDE_postamble()
+
+#endif
diff -puN arch/i386/kernel/head.S~cfi_annotations arch/i386/kernel/head.S
--- linux-2.6.13/arch/i386/kernel/head.S~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/head.S	2005-08-08 19:16:03.000000000 -0700
@@ -11,6 +11,7 @@
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/linkage.h>
+#include <asm/kgdb.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -328,7 +329,9 @@ is386:	movl $2,%ecx		# set MP
 L6:
 	jmp L6			# main should never return here, but
 				# just in case, we know what happens.
-
+	/* This dwarf code tells gdb that this is the end of the unwind */
+	/* This uses the CFA set up for pc=1 located in entry.S */
+	CFI_END_FRAME(is386)
 /*
  * We depend on ET to be correct. This checks for 287/387.
  */
diff -puN arch/i386/kernel/process.c~cfi_annotations arch/i386/kernel/process.c
--- linux-2.6.13/arch/i386/kernel/process.c~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/process.c	2005-08-08 19:16:03.000000000 -0700
@@ -341,7 +341,27 @@ __asm__(".section .text\n"
 	"call *%ebx\n\t"
 	"pushl %eax\n\t"
 	"call do_exit\n"
+	"kernel_thread_helper_end:\n\t"
 	".previous");
+#ifdef CONFIG_KGDB
+#include <linux/dwarf2-lang.h>
+
+	/* This dwarf code tells gdb that this is the end of the unwind */
+	/* This uses the CFA set up for pc=1 located in entry.S */
+#define _ESP 4
+#define _PC  8
+#define _EIP 8
+__asm__(
+	QUOTE_THIS(
+		CFI_preamble(dwarf_4,_PC,1,1)
+		CFA_define_reference(_ESP,0)	/* Stack pointer */
+		CFA_undefine_reg(_EIP)
+		CFI_postamble()
+
+		FDE_preamble(dwarf_4,kernel_thread_helper,kernel_thread_helper_end)
+		FDE_postamble()
+		));
+#endif
 
 /*
  * Create a kernel thread
diff -puN arch/i386/kernel/smpboot.c~cfi_annotations arch/i386/kernel/smpboot.c
--- linux-2.6.13/arch/i386/kernel/smpboot.c~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/smpboot.c	2005-08-08 19:16:03.000000000 -0700
@@ -537,6 +537,9 @@ void __devinit initialize_secondary(void
 
 	asm volatile(
 		"movl %0,%%esp\n\t"
+#ifdef CONFIG_KGDB
+		"pushl end_of_stack_stop_unwind_function\n\t"
+#endif
 		"jmp *%1"
 		:
 		:"r" (current->thread.esp),"r" (current->thread.eip));
diff -puN arch/x86_64/kernel/entry.S~cfi_annotations arch/x86_64/kernel/entry.S
--- linux-2.6.13/arch/x86_64/kernel/entry.S~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/entry.S	2005-08-08 19:16:03.000000000 -0700
@@ -41,6 +41,7 @@
 #include <asm/unistd.h>
 #include <asm/thread_info.h>
 #include <asm/hw_irq.h>
+#include <asm/kgdb.h>
 
 	.code64
 
@@ -741,6 +742,7 @@ ENTRY(kernel_thread)
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
+	CFI_END_FRAME(kernel_thread)
 
 	
 child_rip:
diff -puN include/asm-arm/kgdb.h~cfi_annotations include/asm-arm/kgdb.h
--- linux-2.6.13/include/asm-arm/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-arm/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -14,6 +14,7 @@
 
 #include <linux/config.h>
 #include <asm/ptrace.h>
+#include <asm-generic/kgdb.h>
 
 
 /*
@@ -65,6 +66,7 @@ extern int kgdb_fault_expected;
 #define	NUMREGBYTES		(GDB_MAX_REGS << 2)
 #define	NUMCRITREGBYTES		(32 << 2)
 #define	CHECK_EXCEPTION_STACK()	1
+#endif				/* __ASSEMBLY__ */
 
 #define	_R0		0
 #define	_R1		1
@@ -84,7 +86,8 @@ extern int kgdb_fault_expected;
 #define	_PC		15
 #define	_CPSR		(GDB_MAX_REGS - 1)
 
-#define	CHECK_EXCEPTION_STACK()	1
+/* So that we can denote the end of a frame for tracing, in the simple
+ * case. */
+#define CFI_END_FRAME(func)	__CFI_END_FRAME(_PC,_SP,func)
 
-#endif // !__ASSEMBLY__
 #endif // __ASM_KGDB_H__
diff -puN /dev/null include/asm-generic/kgdb.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/asm-generic/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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. 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__
+
+#include <linux/dwarf2-lang.h>
+#ifdef __ASSEMBLY__
+#ifdef CONFIG_KGDB
+/* This MUST be put at the end of a given assembly function */
+#define __CFI_END_FRAME(pc,sp,func)			\
+CAT3(.Lend_,func,:)					\
+	CFI_preamble(func,pc,0x1,-DATA_ALIGN_FACTOR)	\
+	CFA_define_reference(sp, 0)			\
+	CFA_undefine_reg(pc)				\
+	CFI_postamble()					\
+	FDE_preamble(func,func,CAT3(.Lend,_,func))	\
+	FDE_postamble()
+#else
+#define __CFI_END_FRAME(pc,sp,fn)
+#endif				/* CONFIG_KGDB */
+#endif				/* __ASSEMBLY__ */
+#endif				/* __ASM_GENERIC_KGDB_H__ */
diff -puN include/asm-i386/kgdb.h~cfi_annotations include/asm-i386/kgdb.h
--- linux-2.6.13/include/asm-i386/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-i386/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -6,6 +6,39 @@
  * Copyright (C) 2001-2004 Amit S. Kale
  */
 
+#include <asm-generic/kgdb.h>
+
+/*
+ *  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.
+ */
+#define _EAX	0
+#define _ECX	1
+#define _EDX	2
+#define _EBX	3
+#define _ESP	4
+#define _EBP	5
+#define _ESI	6
+#define _EDI	7
+#define _PC	8
+#define _EIP	8
+#define _PS	9
+#define _EFLAGS	9
+#define _CS	10
+#define _SS	11
+#define _DS	12
+#define _ES	13
+#define _FS	14
+#define _GS	15
+
+/* So that we can denote the end of a frame for tracing, in the simple
+ * case. */
+#define CFI_END_FRAME(func)	__CFI_END_FRAME(_EIP,_ESP,func)
+
+#ifndef __ASSEMBLY__
 /************************************************************************/
 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
 /* at least NUMREGBYTES*2 are needed for register packets */
@@ -14,37 +47,14 @@
 
 /* Number of bytes of registers.  */
 #define NUMREGBYTES		64
+
 /* Number of bytes of registers we need to save for a setjmp/longjmp. */
 #define NUMCRITREGBYTES		24
 
-/*
- *  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.
- */
-enum regnames { _EAX,		/* 0 */
-	_ECX,			/* 1 */
-	_EDX,			/* 2 */
-	_EBX,			/* 3 */
-	_ESP,			/* 4 */
-	_EBP,			/* 5 */
-	_ESI,			/* 6 */
-	_EDI,			/* 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 */
-};
-
 #define BREAKPOINT()		asm("   int $3");
 #define BREAK_INSTR_SIZE	1
 #define CHECK_EXCEPTION_STACK()	1
 #define CACHE_FLUSH_IS_SAFE	1
+#endif				/* !__ASSEMBLY__ */
 #endif				/* _ASM_KGDB_H_ */
 #endif				/* __KERNEL__ */
diff -puN include/asm-mips/kgdb.h~cfi_annotations include/asm-mips/kgdb.h
--- linux-2.6.13/include/asm-mips/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-mips/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -2,6 +2,9 @@
 #ifndef _ASM_KGDB_H_
 #define _ASM_KGDB_H_
 
+#include <asm-generic/kgdb.h>
+
+#ifndef __ASSEMBLY__
 #define BUFMAX			2048
 #define NUMREGBYTES		(90*sizeof(long))
 #define NUMCRITREGBYTES		(12*sizeof(long))
@@ -18,5 +21,6 @@
 
 extern int kgdb_early_setup;
 
+#endif				/* !__ASSEMBLY__ */
 #endif				/* _ASM_KGDB_H_ */
 #endif				/* __KERNEL__ */
diff -puN include/asm-ppc/kgdb.h~cfi_annotations include/asm-ppc/kgdb.h
--- linux-2.6.13/include/asm-ppc/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-ppc/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -12,6 +12,7 @@
 #ifndef _PPC_KGDB_H
 #define _PPC_KGDB_H
 
+#include <asm-generic/kgdb.h>
 #ifndef __ASSEMBLY__
 
 #define BREAK_INSTR_SIZE	4
diff -puN include/asm-sh/kgdb.h~cfi_annotations include/asm-sh/kgdb.h
--- linux-2.6.13/include/asm-sh/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-sh/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -15,6 +15,7 @@
 #define __KGDB_H
 
 #include <asm-generic/kgdb.h>
+#include <asm-generic/kgdb.h>
 /* Based on sh-gdb.c from gdb-6.1, Glenn
      Engel at HP  Ben Lee and Steve Chamberlain */
 #define NUMREGBYTES	112	/* 92 */
diff -puN include/asm-x86_64/kgdb.h~cfi_annotations include/asm-x86_64/kgdb.h
--- linux-2.6.13/include/asm-x86_64/kgdb.h~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/kgdb.h	2005-08-08 19:16:03.000000000 -0700
@@ -6,6 +6,8 @@
  * Copyright (C) 2001-2004 Amit S. Kale
  */
 
+#include <asm-generic/kgdb.h>
+
 /*
  *  Note that this register image is in a different order than
  *  the register image that Linux produces at interrupt time.
@@ -36,6 +38,8 @@
 #define NUMREGBYTES		((_PS+1)*8)
 #define NUMCRITREGBYTES		(8 * 8)		/* 8 registers. */
 
+/* Help GDB to know when to stop backtracing. */
+#define CFI_END_FRAME(func)	__CFI_END_FRAME(_PC,_RSP,func)
 #ifndef __ASSEMBLY__
 /* BUFMAX defines the maximum number of characters in inbound/outbound
  * buffers at least NUMREGBYTES*2 are needed for register packets, and
diff -puN /dev/null include/linux/dwarf2.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/linux/dwarf2.h	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,775 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
+   2003 Free Software Foundation, Inc.
+
+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
+   provided support for this effort -- June 21, 1995.
+
+   Derived from the DWARF 1 implementation written by Ron Guilmette
+   (rfg@netcom.com), November 1990.
+
+   This file is part of GCC.
+
+   GCC 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.
+
+   GCC 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.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+   This file also now contains definitions from the DWARF 3 specification.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.  */
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section.  */
+typedef struct
+{
+  unsigned char li_length          [4];
+  unsigned char li_version         [2];
+  unsigned char li_prologue_length [4];
+  unsigned char li_min_insn_length [1];
+  unsigned char li_default_is_stmt [1];
+  unsigned char li_line_base       [1];
+  unsigned char li_line_range      [1];
+  unsigned char li_opcode_base     [1];
+}
+DWARF2_External_LineInfo;
+
+typedef struct
+{
+  unsigned long  li_length;
+  unsigned short li_version;
+  unsigned int   li_prologue_length;
+  unsigned char  li_min_insn_length;
+  unsigned char  li_default_is_stmt;
+  int            li_line_base;
+  unsigned char  li_line_range;
+  unsigned char  li_opcode_base;
+}
+DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section.  */
+typedef struct
+{
+  unsigned char pn_length  [4];
+  unsigned char pn_version [2];
+  unsigned char pn_offset  [4];
+  unsigned char pn_size    [4];
+}
+DWARF2_External_PubNames;
+
+typedef struct
+{
+  unsigned long  pn_length;
+  unsigned short pn_version;
+  unsigned long  pn_offset;
+  unsigned long  pn_size;
+}
+DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section.  */
+typedef struct
+{
+  unsigned char  cu_length        [4];
+  unsigned char  cu_version       [2];
+  unsigned char  cu_abbrev_offset [4];
+  unsigned char  cu_pointer_size  [1];
+}
+DWARF2_External_CompUnit;
+
+typedef struct
+{
+  unsigned long  cu_length;
+  unsigned short cu_version;
+  unsigned long  cu_abbrev_offset;
+  unsigned char  cu_pointer_size;
+}
+DWARF2_Internal_CompUnit;
+
+typedef struct
+{
+  unsigned char  ar_length       [4];
+  unsigned char  ar_version      [2];
+  unsigned char  ar_info_offset  [4];
+  unsigned char  ar_pointer_size [1];
+  unsigned char  ar_segment_size [1];
+}
+DWARF2_External_ARange;
+
+typedef struct
+{
+  unsigned long  ar_length;
+  unsigned short ar_version;
+  unsigned long  ar_info_offset;
+  unsigned char  ar_pointer_size;
+  unsigned char  ar_segment_size;
+}
+DWARF2_Internal_ARange;
+
+
+/* Tag names and codes.  */
+enum dwarf_tag
+  {
+    DW_TAG_padding = 0x00,
+    DW_TAG_array_type = 0x01,
+    DW_TAG_class_type = 0x02,
+    DW_TAG_entry_point = 0x03,
+    DW_TAG_enumeration_type = 0x04,
+    DW_TAG_formal_parameter = 0x05,
+    DW_TAG_imported_declaration = 0x08,
+    DW_TAG_label = 0x0a,
+    DW_TAG_lexical_block = 0x0b,
+    DW_TAG_member = 0x0d,
+    DW_TAG_pointer_type = 0x0f,
+    DW_TAG_reference_type = 0x10,
+    DW_TAG_compile_unit = 0x11,
+    DW_TAG_string_type = 0x12,
+    DW_TAG_structure_type = 0x13,
+    DW_TAG_subroutine_type = 0x15,
+    DW_TAG_typedef = 0x16,
+    DW_TAG_union_type = 0x17,
+    DW_TAG_unspecified_parameters = 0x18,
+    DW_TAG_variant = 0x19,
+    DW_TAG_common_block = 0x1a,
+    DW_TAG_common_inclusion = 0x1b,
+    DW_TAG_inheritance = 0x1c,
+    DW_TAG_inlined_subroutine = 0x1d,
+    DW_TAG_module = 0x1e,
+    DW_TAG_ptr_to_member_type = 0x1f,
+    DW_TAG_set_type = 0x20,
+    DW_TAG_subrange_type = 0x21,
+    DW_TAG_with_stmt = 0x22,
+    DW_TAG_access_declaration = 0x23,
+    DW_TAG_base_type = 0x24,
+    DW_TAG_catch_block = 0x25,
+    DW_TAG_const_type = 0x26,
+    DW_TAG_constant = 0x27,
+    DW_TAG_enumerator = 0x28,
+    DW_TAG_file_type = 0x29,
+    DW_TAG_friend = 0x2a,
+    DW_TAG_namelist = 0x2b,
+    DW_TAG_namelist_item = 0x2c,
+    DW_TAG_packed_type = 0x2d,
+    DW_TAG_subprogram = 0x2e,
+    DW_TAG_template_type_param = 0x2f,
+    DW_TAG_template_value_param = 0x30,
+    DW_TAG_thrown_type = 0x31,
+    DW_TAG_try_block = 0x32,
+    DW_TAG_variant_part = 0x33,
+    DW_TAG_variable = 0x34,
+    DW_TAG_volatile_type = 0x35,
+    /* DWARF 3.  */
+    DW_TAG_dwarf_procedure = 0x36,
+    DW_TAG_restrict_type = 0x37,
+    DW_TAG_interface_type = 0x38,
+    DW_TAG_namespace = 0x39,
+    DW_TAG_imported_module = 0x3a,
+    DW_TAG_unspecified_type = 0x3b,
+    DW_TAG_partial_unit = 0x3c,
+    DW_TAG_imported_unit = 0x3d,
+    /* SGI/MIPS Extensions.  */
+    DW_TAG_MIPS_loop = 0x4081,
+    /* HP extensions.  See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .  */
+    DW_TAG_HP_array_descriptor = 0x4090,
+    /* GNU extensions.  */
+    DW_TAG_format_label = 0x4101,	/* For FORTRAN 77 and Fortran 90.  */
+    DW_TAG_function_template = 0x4102,	/* For C++.  */
+    DW_TAG_class_template = 0x4103,	/* For C++.  */
+    DW_TAG_GNU_BINCL = 0x4104,
+    DW_TAG_GNU_EINCL = 0x4105,
+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
+    DW_TAG_upc_shared_type = 0x8765,
+    DW_TAG_upc_strict_type = 0x8766,
+    DW_TAG_upc_relaxed_type = 0x8767,
+    /* PGI (STMicroelectronics) extensions.  No documentation available.  */
+    DW_TAG_PGI_kanji_type      = 0xA000,
+    DW_TAG_PGI_interface_block = 0xA020
+  };
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* Flag that tells whether entry has a child or not.  */
+#define DW_children_no   0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+enum dwarf_form
+  {
+    DW_FORM_addr = 0x01,
+    DW_FORM_block2 = 0x03,
+    DW_FORM_block4 = 0x04,
+    DW_FORM_data2 = 0x05,
+    DW_FORM_data4 = 0x06,
+    DW_FORM_data8 = 0x07,
+    DW_FORM_string = 0x08,
+    DW_FORM_block = 0x09,
+    DW_FORM_block1 = 0x0a,
+    DW_FORM_data1 = 0x0b,
+    DW_FORM_flag = 0x0c,
+    DW_FORM_sdata = 0x0d,
+    DW_FORM_strp = 0x0e,
+    DW_FORM_udata = 0x0f,
+    DW_FORM_ref_addr = 0x10,
+    DW_FORM_ref1 = 0x11,
+    DW_FORM_ref2 = 0x12,
+    DW_FORM_ref4 = 0x13,
+    DW_FORM_ref8 = 0x14,
+    DW_FORM_ref_udata = 0x15,
+    DW_FORM_indirect = 0x16
+  };
+
+/* Attribute names and codes.  */
+enum dwarf_attribute
+  {
+    DW_AT_sibling = 0x01,
+    DW_AT_location = 0x02,
+    DW_AT_name = 0x03,
+    DW_AT_ordering = 0x09,
+    DW_AT_subscr_data = 0x0a,
+    DW_AT_byte_size = 0x0b,
+    DW_AT_bit_offset = 0x0c,
+    DW_AT_bit_size = 0x0d,
+    DW_AT_element_list = 0x0f,
+    DW_AT_stmt_list = 0x10,
+    DW_AT_low_pc = 0x11,
+    DW_AT_high_pc = 0x12,
+    DW_AT_language = 0x13,
+    DW_AT_member = 0x14,
+    DW_AT_discr = 0x15,
+    DW_AT_discr_value = 0x16,
+    DW_AT_visibility = 0x17,
+    DW_AT_import = 0x18,
+    DW_AT_string_length = 0x19,
+    DW_AT_common_reference = 0x1a,
+    DW_AT_comp_dir = 0x1b,
+    DW_AT_const_value = 0x1c,
+    DW_AT_containing_type = 0x1d,
+    DW_AT_default_value = 0x1e,
+    DW_AT_inline = 0x20,
+    DW_AT_is_optional = 0x21,
+    DW_AT_lower_bound = 0x22,
+    DW_AT_producer = 0x25,
+    DW_AT_prototyped = 0x27,
+    DW_AT_return_addr = 0x2a,
+    DW_AT_start_scope = 0x2c,
+    DW_AT_stride_size = 0x2e,
+    DW_AT_upper_bound = 0x2f,
+    DW_AT_abstract_origin = 0x31,
+    DW_AT_accessibility = 0x32,
+    DW_AT_address_class = 0x33,
+    DW_AT_artificial = 0x34,
+    DW_AT_base_types = 0x35,
+    DW_AT_calling_convention = 0x36,
+    DW_AT_count = 0x37,
+    DW_AT_data_member_location = 0x38,
+    DW_AT_decl_column = 0x39,
+    DW_AT_decl_file = 0x3a,
+    DW_AT_decl_line = 0x3b,
+    DW_AT_declaration = 0x3c,
+    DW_AT_discr_list = 0x3d,
+    DW_AT_encoding = 0x3e,
+    DW_AT_external = 0x3f,
+    DW_AT_frame_base = 0x40,
+    DW_AT_friend = 0x41,
+    DW_AT_identifier_case = 0x42,
+    DW_AT_macro_info = 0x43,
+    DW_AT_namelist_items = 0x44,
+    DW_AT_priority = 0x45,
+    DW_AT_segment = 0x46,
+    DW_AT_specification = 0x47,
+    DW_AT_static_link = 0x48,
+    DW_AT_type = 0x49,
+    DW_AT_use_location = 0x4a,
+    DW_AT_variable_parameter = 0x4b,
+    DW_AT_virtuality = 0x4c,
+    DW_AT_vtable_elem_location = 0x4d,
+    /* DWARF 3 values.  */
+    DW_AT_allocated     = 0x4e,
+    DW_AT_associated    = 0x4f,
+    DW_AT_data_location = 0x50,
+    DW_AT_stride        = 0x51,
+    DW_AT_entry_pc      = 0x52,
+    DW_AT_use_UTF8      = 0x53,
+    DW_AT_extension     = 0x54,
+    DW_AT_ranges        = 0x55,
+    DW_AT_trampoline    = 0x56,
+    DW_AT_call_column   = 0x57,
+    DW_AT_call_file     = 0x58,
+    DW_AT_call_line     = 0x59,
+    /* SGI/MIPS extensions.  */
+    DW_AT_MIPS_fde = 0x2001,
+    DW_AT_MIPS_loop_begin = 0x2002,
+    DW_AT_MIPS_tail_loop_begin = 0x2003,
+    DW_AT_MIPS_epilog_begin = 0x2004,
+    DW_AT_MIPS_loop_unroll_factor = 0x2005,
+    DW_AT_MIPS_software_pipeline_depth = 0x2006,
+    DW_AT_MIPS_linkage_name = 0x2007,
+    DW_AT_MIPS_stride = 0x2008,
+    DW_AT_MIPS_abstract_name = 0x2009,
+    DW_AT_MIPS_clone_origin = 0x200a,
+    DW_AT_MIPS_has_inlines = 0x200b,
+    /* HP extensions.  */
+    DW_AT_HP_block_index         = 0x2000,
+    DW_AT_HP_unmodifiable        = 0x2001, /* Same as DW_AT_MIPS_fde.  */
+    DW_AT_HP_actuals_stmt_list   = 0x2010,
+    DW_AT_HP_proc_per_section    = 0x2011,
+    DW_AT_HP_raw_data_ptr        = 0x2012,
+    DW_AT_HP_pass_by_reference   = 0x2013,
+    DW_AT_HP_opt_level           = 0x2014,
+    DW_AT_HP_prof_version_id     = 0x2015,
+    DW_AT_HP_opt_flags           = 0x2016,
+    DW_AT_HP_cold_region_low_pc  = 0x2017,
+    DW_AT_HP_cold_region_high_pc = 0x2018,
+    DW_AT_HP_all_variables_modifiable = 0x2019,
+    DW_AT_HP_linkage_name        = 0x201a,
+    DW_AT_HP_prof_flags          = 0x201b,  /* In comp unit of procs_info for -g.  */
+    /* GNU extensions.  */
+    DW_AT_sf_names   = 0x2101,
+    DW_AT_src_info   = 0x2102,
+    DW_AT_mac_info   = 0x2103,
+    DW_AT_src_coords = 0x2104,
+    DW_AT_body_begin = 0x2105,
+    DW_AT_body_end   = 0x2106,
+    DW_AT_GNU_vector = 0x2107,
+    /* VMS extensions.  */
+    DW_AT_VMS_rtnbeg_pd_address = 0x2201,
+    /* UPC extension.  */
+    DW_AT_upc_threads_scaled = 0x3210,
+    /* PGI (STMicroelectronics) extensions.  */
+    DW_AT_PGI_lbase    = 0x3a00,
+    DW_AT_PGI_soffset  = 0x3a01,
+    DW_AT_PGI_lstride  = 0x3a02
+  };
+
+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.  */
+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
+
+/* Location atom names and codes.  */
+enum dwarf_location_atom
+  {
+    DW_OP_addr = 0x03,
+    DW_OP_deref = 0x06,
+    DW_OP_const1u = 0x08,
+    DW_OP_const1s = 0x09,
+    DW_OP_const2u = 0x0a,
+    DW_OP_const2s = 0x0b,
+    DW_OP_const4u = 0x0c,
+    DW_OP_const4s = 0x0d,
+    DW_OP_const8u = 0x0e,
+    DW_OP_const8s = 0x0f,
+    DW_OP_constu = 0x10,
+    DW_OP_consts = 0x11,
+    DW_OP_dup = 0x12,
+    DW_OP_drop = 0x13,
+    DW_OP_over = 0x14,
+    DW_OP_pick = 0x15,
+    DW_OP_swap = 0x16,
+    DW_OP_rot = 0x17,
+    DW_OP_xderef = 0x18,
+    DW_OP_abs = 0x19,
+    DW_OP_and = 0x1a,
+    DW_OP_div = 0x1b,
+    DW_OP_minus = 0x1c,
+    DW_OP_mod = 0x1d,
+    DW_OP_mul = 0x1e,
+    DW_OP_neg = 0x1f,
+    DW_OP_not = 0x20,
+    DW_OP_or = 0x21,
+    DW_OP_plus = 0x22,
+    DW_OP_plus_uconst = 0x23,
+    DW_OP_shl = 0x24,
+    DW_OP_shr = 0x25,
+    DW_OP_shra = 0x26,
+    DW_OP_xor = 0x27,
+    DW_OP_bra = 0x28,
+    DW_OP_eq = 0x29,
+    DW_OP_ge = 0x2a,
+    DW_OP_gt = 0x2b,
+    DW_OP_le = 0x2c,
+    DW_OP_lt = 0x2d,
+    DW_OP_ne = 0x2e,
+    DW_OP_skip = 0x2f,
+    DW_OP_lit0 = 0x30,
+    DW_OP_lit1 = 0x31,
+    DW_OP_lit2 = 0x32,
+    DW_OP_lit3 = 0x33,
+    DW_OP_lit4 = 0x34,
+    DW_OP_lit5 = 0x35,
+    DW_OP_lit6 = 0x36,
+    DW_OP_lit7 = 0x37,
+    DW_OP_lit8 = 0x38,
+    DW_OP_lit9 = 0x39,
+    DW_OP_lit10 = 0x3a,
+    DW_OP_lit11 = 0x3b,
+    DW_OP_lit12 = 0x3c,
+    DW_OP_lit13 = 0x3d,
+    DW_OP_lit14 = 0x3e,
+    DW_OP_lit15 = 0x3f,
+    DW_OP_lit16 = 0x40,
+    DW_OP_lit17 = 0x41,
+    DW_OP_lit18 = 0x42,
+    DW_OP_lit19 = 0x43,
+    DW_OP_lit20 = 0x44,
+    DW_OP_lit21 = 0x45,
+    DW_OP_lit22 = 0x46,
+    DW_OP_lit23 = 0x47,
+    DW_OP_lit24 = 0x48,
+    DW_OP_lit25 = 0x49,
+    DW_OP_lit26 = 0x4a,
+    DW_OP_lit27 = 0x4b,
+    DW_OP_lit28 = 0x4c,
+    DW_OP_lit29 = 0x4d,
+    DW_OP_lit30 = 0x4e,
+    DW_OP_lit31 = 0x4f,
+    DW_OP_reg0 = 0x50,
+    DW_OP_reg1 = 0x51,
+    DW_OP_reg2 = 0x52,
+    DW_OP_reg3 = 0x53,
+    DW_OP_reg4 = 0x54,
+    DW_OP_reg5 = 0x55,
+    DW_OP_reg6 = 0x56,
+    DW_OP_reg7 = 0x57,
+    DW_OP_reg8 = 0x58,
+    DW_OP_reg9 = 0x59,
+    DW_OP_reg10 = 0x5a,
+    DW_OP_reg11 = 0x5b,
+    DW_OP_reg12 = 0x5c,
+    DW_OP_reg13 = 0x5d,
+    DW_OP_reg14 = 0x5e,
+    DW_OP_reg15 = 0x5f,
+    DW_OP_reg16 = 0x60,
+    DW_OP_reg17 = 0x61,
+    DW_OP_reg18 = 0x62,
+    DW_OP_reg19 = 0x63,
+    DW_OP_reg20 = 0x64,
+    DW_OP_reg21 = 0x65,
+    DW_OP_reg22 = 0x66,
+    DW_OP_reg23 = 0x67,
+    DW_OP_reg24 = 0x68,
+    DW_OP_reg25 = 0x69,
+    DW_OP_reg26 = 0x6a,
+    DW_OP_reg27 = 0x6b,
+    DW_OP_reg28 = 0x6c,
+    DW_OP_reg29 = 0x6d,
+    DW_OP_reg30 = 0x6e,
+    DW_OP_reg31 = 0x6f,
+    DW_OP_breg0 = 0x70,
+    DW_OP_breg1 = 0x71,
+    DW_OP_breg2 = 0x72,
+    DW_OP_breg3 = 0x73,
+    DW_OP_breg4 = 0x74,
+    DW_OP_breg5 = 0x75,
+    DW_OP_breg6 = 0x76,
+    DW_OP_breg7 = 0x77,
+    DW_OP_breg8 = 0x78,
+    DW_OP_breg9 = 0x79,
+    DW_OP_breg10 = 0x7a,
+    DW_OP_breg11 = 0x7b,
+    DW_OP_breg12 = 0x7c,
+    DW_OP_breg13 = 0x7d,
+    DW_OP_breg14 = 0x7e,
+    DW_OP_breg15 = 0x7f,
+    DW_OP_breg16 = 0x80,
+    DW_OP_breg17 = 0x81,
+    DW_OP_breg18 = 0x82,
+    DW_OP_breg19 = 0x83,
+    DW_OP_breg20 = 0x84,
+    DW_OP_breg21 = 0x85,
+    DW_OP_breg22 = 0x86,
+    DW_OP_breg23 = 0x87,
+    DW_OP_breg24 = 0x88,
+    DW_OP_breg25 = 0x89,
+    DW_OP_breg26 = 0x8a,
+    DW_OP_breg27 = 0x8b,
+    DW_OP_breg28 = 0x8c,
+    DW_OP_breg29 = 0x8d,
+    DW_OP_breg30 = 0x8e,
+    DW_OP_breg31 = 0x8f,
+    DW_OP_regx = 0x90,
+    DW_OP_fbreg = 0x91,
+    DW_OP_bregx = 0x92,
+    DW_OP_piece = 0x93,
+    DW_OP_deref_size = 0x94,
+    DW_OP_xderef_size = 0x95,
+    DW_OP_nop = 0x96,
+    /* DWARF 3 extensions.  */
+    DW_OP_push_object_address = 0x97,
+    DW_OP_call2 = 0x98,
+    DW_OP_call4 = 0x99,
+    DW_OP_call_ref = 0x9a,
+    /* GNU extensions.  */
+    DW_OP_GNU_push_tls_address = 0xe0,
+    /* HP extensions.  */
+    DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
+    DW_OP_HP_is_value    = 0xe1,
+    DW_OP_HP_fltconst4   = 0xe2,
+    DW_OP_HP_fltconst8   = 0xe3,
+    DW_OP_HP_mod_range   = 0xe4,
+    DW_OP_HP_unmod_range = 0xe5,
+    DW_OP_HP_tls         = 0xe6
+  };
+
+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.  */
+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
+
+/* Type encodings.  */
+enum dwarf_type
+  {
+    DW_ATE_void = 0x0,
+    DW_ATE_address = 0x1,
+    DW_ATE_boolean = 0x2,
+    DW_ATE_complex_float = 0x3,
+    DW_ATE_float = 0x4,
+    DW_ATE_signed = 0x5,
+    DW_ATE_signed_char = 0x6,
+    DW_ATE_unsigned = 0x7,
+    DW_ATE_unsigned_char = 0x8,
+    /* DWARF 3.  */
+    DW_ATE_imaginary_float = 0x9,
+    /* HP extensions.  */
+    DW_ATE_HP_float80            = 0x80, /* Floating-point (80 bit).  */
+    DW_ATE_HP_complex_float80    = 0x81, /* Complex floating-point (80 bit).  */
+    DW_ATE_HP_float128           = 0x82, /* Floating-point (128 bit).  */
+    DW_ATE_HP_complex_float128   = 0x83, /* Complex floating-point (128 bit).  */
+    DW_ATE_HP_floathpintel       = 0x84, /* Floating-point (82 bit IA64).  */
+    DW_ATE_HP_imaginary_float80  = 0x85,
+    DW_ATE_HP_imaginary_float128 = 0x86
+  };
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+enum dwarf_array_dim_ordering
+  {
+    DW_ORD_row_major = 0,
+    DW_ORD_col_major = 1
+  };
+
+/* Access attribute.  */
+enum dwarf_access_attribute
+  {
+    DW_ACCESS_public = 1,
+    DW_ACCESS_protected = 2,
+    DW_ACCESS_private = 3
+  };
+
+/* Visibility.  */
+enum dwarf_visibility_attribute
+  {
+    DW_VIS_local = 1,
+    DW_VIS_exported = 2,
+    DW_VIS_qualified = 3
+  };
+
+/* Virtuality.  */
+enum dwarf_virtuality_attribute
+  {
+    DW_VIRTUALITY_none = 0,
+    DW_VIRTUALITY_virtual = 1,
+    DW_VIRTUALITY_pure_virtual = 2
+  };
+
+/* Case sensitivity.  */
+enum dwarf_id_case
+  {
+    DW_ID_case_sensitive = 0,
+    DW_ID_up_case = 1,
+    DW_ID_down_case = 2,
+    DW_ID_case_insensitive = 3
+  };
+
+/* Calling convention.  */
+enum dwarf_calling_convention
+  {
+    DW_CC_normal = 0x1,
+    DW_CC_program = 0x2,
+    DW_CC_nocall = 0x3
+  };
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute.  */
+enum dwarf_inline_attribute
+  {
+    DW_INL_not_inlined = 0,
+    DW_INL_inlined = 1,
+    DW_INL_declared_not_inlined = 2,
+    DW_INL_declared_inlined = 3
+  };
+
+/* Discriminant lists.  */
+enum dwarf_discrim_list
+  {
+    DW_DSC_label = 0,
+    DW_DSC_range = 1
+  };
+
+/* Line number opcodes.  */
+enum dwarf_line_number_ops
+  {
+    DW_LNS_extended_op = 0,
+    DW_LNS_copy = 1,
+    DW_LNS_advance_pc = 2,
+    DW_LNS_advance_line = 3,
+    DW_LNS_set_file = 4,
+    DW_LNS_set_column = 5,
+    DW_LNS_negate_stmt = 6,
+    DW_LNS_set_basic_block = 7,
+    DW_LNS_const_add_pc = 8,
+    DW_LNS_fixed_advance_pc = 9,
+    /* DWARF 3.  */
+    DW_LNS_set_prologue_end = 10,
+    DW_LNS_set_epilogue_begin = 11,
+    DW_LNS_set_isa = 12
+  };
+
+/* Line number extended opcodes.  */
+enum dwarf_line_number_x_ops
+  {
+    DW_LNE_end_sequence = 1,
+    DW_LNE_set_address = 2,
+    DW_LNE_define_file = 3,
+    /* HP extensions.  */
+    DW_LNE_HP_negate_is_UV_update      = 0x11,
+    DW_LNE_HP_push_context             = 0x12,
+    DW_LNE_HP_pop_context              = 0x13,
+    DW_LNE_HP_set_file_line_column     = 0x14,
+    DW_LNE_HP_set_routine_name         = 0x15,
+    DW_LNE_HP_set_sequence             = 0x16,
+    DW_LNE_HP_negate_post_semantics    = 0x17,
+    DW_LNE_HP_negate_function_exit     = 0x18,
+    DW_LNE_HP_negate_front_end_logical = 0x19,
+    DW_LNE_HP_define_proc              = 0x20
+  };
+
+/* Call frame information.  */
+enum dwarf_call_frame_info
+  {
+    DW_CFA_advance_loc = 0x40,
+    DW_CFA_offset = 0x80,
+    DW_CFA_restore = 0xc0,
+    DW_CFA_nop = 0x00,
+    DW_CFA_set_loc = 0x01,
+    DW_CFA_advance_loc1 = 0x02,
+    DW_CFA_advance_loc2 = 0x03,
+    DW_CFA_advance_loc4 = 0x04,
+    DW_CFA_offset_extended = 0x05,
+    DW_CFA_restore_extended = 0x06,
+    DW_CFA_undefined = 0x07,
+    DW_CFA_same_value = 0x08,
+    DW_CFA_register = 0x09,
+    DW_CFA_remember_state = 0x0a,
+    DW_CFA_restore_state = 0x0b,
+    DW_CFA_def_cfa = 0x0c,
+    DW_CFA_def_cfa_register = 0x0d,
+    DW_CFA_def_cfa_offset = 0x0e,
+    /* DWARF 3.  */
+    DW_CFA_def_cfa_expression = 0x0f,
+    DW_CFA_expression = 0x10,
+    DW_CFA_offset_extended_sf = 0x11,
+    DW_CFA_def_cfa_sf = 0x12,
+    DW_CFA_def_cfa_offset_sf = 0x13,
+    /* SGI/MIPS specific.  */
+    DW_CFA_MIPS_advance_loc8 = 0x1d,
+    /* GNU extensions.  */
+    DW_CFA_GNU_window_save = 0x2d,
+    DW_CFA_GNU_args_size = 0x2e,
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+  };
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_lo_user    0x1c
+#define DW_CFA_hi_user    0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+enum dwarf_source_language
+  {
+    DW_LANG_C89 = 0x0001,
+    DW_LANG_C = 0x0002,
+    DW_LANG_Ada83 = 0x0003,
+    DW_LANG_C_plus_plus = 0x0004,
+    DW_LANG_Cobol74 = 0x0005,
+    DW_LANG_Cobol85 = 0x0006,
+    DW_LANG_Fortran77 = 0x0007,
+    DW_LANG_Fortran90 = 0x0008,
+    DW_LANG_Pascal83 = 0x0009,
+    DW_LANG_Modula2 = 0x000a,
+    DW_LANG_Java = 0x000b,
+    /* DWARF 3.  */
+    DW_LANG_C99 = 0x000c,
+    DW_LANG_Ada95 = 0x000d,
+    DW_LANG_Fortran95 = 0x000e,
+    /* MIPS.  */
+    DW_LANG_Mips_Assembler = 0x8001,
+    /* UPC.  */
+    DW_LANG_Upc = 0x8765
+  };
+
+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.  */
+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.  */
+
+/* Names and codes for macro information.  */
+enum dwarf_macinfo_record_type
+  {
+    DW_MACINFO_define = 1,
+    DW_MACINFO_undef = 2,
+    DW_MACINFO_start_file = 3,
+    DW_MACINFO_end_file = 4,
+    DW_MACINFO_vendor_ext = 255
+  };
+\f
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
+
+#endif /* _ELF_DWARF2_H */
diff -puN /dev/null include/linux/dwarf2-lang.h
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/include/linux/dwarf2-lang.h	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,301 @@
+#ifndef DWARF2_LANG
+#define DWARF2_LANG
+
+/*
+ * This 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 file defines macros that allow generation of DWARF debug records
+ * for asm files.  This file is platform independent.  Register numbers
+ * (which are about the only thing that is platform dependent) are to be
+ * supplied by a platform defined file.
+ */
+/*
+ * We need this to work for both asm and C.  In asm we are using the
+ * old comment trick to concatenate while C uses the new ANSI thing.
+ * Here we have concat macro...  The multi level thing is to allow and
+ * macros used in the names to be resolved prior to the cat (at which
+ * time they are no longer the same string).
+ */
+#define CAT3(a,b,c) _CAT3(a,b,c)
+#define _CAT3(a,b,c) __CAT3(a,b,c)
+#ifndef __STDC__
+#define __CAT3(a,b,c) a/**/b/**/c
+#else
+#define __CAT3(a,b,c) a##b##c
+#endif
+#ifdef __ASSEMBLY__
+#define IFC(a)
+#define IFN_C(a) a
+#define NL ;
+#define QUOTE_THIS(a) a
+#define DWARF_preamble .section .debug_frame,"",%progbits;
+#else
+#define IFC(a) a
+#define IFN_C(a)
+#define NL \n\t
+#define QUOTE_THIS(a) _QUOTE_THIS(a)
+#define _QUOTE_THIS(a) #a
+/* Don't let CPP see the " and , \042=" \054=, */
+#define DWARF_preamble .section .debug_frame \054\042\042\054%progbits
+#endif
+
+#ifdef CONFIG_64BIT
+#define DATA_ALIGN_FACTOR	8
+#define ADDR_LOC		.quad
+#else
+#define DATA_ALIGN_FACTOR	4
+#define ADDR_LOC		.long
+#endif
+
+#include <linux/dwarf2-defs.h>
+/*
+ * This macro starts a debug frame section.  The debug_frame describes
+ * where to find the registers that the enclosing function saved on
+ * entry.
+ *
+ * ORD is use by the label generator and should be the same as what is
+ * passed to CFI_postamble.
+ *
+ * pc,	pc register gdb ordinal.
+ *
+ * code_align this is the factor used to define locations or regions
+ * where the given definitions apply.  If you use labels to define these
+ * this should be 1.
+ *
+ * data_align this is the factor used to define register offsets.  If
+ * you use struct offset, this should be the size of the register in
+ * bytes or the negative of that.  This is how it is used: you will
+ * define a register as the reference register, say the stack pointer,
+ * then you will say where a register is located relative to this
+ * reference registers value, say 40 for register 3 (the gdb register
+ * number).  The <40> will be multiplied by <data_align> to define the
+ * byte offset of the given register (3, in this example).  So if your
+ * <40> is the byte offset and the reference register points at the
+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
+ * 4-byte element in that structure you would want 4.  And if your
+ * reference register points at the end of the structure you would want
+ * a negative data_align value(and you would have to do other math as
+ * well).
+ */
+
+#define CFI_preamble(ORD, pc, code_align, data_align)	\
+         DWARF_preamble	NL				\
+	.align DATA_ALIGN_FACTOR NL			\
+        .globl CAT3(frame,_,ORD) NL			\
+CAT3(frame,_,ORD): NL					\
+	.long 7f-6f NL					\
+6:							\
+	.long	DW_CIE_ID NL				\
+	.byte	DW_CIE_VERSION NL			\
+	.byte 0	 NL					\
+	.uleb128 code_align NL				\
+	.sleb128 data_align NL				\
+	.byte pc NL
+
+/*
+ * After the above macro and prior to the CFI_postamble, you need to
+ * define the initial state.  This starts with defining the reference
+ * register and, usually the pc.  Here are some helper macros:
+ */
+
+#define CFA_define_reference(reg, offset)	\
+	.byte DW_CFA_def_cfa NL			\
+	.uleb128 reg NL				\
+	.uleb128 (offset) NL
+
+#define CFA_define_offset(reg, offset)		\
+	.byte (DW_CFA_offset + reg) NL		\
+	.uleb128 (offset) NL
+
+#define CFA_restore(reg)			\
+        .byte (DW_CFA_restore + reg) NL
+
+#define CFI_postamble()				\
+	.align DATA_ALIGN_FACTOR NL				\
+7: NL						\
+.previous NL
+
+/*
+ * So now your code pushs stuff on the stack, you need a new location
+ * and the rules for what to do.  This starts a running description of
+ * the call frame.  You need to describe what changes with respect to
+ * the call registers as the location of the pc moves through the code.
+ * The following builds an FDE (fram descriptor entry?).  Like the
+ * above, it has a preamble and a postamble.  It also is tied to the CFI
+ * above.
+ * The preamble macro is tied to the CFI thru the first parameter.  The
+ * second is the code start address and then the code end address+1.
+ */
+//         DWARF_preamble() NL
+#define FDE_preamble(ORD, initial_address, end_address)	\
+        DWARF_preamble NL				\
+	.align DATA_ALIGN_FACTOR NL					\
+	.long 9f-8f NL					\
+8:							\
+	.long CAT3(frame,_,ORD) NL			\
+	ADDR_LOC initial_address NL			\
+	ADDR_LOC (end_address - initial_address) NL
+
+#define FDE_postamble()				\
+	.align DATA_ALIGN_FACTOR NL				\
+9:	 NL					\
+.previous NL
+
+/*
+ * That done, you can now add registers, subtract registers, move the
+ * reference and even change the reference.  You can also define a new
+ * area of code the info applies to.  For discontinuous bits you should
+ * start a new FDE.  You may have as many as you like.
+ */
+
+/*
+ * To advance the stack address by <bytes> (0x3f max)
+ */
+
+#define CFA_advance_loc(bytes)			\
+	.byte DW_CFA_advance_loc+bytes NL
+
+/*
+ * This one is good for 0xff or 255
+ */
+#define CFA_advance_loc1(bytes)			\
+	.byte DW_CFA_advance_loc1 NL		\
+        .byte bytes NL
+
+#define CFA_undefine_reg(reg)			\
+        .byte DW_CFA_undefined NL		\
+	.uleb128 reg NL
+/*
+ * With the above you can define all the register locations.  But
+ * suppose the reference register moves... Takes the new offset NOT an
+ * increment.  This is how esp is tracked if it is not saved.
+ */
+
+#define CFA_define_cfa_offset(offset)		\
+	.byte DW_CFA_def_cfa_offset NL		\
+	.uleb128 (offset) NL
+/*
+ * Or suppose you want to use a different reference register...
+ */
+#define CFA_define_cfa_register(reg)		\
+	.byte DW_CFA_def_cfa_register NL	\
+	.uleb128 reg NL
+
+/*
+ * If you want to mess with the stack pointer, here is the expression.
+ * The stack starts empty.
+ */
+#define CFA_def_cfa_expression 			\
+        .byte DW_CFA_def_cfa_expression	NL	\
+	.uleb128 20f-10f NL			\
+10:     NL
+/*
+ * This expression is to be used for other regs.  The stack starts with the
+ * stack address.
+ */
+
+#define CFA_expression(reg)			\
+        .byte DW_CFA_expression	 NL		\
+        .uleb128 reg NL				\
+	.uleb128 20f-10f NL			\
+10:     NL
+/*
+ * Here we do the expression stuff.  You should code the above followed
+ *  by expression OPs followed by CFA_expression_end.
+ */
+
+
+#define CFA_expression_end			\
+20:	 NL
+
+#define CFA_exp_OP_const4s(a)			\
+        .byte DW_OP_const4s NL			\
+        .long a NL
+
+#define  CFA_exp_OP_swap  .byte DW_OP_swap NL
+#define  CFA_exp_OP_dup  .byte DW_OP_dup NL
+#define  CFA_exp_OP_drop  .byte DW_OP_drop NL
+/*
+ * All these work on the top two elements on the stack, replacing them
+ * with the result.  Top comes first where it matters.  True is 1, false 0.
+ */
+#define  CFA_exp_OP_deref .byte DW_OP_deref NL
+#define  CFA_exp_OP_and   .byte DW_OP_and NL
+#define  CFA_exp_OP_div   .byte DW_OP_div NL
+#define  CFA_exp_OP_minus .byte DW_OP_minus NL
+#define  CFA_exp_OP_mod   .byte DW_OP_mod NL
+#define  CFA_exp_OP_neg   .byte DW_OP_neg NL
+#define  CFA_exp_OP_plus  .byte DW_OP_plus NL
+#define  CFA_exp_OP_not   .byte DW_OP_not NL
+#define  CFA_exp_OP_or    .byte DW_OP_or NL
+#define  CFA_exp_OP_xor   .byte DW_OP_xor NL
+#define  CFA_exp_OP_le    .byte DW_OP_le NL
+#define  CFA_exp_OP_ge    .byte DW_OP_ge NL
+#define  CFA_exp_OP_eq    .byte DW_OP_eq NL
+#define  CFA_exp_OP_lt    .byte DW_OP_lt NL
+#define  CFA_exp_OP_gt    .byte DW_OP_gt NL
+#define  CFA_exp_OP_ne    .byte DW_OP_ne NL
+/*
+ * These take a parameter as noted
+ */
+/*
+ * Unconditional skip to loc. loc is a label (loc:)
+ */
+#define CFA_exp_OP_skip(loc)			\
+         .byte DW_OP_skip  NL 			\
+	 .hword  loc-.-2 NL
+/*
+ * Conditional skip to loc (TOS != 0, TOS--) (loc is a label)
+ */
+#define CFA_exp_OP_bra(loc)			\
+         .byte DW_OP_bra NL			\
+	 .hword loc-.-2 NL
+
+/*
+ * TOS += no (an unsigned number)
+ */
+#define CFA_exp_OP_plus_uconst(no)		\
+         .byte DW_OP_plus_uconst NL		\
+         .uleb128 no NL
+
+/*
+ * ++TOS = no (a unsigned number)
+ */
+#define CFA_exp_OP_constu(no)			\
+         .byte DW_OP_constu NL			\
+	 .uleb128 no NL
+/*
+ * ++TOS = no (a signed number)
+ */
+#define CFA_exp_OP_consts(no)			\
+         .byte DW_OP_consts NL			\
+	 .sleb128 no NL
+/*
+ * ++TOS = no (an unsigned byte)
+ */
+#define CFA_exp_OP_const1u(no)			\
+         .byte DW_OP_const1u NL			\
+	 .byte no NL
+
+
+/*
+ * ++TOS = no (a address)
+ */
+#define CFA_exp_OP_addr(no)			\
+         .byte DW_OP_addr NL			\
+	 .long no NL
+
+/*
+ * Push current frames value for "reg" + offset
+ * We take advantage of the opcode assignments to make this a litteral reg
+ * rather than use the DW_OP_bregx opcode.
+ */
+
+#define CFA_exp_OP_breg(reg,offset)		\
+         .byte DW_OP_breg0+reg NL		\
+         .sleb128 offset NL
+#endif
diff -puN Makefile~cfi_annotations Makefile
--- linux-2.6.13/Makefile~cfi_annotations	2005-08-08 19:16:03.000000000 -0700
+++ linux-2.6.13-trini/Makefile	2005-08-08 19:16:03.000000000 -0700
@@ -1345,5 +1345,8 @@ clean := -f $(if $(KBUILD_SRC),$(srctree
 descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=$(1) $(2)
 
 endif	# skip-makefile
+include/linux/dwarf2-defs.h: $(srctree)/include/linux/dwarf2.h $(srctree)/scripts/dwarfh.awk
+	mkdir -p include/linux/
+	awk -f $(srctree)/scripts/dwarfh.awk $(srctree)/include/linux/dwarf2.h > include/linux/dwarf2-defs.h
 
-FORCE:
+FORCE: include/linux/dwarf2-defs.h
diff -puN /dev/null scripts/dwarfh.awk
--- /dev/null	2005-08-08 08:07:04.272443000 -0700
+++ linux-2.6.13-trini/scripts/dwarfh.awk	2005-08-08 19:16:03.000000000 -0700
@@ -0,0 +1,19 @@
+BEGIN {
+	print "#ifndef  _ELF_DWARF_H"
+		print "/* Machine generated from dwarf2.h by scripts/dwarfh.awk */"
+}
+$2 == "=" {
+	gsub(/,/, "", $3)
+	print "#define " $1 "\t " $3
+}
+$1 == "#define" {
+	print $0
+	while( index($0,"\\") == length($0)){
+		getline
+		print $0
+	}
+}
+/.*/ {}
+END {
+	print "#endif"
+}
_

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

* [patch 14/16] Minor SysRq keyboard bugfix for KGDB
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (11 preceding siblings ...)
  2005-08-29 16:11   ` [patch 13/16] Add CFI DWARF2 annotation support Tom Rini
@ 2005-08-29 16:11   ` Tom Rini
  2005-08-29 16:11   ` [patch 15/16] Allow KGDB to work well with loaded modules Tom Rini
  2005-08-29 16:12   ` [patch 16/16] Add hardware breakpoint support for i386 Tom Rini
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini, george


CC: George Anzginer <george@mvista.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.

---

 linux-2.6.13-trini/drivers/char/keyboard.c |    1 +
 1 files changed, 1 insertion(+)

diff -puN drivers/char/keyboard.c~sysrq_bugfix drivers/char/keyboard.c
--- linux-2.6.13/drivers/char/keyboard.c~sysrq_bugfix	2005-08-08 19:16:04.000000000 -0700
+++ linux-2.6.13-trini/drivers/char/keyboard.c	2005-08-08 19:16:04.000000000 -0700
@@ -1070,6 +1070,7 @@ static void kbd_keycode(unsigned int key
 	}
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+		sysrq_down = 0;		/* In case we miss the 'up' event. */
 		return;
 	}
 #endif
_

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

* [patch 15/16] Allow KGDB to work well with loaded modules
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (12 preceding siblings ...)
  2005-08-29 16:11   ` [patch 14/16] Minor SysRq keyboard bugfix for KGDB Tom Rini
@ 2005-08-29 16:11   ` Tom Rini
  2005-08-29 16:12   ` [patch 16/16] Add hardware breakpoint support for i386 Tom Rini
  14 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:11 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini


This allows for KGDB to better deal with autoloaded modules.  The way this
works, requires a patch to GDB.  This patch can be found at
ftp://source.mvista.com/pub/kgdb/gdb-6.3-kgdb-module-notification.patch

The way this works is that the solib-search-path must contain the location of
any module to be debugged, and then when a module is loaded GDB acts like a
shared library has been loaded now, and can be used that way.

---

 linux-2.6.13-trini/include/linux/module.h |   16 ++++++++
 linux-2.6.13-trini/kernel/module.c        |   56 ++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff -puN include/linux/module.h~module include/linux/module.h
--- linux-2.6.13/include/linux/module.h~module	2005-08-29 09:03:42.000000000 -0700
+++ linux-2.6.13-trini/include/linux/module.h	2005-08-29 09:03:42.000000000 -0700
@@ -210,8 +210,17 @@ enum module_state
 	MODULE_STATE_LIVE,
 	MODULE_STATE_COMING,
 	MODULE_STATE_GOING,
+ 	MODULE_STATE_GONE,
 };
 
+#ifdef CONFIG_KGDB
+#define MAX_SECTNAME 31
+struct mod_section {
+       void *address;
+       char name[MAX_SECTNAME + 1];
+};
+#endif
+
 /* Similar stuff for section attributes. */
 #define MODULE_SECT_NAME_LEN 32
 struct module_sect_attr
@@ -239,6 +248,13 @@ struct module
 	/* Unique handle for this module */
 	char name[MODULE_NAME_LEN];
 
+#ifdef CONFIG_KGDB
+	/* keep kgdb info at the begining so that gdb doesn't have a chance to
+	 * miss out any fields */
+	unsigned long num_sections;
+	struct mod_section *mod_sections;
+#endif
+
 	/* Sysfs stuff. */
 	struct module_kobject mkobj;
 	struct module_param_attrs *param_attrs;
diff -puN kernel/module.c~module kernel/module.c
--- linux-2.6.13/kernel/module.c~module	2005-08-29 09:03:42.000000000 -0700
+++ linux-2.6.13-trini/kernel/module.c	2005-08-29 09:03:42.000000000 -0700
@@ -623,6 +623,12 @@ sys_delete_module(const char __user *nam
 	if (ret != 0)
 		goto out;
 
+	down(&notify_mutex);
+	notifier_call_chain(&module_notify_list, MODULE_STATE_GOING,
+        			mod);
+	up(&notify_mutex);
+
+
 	/* Never wait if forced. */
 	if (!forced && module_refcount(mod) != 0)
 		wait_for_zero_refcount(mod);
@@ -635,6 +641,11 @@ sys_delete_module(const char __user *nam
 	}
 	free_module(mod);
 
+	down(&notify_mutex);
+	notifier_call_chain(&module_notify_list, MODULE_STATE_GONE,
+			NULL);
+	up(&notify_mutex);
+
  out:
 	up(&module_mutex);
 	return ret;
@@ -1173,6 +1184,11 @@ static void free_module(struct module *m
 	/* Arch-specific cleanup. */
 	module_arch_cleanup(mod);
 
+#ifdef CONFIG_KGDB
+	/* kgdb info */
+	vfree(mod->mod_sections);
+#endif
+
 	/* Module unload stuff */
 	module_unload_free(mod);
 
@@ -1407,6 +1423,31 @@ static void setup_modinfo(struct module 
 }
 #endif
 
+#ifdef CONFIG_KGDB
+int add_modsects (struct module *mod, Elf_Ehdr *hdr, Elf_Shdr *sechdrs, const
+                char *secstrings)
+{
+        int i;
+
+        mod->num_sections = hdr->e_shnum - 1;
+        mod->mod_sections = vmalloc((hdr->e_shnum - 1)*
+		sizeof (struct mod_section));
+
+        if (mod->mod_sections == NULL) {
+                return -ENOMEM;
+        }
+
+        for (i = 1; i < hdr->e_shnum; i++) {
+                mod->mod_sections[i - 1].address = (void *)sechdrs[i].sh_addr;
+                strncpy(mod->mod_sections[i - 1].name, secstrings +
+                                sechdrs[i].sh_name, MAX_SECTNAME);
+                mod->mod_sections[i - 1].name[MAX_SECTNAME] = '\0';
+	}
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
@@ -1775,6 +1816,12 @@ static struct module *load_module(void _
 
 	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
+#ifdef CONFIG_KGDB
+        if ((err = add_modsects(mod, hdr, sechdrs, secstrings)) < 0) {
+                goto nomodsectinfo;
+        }
+#endif
+
 	err = module_finalize(hdr, sechdrs, mod);
 	if (err < 0)
 		goto cleanup;
@@ -1822,6 +1869,11 @@ static struct module *load_module(void _
  arch_cleanup:
 	module_arch_cleanup(mod);
  cleanup:
+
+#ifdef CONFIG_KGDB
+nomodsectinfo:
+       vfree(mod->mod_sections);
+#endif
 	module_unload_free(mod);
 	module_free(mod, mod->module_init);
  free_core:
@@ -1909,6 +1961,10 @@ sys_init_module(void __user *umod,
 		/* Init routine failed: abort.  Try to protect us from
                    buggy refcounters. */
 		mod->state = MODULE_STATE_GOING;
+		down(&notify_mutex);
+		notifier_call_chain(&module_notify_list, MODULE_STATE_GOING,
+				mod);
+		up(&notify_mutex);
 		synchronize_sched();
 		if (mod->unsafe)
 			printk(KERN_ERR "%s: module is now stuck!\n",
_

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

* [patch 16/16] Add hardware breakpoint support for i386
       [not found] ` <1.2982005.trini@kernel.crashing.org>
                     ` (13 preceding siblings ...)
  2005-08-29 16:11   ` [patch 15/16] Allow KGDB to work well with loaded modules Tom Rini
@ 2005-08-29 16:12   ` Tom Rini
  2005-08-29 21:23     ` Andi Kleen
  2005-08-30  1:06     ` Keith Owens
  14 siblings, 2 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:12 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, trini


This adds hardware breakpoint support for i386.  This is not as well tested as
software breakpoints, but in some minimal testing appears to be functional.

---

 linux-2.6.13-trini/arch/i386/kernel/kgdb.c |   49 +++++++++++++++++++++++++
 1 files changed, 49 insertions(+)

diff -puN arch/i386/kernel/kgdb.c~i386 arch/i386/kernel/kgdb.c
--- linux-2.6.13/arch/i386/kernel/kgdb.c~i386	2005-08-10 10:53:22.000000000 -0700
+++ linux-2.6.13-trini/arch/i386/kernel/kgdb.c	2005-08-10 10:53:22.000000000 -0700
@@ -184,6 +184,54 @@ void kgdb_correct_hw_break(void)
 		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
 }
 
+int kgdb_remove_hw_break(unsigned long addr)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 0;
+	return 0;
+}
+
+void kgdb_remove_all_hw_break(void)
+{
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if (breakinfo[i].enabled) {
+			/* Do what? */
+			;
+		}
+		memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
+	}
+}
+
+int kgdb_set_hw_break(unsigned long addr)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (!breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 1;
+	breakinfo[idx].type = 1;
+	breakinfo[idx].len = 1;
+	breakinfo[idx].addr = addr;
+	return 0;
+}
+
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
 	/* Disable hardware debugging while we are in kgdb */
@@ -298,4 +346,5 @@ int kgdb_arch_init(void)
 
 struct kgdb_arch arch_kgdb_ops = {
 	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
 };
_

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-29 16:09   ` [patch 04/16] I/O driver for 8250-compatible UARTs Tom Rini
@ 2005-08-29 16:18     ` Russell King
  2005-08-29 16:28       ` Tom Rini
  2005-08-31 19:38     ` Bjorn Helgaas
  1 sibling, 1 reply; 37+ messages in thread
From: Russell King @ 2005-08-29 16:18 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel

On Mon, Aug 29, 2005 at 09:09:37AM -0700, Tom Rini wrote:
> This is the I/O driver for any 8250-compatible UARTs.

Ah, obviously its patchbomb time.  2.6.13 must have been released! 8)

I wish for this stuff to wait until my queue of stuff has gone to
Linus first - otherwise Linus will probably have a merge headache
on his hands... unless these patches are against the -mm kernels.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-29 16:18     ` Russell King
@ 2005-08-29 16:28       ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 16:28 UTC (permalink / raw)
  To: akpm, linux-kernel

On Mon, Aug 29, 2005 at 05:18:17PM +0100, Russell King wrote:
> On Mon, Aug 29, 2005 at 09:09:37AM -0700, Tom Rini wrote:
> > This is the I/O driver for any 8250-compatible UARTs.
> 
> Ah, obviously its patchbomb time.  2.6.13 must have been released! 8)
> 
> I wish for this stuff to wait until my queue of stuff has gone to
> Linus first - otherwise Linus will probably have a merge headache
> on his hands... unless these patches are against the -mm kernels.

I forsee it as being unlikely that this will hit Linus' tree without
sometime spent in -mm, and probably more time than it will take for your
queue to drain.  But, these are unlikey to cause a headache (new func,
extern for said func, Kconfig around SERIAL_8250_NR_UARTS, it really is
simplier than before :))

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 08/16] Add support for X86_64 platforms to KGDB
  2005-08-29 16:10   ` [patch 08/16] Add support for X86_64 platforms to KGDB Tom Rini
@ 2005-08-29 17:13     ` Andi Kleen
  2005-08-29 17:45       ` Tom Rini
  0 siblings, 1 reply; 37+ messages in thread
From: Andi Kleen @ 2005-08-29 17:13 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, amitkale

On Monday 29 August 2005 18:10, Tom Rini wrote:

> +void __init early_setup_per_cpu_area(void)
> +{
> +	static char cpu0[PERCPU_ENOUGH_ROOM]
> +		__attribute__ ((aligned (SMP_CACHE_BYTES)));
> +	char *ptr = cpu0;
> +
> +	cpu_pda[0].data_offset = ptr - __per_cpu_start;
> +	memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
> +}

What is that?  It looks totally bogus. Can you tell exactly where you
believe early per cpu data is needed?

> +
>  /*
>   * Great future plan:
>   * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
> @@ -97,7 +107,9 @@ void __init setup_per_cpu_areas(void)
>  	for (i = 0; i < NR_CPUS; i++) {
>  		char *ptr;
>
> -		if (!NODE_DATA(cpu_to_node(i))) {
> +		if (cpu_pda[i].data_offset)
> +			continue;

And that looks broken too.

In general I would also advise to mix any other changes outside kgdb* into the 
x86-64 kgdb patch. Either the patch should be merged into mainline in a 
separate patch or kgdb reworked to not need this.

> +	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> +				SIGSEGV) == NOTIFY_STOP)
> +		return;
> +

I can see the point of that. It's ok if you submit it as a separate patch.

Regarding early trap init: I would have no problem to move all of traps_init
into setup_arch (and leave traps_init empty for generic code). I actually
don't know why it runs so late. But doing it half way is ugly.

-Andi

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

* Re: [patch 08/16] Add support for X86_64 platforms to KGDB
  2005-08-29 17:13     ` Andi Kleen
@ 2005-08-29 17:45       ` Tom Rini
  2005-08-29 18:46         ` Andi Kleen
  0 siblings, 1 reply; 37+ messages in thread
From: Tom Rini @ 2005-08-29 17:45 UTC (permalink / raw)
  To: Andi Kleen; +Cc: akpm, linux-kernel, amitkale, Bob Picco

On Mon, Aug 29, 2005 at 07:13:47PM +0200, Andi Kleen wrote:
> On Monday 29 August 2005 18:10, Tom Rini wrote:
> 
> > +void __init early_setup_per_cpu_area(void)
> > +{
> > +	static char cpu0[PERCPU_ENOUGH_ROOM]
> > +		__attribute__ ((aligned (SMP_CACHE_BYTES)));
> > +	char *ptr = cpu0;
> > +
> > +	cpu_pda[0].data_offset = ptr - __per_cpu_start;
> > +	memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
> > +}
> 
> What is that?  It looks totally bogus. Can you tell exactly where you
> believe early per cpu data is needed?

Bob did this part (forgot to CC him, oops).  But I believe it's needed
for setting traps so much earlier.

> > +
> >  /*
> >   * Great future plan:
> >   * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
> > @@ -97,7 +107,9 @@ void __init setup_per_cpu_areas(void)
> >  	for (i = 0; i < NR_CPUS; i++) {
> >  		char *ptr;
> >
> > -		if (!NODE_DATA(cpu_to_node(i))) {
> > +		if (cpu_pda[i].data_offset)
> > +			continue;
> 
> And that looks broken too.

I believe that's to takecare of the case where something is covered in
early_setup_cpu_areas().

> In general I would also advise to mix any other changes outside kgdb* into the 
> x86-64 kgdb patch. Either the patch should be merged into mainline in a 
> separate patch or kgdb reworked to not need this.

ok.

> > +	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> > +				SIGSEGV) == NOTIFY_STOP)
> > +		return;
> > +
> 
> I can see the point of that. It's ok if you submit it as a separate patch.

I can split that out into one that follows the KDB_VECTOR rename easily
enough.

> Regarding early trap init: I would have no problem to move all of traps_init
> into setup_arch (and leave traps_init empty for generic code). I actually
> don't know why it runs so late. But doing it half way is ugly.

Should I make setup_per_cpu_area and trap_init empty and turn the real
ones into early_foo?

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 08/16] Add support for X86_64 platforms to KGDB
  2005-08-29 17:45       ` Tom Rini
@ 2005-08-29 18:46         ` Andi Kleen
  2005-08-29 18:49           ` Tom Rini
  0 siblings, 1 reply; 37+ messages in thread
From: Andi Kleen @ 2005-08-29 18:46 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, amitkale, Bob Picco

On Monday 29 August 2005 19:45, Tom Rini wrote:

>
> Bob did this part (forgot to CC him, oops).  But I believe it's needed
> for setting traps so much earlier.

Ok looking again I guess he needed it for the GDT access in cpu_init

> > > +	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> > > +				SIGSEGV) == NOTIFY_STOP)
> > > +		return;
> > > +
> >
> > I can see the point of that. It's ok if you submit it as a separate
> > patch.
>
> I can split that out into one that follows the KDB_VECTOR rename easily
> enough.

That's fine. The rename is fine for me too btw.

>
> > Regarding early trap init: I would have no problem to move all of
> > traps_init into setup_arch (and leave traps_init empty for generic code).
> > I actually don't know why it runs so late. But doing it half way is ugly.
>
> Should I make setup_per_cpu_area and trap_init empty and turn the real
> ones into early_foo?

setup_per_cpu_area is still needed later because it needs to allocate for non 
BP and you cannot do that that early. 

-Andi



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

* Re: [patch 08/16] Add support for X86_64 platforms to KGDB
  2005-08-29 18:46         ` Andi Kleen
@ 2005-08-29 18:49           ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 18:49 UTC (permalink / raw)
  To: Andi Kleen; +Cc: akpm, linux-kernel, amitkale, Bob Picco

On Mon, Aug 29, 2005 at 08:46:15PM +0200, Andi Kleen wrote:
> On Monday 29 August 2005 19:45, Tom Rini wrote:
> 
> >
> > Bob did this part (forgot to CC him, oops).  But I believe it's needed
> > for setting traps so much earlier.
> 
> Ok looking again I guess he needed it for the GDT access in cpu_init
> 
> > > > +	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> > > > +				SIGSEGV) == NOTIFY_STOP)
> > > > +		return;
> > > > +
> > >
> > > I can see the point of that. It's ok if you submit it as a separate
> > > patch.
> >
> > I can split that out into one that follows the KDB_VECTOR rename easily
> > enough.
> 
> That's fine. The rename is fine for me too btw.
> 
> >
> > > Regarding early trap init: I would have no problem to move all of
> > > traps_init into setup_arch (and leave traps_init empty for generic code).
> > > I actually don't know why it runs so late. But doing it half way is ugly.
> >
> > Should I make setup_per_cpu_area and trap_init empty and turn the real
> > ones into early_foo?
> 
> setup_per_cpu_area is still needed later because it needs to allocate for non 
> BP and you cannot do that that early. 

OK.  So I'll send out a patch that makes trap_init() empty and use the
early_setup_per_cpu_areas() Bob wrote as well.

Andrew: In sum, there will be 3 patches that replace the x86_64 main
patch (2 split-out-stuff, 1 new kgdb patch).

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 2/3] x86_64: Run setup_per_cpu_areas and trap_init sooner
  2005-08-29 16:09   ` [patch 02/16] Add support for i386 platforms to KGDB Tom Rini
@ 2005-08-29 19:55     ` Andi Kleen
  2005-08-29 20:03       ` Tom Rini
  0 siblings, 1 reply; 37+ messages in thread
From: Andi Kleen @ 2005-08-29 19:55 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, bob.picco


> +void __init early_setup_per_cpu_areas(void)
> +{
> +	static char cpu0[PERCPU_ENOUGH_ROOM]
> +		__attribute__ ((aligned (SMP_CACHE_BYTES)));

This needs a __cacheline_aligned too, otherwise there could be false sharing.

-Andi


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

* Re: [patch 2/3] x86_64: Run setup_per_cpu_areas and trap_init sooner
  2005-08-29 19:55     ` [patch 2/3] x86_64: Run setup_per_cpu_areas and trap_init sooner Andi Kleen
@ 2005-08-29 20:03       ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-29 20:03 UTC (permalink / raw)
  To: Andi Kleen; +Cc: akpm, linux-kernel, bob.picco

On Mon, Aug 29, 2005 at 09:55:00PM +0200, Andi Kleen wrote:
> 
> > +void __init early_setup_per_cpu_areas(void)
> > +{
> > +	static char cpu0[PERCPU_ENOUGH_ROOM]
> > +		__attribute__ ((aligned (SMP_CACHE_BYTES)));
> 
> This needs a __cacheline_aligned too, otherwise there could be false sharing.

Done, thanks:

CC: Andi Kleen <ak@suse.de>, Bob Picco <bob.picco@hp.com>
It can be handy in some situations to have run trap_init() sooner than the
generic code does.  In order to do this on x86_64 we need to add a custom
early_setup_per_cpu_areas() call as well.

---

 linux-2.6.13-trini/arch/x86_64/kernel/setup.c   |    3 +++
 linux-2.6.13-trini/arch/x86_64/kernel/setup64.c |   16 +++++++++++++++-
 linux-2.6.13-trini/arch/x86_64/kernel/traps.c   |    4 ++++
 linux-2.6.13-trini/include/asm-x86_64/proto.h   |    2 ++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff -puN arch/x86_64/kernel/setup.c~x86_64-early_funcs arch/x86_64/kernel/setup.c
--- linux-2.6.13/arch/x86_64/kernel/setup.c~x86_64-early_funcs	2005-08-29 12:39:49.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/setup.c	2005-08-29 12:39:49.000000000 -0700
@@ -525,6 +525,9 @@ void __init setup_arch(char **cmdline_p)
 {
 	unsigned long kernel_end;
 
+	early_setup_per_cpu_areas();
+	early_trap_init();
+
  	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
diff -puN arch/x86_64/kernel/setup64.c~x86_64-early_funcs arch/x86_64/kernel/setup64.c
--- linux-2.6.13/arch/x86_64/kernel/setup64.c~x86_64-early_funcs	2005-08-29 12:39:49.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/setup64.c	2005-08-29 13:01:52.000000000 -0700
@@ -77,7 +77,19 @@ static int __init nonx32_setup(char *str
 }
 __setup("noexec32=", nonx32_setup);
 
+void __init early_setup_per_cpu_areas(void)
+{
+	static char cpu0[PERCPU_ENOUGH_ROOM] __cacheline_aligned
+		__attribute__ ((aligned (SMP_CACHE_BYTES)));
+	char *ptr = cpu0;
+
+	cpu_pda[0].data_offset = ptr - __per_cpu_start;
+	memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+}
+
 /*
+ * We run this a bit sooner than the normal code, so provide a dummy
+ * function as well.
  * Great future plan:
  * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
  * Always point %gs to its beginning
@@ -97,7 +109,9 @@ void __init setup_per_cpu_areas(void)
 	for (i = 0; i < NR_CPUS; i++) { 
 		char *ptr;
 
-		if (!NODE_DATA(cpu_to_node(i))) {
+		if (cpu_pda[i].data_offset)
+			continue;
+		else if (!NODE_DATA(cpu_to_node(i))) {
 			printk("cpu with no node %d, num_online_nodes %d\n",
 			       i, num_online_nodes());
 			ptr = alloc_bootmem(size);
diff -puN arch/x86_64/kernel/traps.c~x86_64-early_funcs arch/x86_64/kernel/traps.c
--- linux-2.6.13/arch/x86_64/kernel/traps.c~x86_64-early_funcs	2005-08-29 12:39:49.000000000 -0700
+++ linux-2.6.13-trini/arch/x86_64/kernel/traps.c	2005-08-29 12:39:49.000000000 -0700
@@ -904,6 +904,10 @@ void do_call_debug(struct pt_regs *regs)
 
 void __init trap_init(void)
 {
+}
+
+void __init early_trap_init(void)
+{
 	set_intr_gate(0,&divide_error);
 	set_intr_gate_ist(1,&debug,DEBUG_STACK);
 	set_intr_gate_ist(2,&nmi,NMI_STACK);
diff -puN include/asm-x86_64/proto.h~x86_64-early_funcs include/asm-x86_64/proto.h
--- linux-2.6.13/include/asm-x86_64/proto.h~x86_64-early_funcs	2005-08-29 12:39:49.000000000 -0700
+++ linux-2.6.13-trini/include/asm-x86_64/proto.h	2005-08-29 12:39:49.000000000 -0700
@@ -10,6 +10,8 @@ struct pt_regs;
 
 extern void get_cpu_vendor(struct cpuinfo_x86*);
 extern void start_kernel(void);
+extern void early_trap_init(void);
+extern void early_setup_per_cpu_areas(void);
 extern void pda_init(int); 
 
 extern void early_idt_handler(void);

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 16/16] Add hardware breakpoint support for i386
  2005-08-29 16:12   ` [patch 16/16] Add hardware breakpoint support for i386 Tom Rini
@ 2005-08-29 21:23     ` Andi Kleen
  2005-08-31 14:39       ` Tom Rini
  2005-08-30  1:06     ` Keith Owens
  1 sibling, 1 reply; 37+ messages in thread
From: Andi Kleen @ 2005-08-29 21:23 UTC (permalink / raw)
  To: Tom Rini; +Cc: linux-kernel

Tom Rini <trini@kernel.crashing.org> writes:

> This adds hardware breakpoint support for i386.  This is not as well tested as
> software breakpoints, but in some minimal testing appears to be functional.

This really would need so coordination with user space using 
them. Otherwise it'll be quite unreliable because any user program
can break it.

Long ago (in 2.4 time frame) there used to be a IBM patch floating
around to reserve them globally and user space to use specific ones. I
guess something like that would be needed again.

-Andi


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

* Re: [patch 16/16] Add hardware breakpoint support for i386
  2005-08-29 16:12   ` [patch 16/16] Add hardware breakpoint support for i386 Tom Rini
  2005-08-29 21:23     ` Andi Kleen
@ 2005-08-30  1:06     ` Keith Owens
  1 sibling, 0 replies; 37+ messages in thread
From: Keith Owens @ 2005-08-30  1:06 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel

On Mon, 29 Aug 2005 09:12:08 -0700, 
Tom Rini <trini@kernel.crashing.org> wrote:
>
>This adds hardware breakpoint support for i386.  This is not as well tested as
>software breakpoints, but in some minimal testing appears to be functional.

Hardware breakpoints must be per cpu, not global.  Also you will fall
over applications that are using gdb, because gdb uses the same
registers.  KDB has never really supported kernel hardware breakpoints,
they are hard to do without stamping on user space.


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

* Re: [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault()
  2005-08-29 16:08 [patch 01/16] Add a KGDB core Tom Rini
       [not found] ` <1.2982005.trini@kernel.crashing.org>
@ 2005-08-30  7:33 ` George Anzinger
  2005-08-30 14:06   ` Tom Rini
  1 sibling, 1 reply; 37+ messages in thread
From: George Anzinger @ 2005-08-30  7:33 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, ak

Tom Rini wrote:
> CC: Andi Kleen <ak@suse.de>
> This adds a call to notify_die() in the "no context" portion of
> do_page_fault() as someone on the chain might care and want to do a fixup.
> 
> ---
> 
>  linux-2.6.13-trini/arch/x86_64/mm/fault.c |    4 ++++
>  1 files changed, 4 insertions(+)
> 
> diff -puN arch/x86_64/mm/fault.c~x86_64-no_context_hook arch/x86_64/mm/fault.c
> --- linux-2.6.13/arch/x86_64/mm/fault.c~x86_64-no_context_hook	2005-08-29 11:09:13.000000000 -0700
> +++ linux-2.6.13-trini/arch/x86_64/mm/fault.c	2005-08-29 11:09:13.000000000 -0700
> @@ -514,6 +514,10 @@ no_context:
>  	if (is_errata93(regs, address))
>  		return; 
>  
> +	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> +				SIGSEGV) == NOTIFY_STOP)
> +		return;
> +
>  /*
>   * Oops. The kernel tried to access some bad page. We'll have to
>   * terminate things with extreme prejudice.

Please use a more descriptive text than "no context".  This bit of info 
SHOULD be available to the gdb/kgdb user and should indicate why kgdb 
was entered.  It thus should be something like "bad kernel address" or 
"illegal kernel address".
> 
-- 
George Anzinger   george@mvista.com
HRT (High-res-timers):  http://sourceforge.net/projects/high-res-timers/

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

* Re: [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault()
  2005-08-30  7:33 ` [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault() George Anzinger
@ 2005-08-30 14:06   ` Tom Rini
  2005-08-30 14:50     ` George Anzinger
  0 siblings, 1 reply; 37+ messages in thread
From: Tom Rini @ 2005-08-30 14:06 UTC (permalink / raw)
  To: George Anzinger; +Cc: akpm, linux-kernel, ak

On Tue, Aug 30, 2005 at 12:33:25AM -0700, George Anzinger wrote:
> Tom Rini wrote:
> >CC: Andi Kleen <ak@suse.de>
> >This adds a call to notify_die() in the "no context" portion of
> >do_page_fault() as someone on the chain might care and want to do a fixup.
> >
> >---
> >
> > linux-2.6.13-trini/arch/x86_64/mm/fault.c |    4 ++++
> > 1 files changed, 4 insertions(+)
> >
> >diff -puN arch/x86_64/mm/fault.c~x86_64-no_context_hook 
> >arch/x86_64/mm/fault.c
> >--- linux-2.6.13/arch/x86_64/mm/fault.c~x86_64-no_context_hook 2005-08-29 
> >11:09:13.000000000 -0700
> >+++ linux-2.6.13-trini/arch/x86_64/mm/fault.c	2005-08-29 
> >11:09:13.000000000 -0700
> >@@ -514,6 +514,10 @@ no_context:
> > 	if (is_errata93(regs, address))
> > 		return; 
> > 
> >+	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
> >+				SIGSEGV) == NOTIFY_STOP)
> >+		return;
> >+
> > /*
> >  * Oops. The kernel tried to access some bad page. We'll have to
> >  * terminate things with extreme prejudice.
> 
> Please use a more descriptive text than "no context".  This bit of info 
> SHOULD be available to the gdb/kgdb user and should indicate why kgdb 
> was entered.  It thus should be something like "bad kernel address" or 
> "illegal kernel address".

"no context" is the label we're in, in the code.  What it's actually
used for is "hey, we (== kgdb) tried to read/write a very very bogus
addr, time to longjmp".  If it's not true that kgdb is at fault then we
drop to the debugger anyhow, and the user can see where they came from.

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault()
  2005-08-30 14:06   ` Tom Rini
@ 2005-08-30 14:50     ` George Anzinger
  2005-08-30 19:53       ` Tom Rini
  0 siblings, 1 reply; 37+ messages in thread
From: George Anzinger @ 2005-08-30 14:50 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, ak

Tom Rini wrote:
> On Tue, Aug 30, 2005 at 12:33:25AM -0700, George Anzinger wrote:
> 
>>Tom Rini wrote:
>>
>>>CC: Andi Kleen <ak@suse.de>
>>>This adds a call to notify_die() in the "no context" portion of
>>>do_page_fault() as someone on the chain might care and want to do a fixup.
>>>
>>>---
>>>
>>>linux-2.6.13-trini/arch/x86_64/mm/fault.c |    4 ++++
>>>1 files changed, 4 insertions(+)
>>>
>>>diff -puN arch/x86_64/mm/fault.c~x86_64-no_context_hook 
>>>arch/x86_64/mm/fault.c
>>>--- linux-2.6.13/arch/x86_64/mm/fault.c~x86_64-no_context_hook 2005-08-29 
>>>11:09:13.000000000 -0700
>>>+++ linux-2.6.13-trini/arch/x86_64/mm/fault.c	2005-08-29 
>>>11:09:13.000000000 -0700
>>>@@ -514,6 +514,10 @@ no_context:
>>>	if (is_errata93(regs, address))
>>>		return; 
>>>
>>>+	if (notify_die(DIE_PAGE_FAULT, "no context", regs, error_code, 14,
>>>+				SIGSEGV) == NOTIFY_STOP)
>>>+		return;
>>>+
>>>/*
>>> * Oops. The kernel tried to access some bad page. We'll have to
>>> * terminate things with extreme prejudice.
>>
>>Please use a more descriptive text than "no context".  This bit of info 
>>SHOULD be available to the gdb/kgdb user and should indicate why kgdb 
>>was entered.  It thus should be something like "bad kernel address" or 
>>"illegal kernel address".
> 
> 
> "no context" is the label we're in, in the code.  What it's actually
> used for is "hey, we (== kgdb) tried to read/write a very very bogus
> addr, time to longjmp".  If it's not true that kgdb is at fault then we
> drop to the debugger anyhow, and the user can see where they came from.
> 
No.  What the user sees is the offending code (i.e. prior to the trap to 
page_fault), NOT how kgdb happend to be called.  The "no_context" is IN 
the _context_ of page_fault, but that is lost by the time you get to 
kgdb and ask to see _why_ (via, hint, hint: "p kgdb_info").

-- 
George Anzinger   george@mvista.com
HRT (High-res-timers):  http://sourceforge.net/projects/high-res-timers/

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

* Re: [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault()
  2005-08-30 14:50     ` George Anzinger
@ 2005-08-30 19:53       ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-30 19:53 UTC (permalink / raw)
  To: George Anzinger; +Cc: akpm, linux-kernel

On Tue, Aug 30, 2005 at 07:50:31AM -0700, George Anzinger wrote:
> Tom Rini wrote:
[snip]
> >"no context" is the label we're in, in the code.  What it's actually
> >used for is "hey, we (== kgdb) tried to read/write a very very bogus
> >addr, time to longjmp".  If it's not true that kgdb is at fault then we
> >drop to the debugger anyhow, and the user can see where they came from.
> >
> No.  What the user sees is the offending code (i.e. prior to the trap to 
> page_fault), NOT how kgdb happend to be called.  The "no_context" is IN 
> the _context_ of page_fault, but that is lost by the time you get to 
> kgdb and ask to see _why_ (via, hint, hint: "p kgdb_info").

So you're suggesting changing what we pass in so that if we also modify
kgdb_info to contain the 'where' thing you talked about before, it would
be more useful, yes?  If so, I think that can wait just a bit. :)

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 16/16] Add hardware breakpoint support for i386
  2005-08-29 21:23     ` Andi Kleen
@ 2005-08-31 14:39       ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-31 14:39 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-kernel

On Mon, Aug 29, 2005 at 11:23:39PM +0200, Andi Kleen wrote:
> Tom Rini <trini@kernel.crashing.org> writes:
> 
> > This adds hardware breakpoint support for i386.  This is not as well tested as
> > software breakpoints, but in some minimal testing appears to be functional.
> 
> This really would need so coordination with user space using 
> them. Otherwise it'll be quite unreliable because any user program
> can break it.

Probably easiest to just drop this for now then, thanks.

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-29 16:09   ` [patch 04/16] I/O driver for 8250-compatible UARTs Tom Rini
  2005-08-29 16:18     ` Russell King
@ 2005-08-31 19:38     ` Bjorn Helgaas
  2005-08-31 20:10       ` Tom Rini
  1 sibling, 1 reply; 37+ messages in thread
From: Bjorn Helgaas @ 2005-08-31 19:38 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, rmk

On Monday 29 August 2005 10:09 am, Tom Rini wrote:
>  linux-2.6.13-trini/drivers/serial/kgdb_8250.c  |  594 +++++++++++++++++++++

The existing stuff in drivers/serial is named "8250_*"; is
there a reason you're using "kgdb_8250" rather than "8250_kgdb"?

> + *	serial8250_unregister_by_port - remove a 16x50 serial port
> + *	at runtime.
> + *	@port: A &struct uart_port that describes the port to remove.
> + *
> + *	Remove one serial port.  This may not be called from interrupt
> + *	context.  We hand the port back to the our control.

Hand the port back to whose control?

> +MODULE_PARM_DESC(kgdb8250, " kgdb8250=<port number>,<baud rate>\n");

Document IRQ/MMIO/IOport stuff here too (whatever it turns out to be,
see below).

It seems wrong to me to have kgdb8250 use "ttyS" names for devices.
In general you don't know the ttyS name for a device until after the
8250 driver claims it.  Sure, it's a convenience to use "ttyS0"
instead of "io,0x3f8", but it also makes it hard to run kgdb on a
PCI or MMIO UART, because you don't know what its name will be.

If you gave up the convenience and just always required an I/O port
or MMIO address, you could nuke all the old_rs_table[] and
kgdb8250_ports[] stuff, not to mention a bunch of config options.

> +static int kgdb8250_local_init(void)
> +{
> +	if (old_rs_table_copied == 0)
> +		kgdb8250_copy_rs_table();

This would be easier to maintain if the "if (old_rs_table_copied)"
test were in the callee, not in every caller.

> +	switch (CURRENTPORT.iotype) {
> +	case UPIO_MEM:
> +		if (CURRENTPORT.mapbase)
> +			kgdb8250_needs_request_mem_region = 1;
> +		if (CURRENTPORT.flags & UPF_IOREMAP) {
> +			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
> +						      8 << KGDB8250_REG_SHIFT);

Shouldn't this be ioremap instead of ioport_map?

> +static int kgdb_init_io(void)
> +{
> +#ifdef CONFIG_KGDB_8250_MODULE
> +	if (strlen(config)) {
> +		if (kgdb8250_opt(config))
> +			return -EINVAL;
> +	} else {
> +		printk(KERN_ERR "kgdb8250: argument error, usage: "
> +		       "kgdb8250=<port number>,<baud rate>");
> +#ifdef CONFIG_IA64
> +		printk(",<irq>,<iomem base>");
> +#endif

This isn't ia64-specific.

> +static void __init kgdb8250_hookup_irq(void)
> +{
> +#if defined(CONFIG_SERIAL_8250) || defined (CONFIG_SERIAL_8250_MODULE)
> +	/* Take the port away from the main driver. */
> +	serial8250_unregister_by_port(&CURRENTPORT);
> +
> +	/* Now reinit the port as the above has disabled things. */
> +	kgdb8250_init();
> +#endif
> +	/* We may need to call request_mem_region() first. */
> +	if (kgdb8250_needs_request_mem_region)
> +		request_mem_region(CURRENTPORT.mapbase,
> +				   8 << KGDB8250_REG_SHIFT, "kgdb");

The unregister/init/request_mem_region stuff doesn't sound very much
like "hookup_irq".

> + * Syntax for this cmdline option is "kgdb8250=ttyno,baudrate"
> + * with ",irq,iomembase" tacked on the end on IA64.

This syntax doesn't really make sense on ia64, because there are
no fixed "ttyno/iomembase" mappings.  It would be unambiguous to
specify either ttyno OR iomembase, but there's no good way to use
both.

And there should be syntax to specify either MMIO or I/O port space
devices.  Intel ia64 boxes typically have I/O port UARTs (0x3f8, etc),
and HP boxes typically have MMIO devices.

> +#ifdef CONFIG_IA64
> +	if (*str == ',') {
> +		str++;
> +		KGDB8250_IRQ = simple_strtoul(str, &str, 10);
> +		if (*str == ',') {
> +			str++;
> +			CURRENTPORT.iotype = SERIAL_IO_MEM;
> +			CURRENTPORT.membase =
> +			    (unsigned char *)simple_strtoul(str, &str, 0);
> +		}
> +	}
> +#endif

Not ia64-specific.

> +config KGDB_SIMPLE_SERIAL
> +	bool "Simple selection of KGDB serial port"
> +	depends on KGDB_8250
> +	default y
> +	help
> +	  If you say Y here, you will only have to pick the baud rate
> +	  and serial port (ttyS) that you wish to use for KGDB.  If you
> +	  say N, you will have provide the I/O port and IRQ number.  Note
> +	  that if your serial ports are iomapped, such as on ia64, then
> +	  you must say Y here.  If in doubt, say Y.

How about: "... you will have to provide the address (I/O port or MMIO
address) and IRQ ..."

I don't understand the "iomapped" bit -- does that mean MMIO?  And why
would it make any difference whether they're in I/O port or MMIO space?

I expect that if you use "ttyS" naming to select a port, that doesn't
work early in boot on ia64, because ia64 doesn't have compiled-in
knowledge of where ttyS devices live.  Is that related to what this is
trying to say?

> +config KGDB_PORT
> +	hex "hex I/O port address of the debug serial port"
> +	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
> +	default 3f8
> +	help
> +	  This is the unmapped (and on platforms with 1:1 mapping
> +	  this is typically, but not always the same as the mapped)
> +	  address of the serial port.  The stanards on your architecture
> +	  may be found in include/asm-$(ARCH)/serial.h.

Not ia64-specific.  The description sounds like it applies to MMIO,
not to I/O port space.    And s/stanards/standards/.

> +config KGDB_IRQ
> +	int "IRQ of the debug serial port"
> +	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
> +	default 4
> +	help
> +	  This is the IRQ for the debug port.  This must be known so that
> +	  KGDB can interrupt the running system (either for a new
> +	  connection or when in gdb and control-C is issued).

Not ia64-specific.

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-31 19:38     ` Bjorn Helgaas
@ 2005-08-31 20:10       ` Tom Rini
  2005-08-31 21:03         ` Russell King
  2005-08-31 21:19         ` Bjorn Helgaas
  0 siblings, 2 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-31 20:10 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: akpm, linux-kernel, rmk

On Wed, Aug 31, 2005 at 01:38:52PM -0600, Bjorn Helgaas wrote:
> On Monday 29 August 2005 10:09 am, Tom Rini wrote:
> >  linux-2.6.13-trini/drivers/serial/kgdb_8250.c  |  594 +++++++++++++++++++++
> 
> The existing stuff in drivers/serial is named "8250_*"; is
> there a reason you're using "kgdb_8250" rather than "8250_kgdb"?

All the other kgdb stuff tends to be prefixed, not suffixed.  But I
don't really care either way.

> > + *	serial8250_unregister_by_port - remove a 16x50 serial port
> > + *	at runtime.
> > + *	@port: A &struct uart_port that describes the port to remove.
> > + *
> > + *	Remove one serial port.  This may not be called from interrupt
> > + *	context.  We hand the port back to the our control.
> 
> Hand the port back to whose control?

Ok, that is non-sensical.  "We hand the port to the callers control." is
what I meant to say.

> > +MODULE_PARM_DESC(kgdb8250, " kgdb8250=<port number>,<baud rate>\n");
> 
> Document IRQ/MMIO/IOport stuff here too (whatever it turns out to be,
> see below).
> 
> It seems wrong to me to have kgdb8250 use "ttyS" names for devices.
> In general you don't know the ttyS name for a device until after the
> 8250 driver claims it.  Sure, it's a convenience to use "ttyS0"
> instead of "io,0x3f8", but it also makes it hard to run kgdb on a
> PCI or MMIO UART, because you don't know what its name will be.

I've tried intentionally to not mention 'ttyS' anywhere (exposed to the
user) because it's really not 'ttySN' but it is the port registered to
us.


> If you gave up the convenience and just always required an I/O port
> or MMIO address, you could nuke all the old_rs_table[] and
> kgdb8250_ports[] stuff, not to mention a bunch of config options.

But that's really rather handy so I'd rather not get rid of it.

There's really two cases we have to deal with.  The first case is a
known at compile time or can be registered at boot-time easily port (ie
dumb old PC or ARM boards).  The second case is "serial port over
there".  Perhaps we should change the kgdb8250 arg to be an override of
the default port, so:
kgdb8250={io,mmio},<irq>,<token>,<baud rate>

Would that work?

> > +static int kgdb8250_local_init(void)
> > +{
> > +	if (old_rs_table_copied == 0)
> > +		kgdb8250_copy_rs_table();
> 
> This would be easier to maintain if the "if (old_rs_table_copied)"
> test were in the callee, not in every caller.

I'm not sure.  In the compiled-in case we know it's always been run
prior to freeing __init data, and thus it's quasi-safe.  I suppose it
wouldn't be too big a deal to just remove the __init and do it like
that.

> > +	switch (CURRENTPORT.iotype) {
> > +	case UPIO_MEM:
> > +		if (CURRENTPORT.mapbase)
> > +			kgdb8250_needs_request_mem_region = 1;
> > +		if (CURRENTPORT.flags & UPF_IOREMAP) {
> > +			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
> > +						      8 << KGDB8250_REG_SHIFT);
> 
> Shouldn't this be ioremap instead of ioport_map?

If I remember right from the testing, no.  Or if my memory is wrong and
that's retorihcal, sure.

> > +static int kgdb_init_io(void)
> > +{
> > +#ifdef CONFIG_KGDB_8250_MODULE
> > +	if (strlen(config)) {
> > +		if (kgdb8250_opt(config))
> > +			return -EINVAL;
> > +	} else {
> > +		printk(KERN_ERR "kgdb8250: argument error, usage: "
> > +		       "kgdb8250=<port number>,<baud rate>");
> > +#ifdef CONFIG_IA64
> > +		printk(",<irq>,<iomem base>");
> > +#endif
> 
> This isn't ia64-specific.

It is and it isn't.  Since no one's tried a PCI card uart for KGDB nor
had a case where we have to pass in the mmio addr except on ia64, it is
ia64-specific.  But as I said above, if we make kgdb8250= an override of
the compiled in choice, it wouldn't be.

> > +static void __init kgdb8250_hookup_irq(void)
> > +{
> > +#if defined(CONFIG_SERIAL_8250) || defined (CONFIG_SERIAL_8250_MODULE)
> > +	/* Take the port away from the main driver. */
> > +	serial8250_unregister_by_port(&CURRENTPORT);
> > +
> > +	/* Now reinit the port as the above has disabled things. */
> > +	kgdb8250_init();
> > +#endif
> > +	/* We may need to call request_mem_region() first. */
> > +	if (kgdb8250_needs_request_mem_region)
> > +		request_mem_region(CURRENTPORT.mapbase,
> > +				   8 << KGDB8250_REG_SHIFT, "kgdb");
> 
> The unregister/init/request_mem_region stuff doesn't sound very much
> like "hookup_irq".

All the stuff that's required before you can really hookup the IRQ.
Suggested name appricated.

> > + * Syntax for this cmdline option is "kgdb8250=ttyno,baudrate"
> > + * with ",irq,iomembase" tacked on the end on IA64.
> 
> This syntax doesn't really make sense on ia64, because there are
> no fixed "ttyno/iomembase" mappings.  It would be unambiguous to
> specify either ttyno OR iomembase, but there's no good way to use
> both.

It's true that ttyno isn't really useful on ia64.

> > +config KGDB_SIMPLE_SERIAL
> > +	bool "Simple selection of KGDB serial port"
> > +	depends on KGDB_8250
> > +	default y
> > +	help
> > +	  If you say Y here, you will only have to pick the baud rate
> > +	  and serial port (ttyS) that you wish to use for KGDB.  If you
> > +	  say N, you will have provide the I/O port and IRQ number.  Note
> > +	  that if your serial ports are iomapped, such as on ia64, then
> > +	  you must say Y here.  If in doubt, say Y.
> 
> How about: "... you will have to provide the address (I/O port or MMIO
> address) and IRQ ..."

I'd really rather not force everyone to pass in the address token and
IRQ#.

> I don't understand the "iomapped" bit -- does that mean MMIO?  And why
> would it make any difference whether they're in I/O port or MMIO space?

It's the special "boot once, figure out your I/O address and IRQ, reboot
and pass it in" case of IA64.  I'm under the impression that it's
because of the more dynamic than other arches that we couldn't just
register the ports as we find them to KGDB and let the user pick from a
pre-registered port that we play that game.

> I expect that if you use "ttyS" naming to select a port, that doesn't
> work early in boot on ia64, because ia64 doesn't have compiled-in
> knowledge of where ttyS devices live.  Is that related to what this is
> trying to say?

Yes.

> > +config KGDB_PORT
> > +	hex "hex I/O port address of the debug serial port"
> > +	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
> > +	default 3f8
> > +	help
> > +	  This is the unmapped (and on platforms with 1:1 mapping
> > +	  this is typically, but not always the same as the mapped)
> > +	  address of the serial port.  The stanards on your architecture
> > +	  may be found in include/asm-$(ARCH)/serial.h.
> 
> Not ia64-specific.  The description sounds like it applies to MMIO,
> not to I/O port space.    And s/stanards/standards/.

Having !mmio uarts on ia64 is news to me (but I've never used an ia64
box), hence the depends line.

> > +config KGDB_IRQ
> > +	int "IRQ of the debug serial port"
> > +	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
> > +	default 4
> > +	help
> > +	  This is the IRQ for the debug port.  This must be known so that
> > +	  KGDB can interrupt the running system (either for a new
> > +	  connection or when in gdb and control-C is issued).
> 
> Not ia64-specific.

True, don't recall why I did that one like that now, thanks.

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-31 20:10       ` Tom Rini
@ 2005-08-31 21:03         ` Russell King
  2005-08-31 21:23           ` Tom Rini
  2005-08-31 21:19         ` Bjorn Helgaas
  1 sibling, 1 reply; 37+ messages in thread
From: Russell King @ 2005-08-31 21:03 UTC (permalink / raw)
  To: Tom Rini; +Cc: Bjorn Helgaas, akpm, linux-kernel

On Wed, Aug 31, 2005 at 01:10:39PM -0700, Tom Rini wrote:
> On Wed, Aug 31, 2005 at 01:38:52PM -0600, Bjorn Helgaas wrote:
> > On Monday 29 August 2005 10:09 am, Tom Rini wrote:
> > >  linux-2.6.13-trini/drivers/serial/kgdb_8250.c  |  594 +++++++++++++++++++++
> > 
> > The existing stuff in drivers/serial is named "8250_*"; is
> > there a reason you're using "kgdb_8250" rather than "8250_kgdb"?
> 
> All the other kgdb stuff tends to be prefixed, not suffixed.  But I
> don't really care either way.

I'd prefer it was 8250_kgdb.c actually - that keeps it along side the
other 8250 files.

> > > +	switch (CURRENTPORT.iotype) {
> > > +	case UPIO_MEM:
> > > +		if (CURRENTPORT.mapbase)
> > > +			kgdb8250_needs_request_mem_region = 1;
> > > +		if (CURRENTPORT.flags & UPF_IOREMAP) {
> > > +			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
> > > +						      8 << KGDB8250_REG_SHIFT);
> > 
> > Shouldn't this be ioremap instead of ioport_map?
> 
> If I remember right from the testing, no.  Or if my memory is wrong and
> that's retorihcal, sure.

ioport_map() is supposed to be used to map the IO range for the ioread/
iowrite operations.  IOW, it takes something compatible with inb() and
friends and converts it to something compatible with ioread8() and
friends.

It does not take a MMIO cookie, so the code above appears to be
conceptually wrong.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-31 20:10       ` Tom Rini
  2005-08-31 21:03         ` Russell King
@ 2005-08-31 21:19         ` Bjorn Helgaas
  2005-08-31 22:15           ` Tom Rini
  1 sibling, 1 reply; 37+ messages in thread
From: Bjorn Helgaas @ 2005-08-31 21:19 UTC (permalink / raw)
  To: Tom Rini; +Cc: akpm, linux-kernel, rmk

On Wednesday 31 August 2005 2:10 pm, Tom Rini wrote:
> On Wed, Aug 31, 2005 at 01:38:52PM -0600, Bjorn Helgaas wrote:
> > On Monday 29 August 2005 10:09 am, Tom Rini wrote:
> I've tried intentionally to not mention 'ttyS' anywhere (exposed to the
> user) because it's really not 'ttySN' but it is the port registered to
> us.

So kgdb's port N is different from ttySN?  That sounds really
confusing.  And KGDB_SIMPLE_SERIAL does mention "ttyS".

> There's really two cases we have to deal with.  The first case is a
> known at compile time or can be registered at boot-time easily port (ie
> dumb old PC or ARM boards).  The second case is "serial port over
> there".  Perhaps we should change the kgdb8250 arg to be an override of
> the default port, so:
> kgdb8250={io,mmio},<irq>,<token>,<baud rate>

That makes sense.  But I'd make it {io,mmio},<token>,<baud>,<irq>
so it's more like the existing "console=uart" argument.

> > > +	switch (CURRENTPORT.iotype) {
> > > +	case UPIO_MEM:
> > > +		if (CURRENTPORT.mapbase)
> > > +			kgdb8250_needs_request_mem_region = 1;
> > > +		if (CURRENTPORT.flags & UPF_IOREMAP) {
> > > +			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
> > > +						      8 << KGDB8250_REG_SHIFT);
> > 
> > Shouldn't this be ioremap instead of ioport_map?
> 
> If I remember right from the testing, no.  Or if my memory is wrong and
> that's retorihcal, sure.

ioport_map() certainly isn't going to do anything good with an MMIO
address.

> > > +		printk(KERN_ERR "kgdb8250: argument error, usage: "
> > > +		       "kgdb8250=<port number>,<baud rate>");
> > > +#ifdef CONFIG_IA64
> > > +		printk(",<irq>,<iomem base>");
> > > +#endif
> > 
> > This isn't ia64-specific.
> 
> It is and it isn't.  Since no one's tried a PCI card uart for KGDB nor
> had a case where we have to pass in the mmio addr except on ia64, it is
> ia64-specific.

Maybe it's only been *tested* on ia64, but I don't think that's a
reason to make it compiled only on ia64.

> > > + * Syntax for this cmdline option is "kgdb8250=ttyno,baudrate"
> > > + * with ",irq,iomembase" tacked on the end on IA64.
> > 
> > This syntax doesn't really make sense on ia64, because there are
> > no fixed "ttyno/iomembase" mappings.  It would be unambiguous to
> > specify either ttyno OR iomembase, but there's no good way to use
> > both.
> 
> It's true that ttyno isn't really useful on ia64.

Then I think it would be a mistake to have syntax that requires both
ttyno and iomembase in the same command-line option.  I'm visualizing
something like this:

	kgdb8250=ttyS0,115200
	kgdb8250=io,0x3f8,115200,49
	kgdb8250=mmio,0xff5e0000,115200,49

where you can easily decide which type of device specification
you've got.

> > > +config KGDB_SIMPLE_SERIAL
> > > +	bool "Simple selection of KGDB serial port"
> > > +	depends on KGDB_8250
> > > +	default y
> > > +	help
> > > +	  If you say Y here, you will only have to pick the baud rate
> > > +	  and serial port (ttyS) that you wish to use for KGDB.  If you
> > > +	  say N, you will have provide the I/O port and IRQ number.  Note
> > > +	  that if your serial ports are iomapped, such as on ia64, then
> > > +	  you must say Y here.  If in doubt, say Y.
> > 
> > How about: "... you will have to provide the address (I/O port or MMIO
> > address) and IRQ ..."
> 
> I'd really rather not force everyone to pass in the address token and
> IRQ#.

My point was merely that you should support explicit MMIO addresses
as well as explicit I/O ports.  I guess it makes sense to accept
ttyS names as well, and accept the limitation that before the 8250
driver initializes, ttyS names only work for devices defined at
compile-time in SERIAL_PORT_DFNS.

> > I don't understand the "iomapped" bit -- does that mean MMIO?  And why
> > would it make any difference whether they're in I/O port or MMIO space?
> 
> It's the special "boot once, figure out your I/O address and IRQ, reboot
> and pass it in" case of IA64.  I'm under the impression that it's
> because of the more dynamic than other arches that we couldn't just
> register the ports as we find them to KGDB and let the user pick from a
> pre-registered port that we play that game.

Yup, ia64 doesn't require serial ports at fixed addresses.  They're all
discovered via ACPI and PCI enumeration.

But "iomapped" doesn't suggest that to me.  And I would expect the
text to say that if you don't have any compiled-in UART names, you'd
have to say "N".  But it says use "Y" for ia64.

Actually, I think KGDB_SIMPLE_SERIAL, KGDB_*BAUD, KGDB_PORT_*,
KGDB_PORT, and KGDB_IRQ are overkill.  Could they all be nuked
in favor of a KGDB_8250_DEVICE that could be set to things like
"ttyS0,115200" or "io,0x3f8,115200,49"?

> > > +config KGDB_PORT
> > > +	hex "hex I/O port address of the debug serial port"
> > > +	depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64
> > > +	default 3f8
> > > +	help
> > > +	  This is the unmapped (and on platforms with 1:1 mapping
> > > +	  this is typically, but not always the same as the mapped)
> > > +	  address of the serial port.  The stanards on your architecture
> > > +	  may be found in include/asm-$(ARCH)/serial.h.
> > 
> > Not ia64-specific.  The description sounds like it applies to MMIO,
> > not to I/O port space.    And s/stanards/standards/.
> 
> Having !mmio uarts on ia64 is news to me (but I've never used an ia64
> box), hence the depends line.

Intel-based boxes have only I/O port UARTs.  But regardless, the
MMIO-ness or I/O port-ness of a UART is completely arch-independent.

The description point is that "unmapped" and "1:1 mapping" sound like
things related to MMIO addresses, not to I/O port addresses.

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-31 21:03         ` Russell King
@ 2005-08-31 21:23           ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-31 21:23 UTC (permalink / raw)
  To: Bjorn Helgaas, akpm, linux-kernel

On Wed, Aug 31, 2005 at 10:03:34PM +0100, Russell King wrote:
> On Wed, Aug 31, 2005 at 01:10:39PM -0700, Tom Rini wrote:
> > On Wed, Aug 31, 2005 at 01:38:52PM -0600, Bjorn Helgaas wrote:
> > > On Monday 29 August 2005 10:09 am, Tom Rini wrote:
> > > >  linux-2.6.13-trini/drivers/serial/kgdb_8250.c  |  594 +++++++++++++++++++++
> > > 
> > > The existing stuff in drivers/serial is named "8250_*"; is
> > > there a reason you're using "kgdb_8250" rather than "8250_kgdb"?
> > 
> > All the other kgdb stuff tends to be prefixed, not suffixed.  But I
> > don't really care either way.
> 
> I'd prefer it was 8250_kgdb.c actually - that keeps it along side the
> other 8250 files.

Will do.

> > > > +	switch (CURRENTPORT.iotype) {
> > > > +	case UPIO_MEM:
> > > > +		if (CURRENTPORT.mapbase)
> > > > +			kgdb8250_needs_request_mem_region = 1;
> > > > +		if (CURRENTPORT.flags & UPF_IOREMAP) {
> > > > +			CURRENTPORT.membase = ioport_map(CURRENTPORT.mapbase,
> > > > +						      8 << KGDB8250_REG_SHIFT);
> > > 
> > > Shouldn't this be ioremap instead of ioport_map?
> > 
> > If I remember right from the testing, no.  Or if my memory is wrong and
> > that's retorihcal, sure.
> 
> ioport_map() is supposed to be used to map the IO range for the ioread/
> iowrite operations.  IOW, it takes something compatible with inb() and
> friends and converts it to something compatible with ioread8() and
> friends.
> 
> It does not take a MMIO cookie, so the code above appears to be
> conceptually wrong.
> 

So it's luck (or another mapping I didn't see elsewhere) that this
worked, and it should still be ioremap(...) to use with ioread/write8
later on in the code?

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [patch 04/16] I/O driver for 8250-compatible UARTs
  2005-08-31 21:19         ` Bjorn Helgaas
@ 2005-08-31 22:15           ` Tom Rini
  0 siblings, 0 replies; 37+ messages in thread
From: Tom Rini @ 2005-08-31 22:15 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: akpm, linux-kernel, rmk

On Wed, Aug 31, 2005 at 03:19:37PM -0600, Bjorn Helgaas wrote:
> On Wednesday 31 August 2005 2:10 pm, Tom Rini wrote:
> > On Wed, Aug 31, 2005 at 01:38:52PM -0600, Bjorn Helgaas wrote:
> > > On Monday 29 August 2005 10:09 am, Tom Rini wrote:
> > I've tried intentionally to not mention 'ttyS' anywhere (exposed to the
> > user) because it's really not 'ttySN' but it is the port registered to
> > us.
> 
> So kgdb's port N is different from ttySN?  That sounds really
> confusing.  And KGDB_SIMPLE_SERIAL does mention "ttyS".

It's not intentionally different, and really only might be different in
the we have ttySX case, but ttySX isn't registered to KGDB case.

> > There's really two cases we have to deal with.  The first case is a
> > known at compile time or can be registered at boot-time easily port (ie
> > dumb old PC or ARM boards).  The second case is "serial port over
> > there".  Perhaps we should change the kgdb8250 arg to be an override of
> > the default port, so:
> > kgdb8250={io,mmio},<irq>,<token>,<baud rate>
> 
> That makes sense.  But I'd make it {io,mmio},<token>,<baud>,<irq>
> so it's more like the existing "console=uart" argument.

ok.

> > > > +		printk(KERN_ERR "kgdb8250: argument error, usage: "
> > > > +		       "kgdb8250=<port number>,<baud rate>");
> > > > +#ifdef CONFIG_IA64
> > > > +		printk(",<irq>,<iomem base>");
> > > > +#endif
> > > 
> > > This isn't ia64-specific.
> > 
> > It is and it isn't.  Since no one's tried a PCI card uart for KGDB nor
> > had a case where we have to pass in the mmio addr except on ia64, it is
> > ia64-specific.
> 
> Maybe it's only been *tested* on ia64, but I don't think that's a
> reason to make it compiled only on ia64.

It's only been needed on ia64.  But it's moot since I've reworked things
for kgdb8250= is always a complete override.

> Actually, I think KGDB_SIMPLE_SERIAL, KGDB_*BAUD, KGDB_PORT_*,
> KGDB_PORT, and KGDB_IRQ are overkill.  Could they all be nuked
> in favor of a KGDB_8250_DEVICE that could be set to things like
> "ttyS0,115200" or "io,0x3f8,115200,49"?

Hmm.  I'll give that a shot momentarily... That sounds like a good idea
'tho..

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

end of thread, other threads:[~2005-08-31 22:15 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-08-29 16:08 [patch 01/16] Add a KGDB core Tom Rini
     [not found] ` <1.2982005.trini@kernel.crashing.org>
2005-08-29 16:09   ` [patch 02/16] Add support for i386 platforms to KGDB Tom Rini
2005-08-29 19:55     ` [patch 2/3] x86_64: Run setup_per_cpu_areas and trap_init sooner Andi Kleen
2005-08-29 20:03       ` Tom Rini
2005-08-29 16:09   ` [patch 03/16] Add support for PowerPC32 platforms to KGDB Tom Rini
2005-08-29 16:09   ` [patch 04/16] I/O driver for 8250-compatible UARTs Tom Rini
2005-08-29 16:18     ` Russell King
2005-08-29 16:28       ` Tom Rini
2005-08-31 19:38     ` Bjorn Helgaas
2005-08-31 20:10       ` Tom Rini
2005-08-31 21:03         ` Russell King
2005-08-31 21:23           ` Tom Rini
2005-08-31 21:19         ` Bjorn Helgaas
2005-08-31 22:15           ` Tom Rini
2005-08-29 16:09   ` [patch 05/16] Add support for MIPS platforms to KGDB Tom Rini
2005-08-29 16:10   ` [patch 06/16] Add support for IA64 " Tom Rini
2005-08-29 16:10   ` [patch 07/16] x86_64: Rename KDB_VECTOR to DEBUGGER_VECTOR Tom Rini
2005-08-29 16:10   ` [patch 08/16] Add support for X86_64 platforms to KGDB Tom Rini
2005-08-29 17:13     ` Andi Kleen
2005-08-29 17:45       ` Tom Rini
2005-08-29 18:46         ` Andi Kleen
2005-08-29 18:49           ` Tom Rini
2005-08-29 16:10   ` [patch 09/16] Add support for SuperH " Tom Rini
2005-08-29 16:10   ` [patch 10/16] Add support for ARM " Tom Rini
2005-08-29 16:11   ` [patch 11/16] Add support for PowerPC64 " Tom Rini
2005-08-29 16:11   ` [patch 12/16] KGDBoE I/O driver Tom Rini
2005-08-29 16:11   ` [patch 13/16] Add CFI DWARF2 annotation support Tom Rini
2005-08-29 16:11   ` [patch 14/16] Minor SysRq keyboard bugfix for KGDB Tom Rini
2005-08-29 16:11   ` [patch 15/16] Allow KGDB to work well with loaded modules Tom Rini
2005-08-29 16:12   ` [patch 16/16] Add hardware breakpoint support for i386 Tom Rini
2005-08-29 21:23     ` Andi Kleen
2005-08-31 14:39       ` Tom Rini
2005-08-30  1:06     ` Keith Owens
2005-08-30  7:33 ` [patch 1/3] x86_64: Add a notify_die() call to the "no context" part of do_page_fault() George Anzinger
2005-08-30 14:06   ` Tom Rini
2005-08-30 14:50     ` George Anzinger
2005-08-30 19:53       ` Tom Rini

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