diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/Documentation/Configure.help linux-2.4.22-pa12/Documentation/Configure.help
--- linux-2.4.22-pa12.orig/Documentation/Configure.help	2003-10-03 05:01:34.000000000 +0200
+++ linux-2.4.22-pa12/Documentation/Configure.help	2003-10-04 15:56:58.000000000 +0200
@@ -21160,6 +21160,40 @@
   If you have a Western Digital WD93 SCSI controller on
   an SGI MIPS system, say Y.  Otherwise, say N.
 
+KGDB: Remote (serial) kernel debugging with gdb
+CONFIG_PARISC_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the parisc
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 32 MB.
+  To use this feature you need to perform some basic setup described
+  briefly in Documentation/parisc/kgdb-serial.txt.
+  Currently only PA32 platforms are supported.
+  This is only useful for kernel hackers. If unsure, say N.
+
+KGDB: Thread analysis
+CONFIG_KGDB_THREAD
+  With thread analysis enabled, gdb can talk to kgdb stub to list
+  threads and to get stack trace for a thread. This option also enables
+  some code which helps gdb get exact status of thread. Thread analysis
+  adds some overhead to schedule and down functions. You can disable this
+  option if you do not want to compromise on speed.
+
+KGDB: Console messages through gdb
+CONFIG_GDB_CONSOLE
+  If you say Y here, console messages will appear through gdb.
+  Other consoles such as tty or ttyS will continue to work as usual.
+  NEVER use this option if you plan to debug gdb remote serial protocol
+  
+KGDB: Enable kernel asserts
+CONFIG_KERNEL_ASSERTS
+  This option enables kernel asserts. A kernel assert is a condition,
+  which if turnes out to be false during an execution path, then kgdb
+  is called. Kernel assertions help in modifying the kernel or writing
+  drivers. Bugs can be traced sooner with kernel asserts because invalid
+  conditions caused by bugs are checked at various places. Kernel asserts
+  add the overhead of checking asserted conditions. You can disable this
+  option if you do not want the overhead.
+
 Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
   If you say Y here, you will have some control over the system even
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/Documentation/parisc/gdbrc linux-2.4.22-pa12/Documentation/parisc/gdbrc
--- linux-2.4.22-pa12.orig/Documentation/parisc/gdbrc	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/Documentation/parisc/gdbrc	2003-10-04 15:56:58.000000000 +0200
@@ -0,0 +1,9 @@
+set remotelogfile kgdb.log
+set remotebaud 38400
+set debug remote 1
+set debug serial 1
+set debug arch 1
+set prompt (kgdb)\ 
+set remote Z-packet 0
+target remote /dev/ttyS0
+
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/Documentation/parisc/kgdb-serial.txt linux-2.4.22-pa12/Documentation/parisc/kgdb-serial.txt
--- linux-2.4.22-pa12.orig/Documentation/parisc/kgdb-serial.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/Documentation/parisc/kgdb-serial.txt	2003-10-04 15:56:58.000000000 +0200
@@ -0,0 +1,296 @@
+About the PA/RISC stub of kgdb
+==============================
+The PA/RISC stub of kgdb was written by Laurent Canet <canetl@esiee.fr>
+and Thibaut Varene <varenet@esiee.fr>.
+Currently it only works on 32 bits machines, or in 32 bits kernel mode
+(there is no 64bits gdb available). 
+Most of the original KGDB features are available, excepted hardware
+assisted debugging and single stepping, which are not (yet) supported
+or available.
+
+
+Version
+=======
+
+This version of the gdbstub package was developed and tested on
+kernel version 2.4.20.  It will not install on a 2.2 kernel.  It may
+not work on earlier versions of 2.3 kernels.  
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need a modem
+eliminator and the appropriate cables.
+
+On the DEVELOPMENT machine you need to apply the patch for the gdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and
+do "make menuconfig".  Go down to the kernel hacking menu item and
+open it up.  Enable the kernel gdb stub code by selecting that item.
+
+Save and exit the menuconfig program.  Then do "make clean" and
+"make bzImage" (or whatever target you want to make).  This gets
+the kernel compiled with the "-g" option set -- necessary for
+debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on our TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.
+I usually arrange to copy development:/usr/src/linux/arch/i386/boot/zImage
+to /vmlinuz on the TARGET machine via a LAN based NFS access.  That is,
+I run the cp command on the target and copy from the development machine
+via the LAN.  Run Lilo on the new kernel on the target machine so that it
+will boot!  Then boot the kernel on the target machine.
+
+There is an utility program named "gdbstart" in the
+development:/usr/src/linux/arch/i386/kernel directory.
+You should copy this program over to your target machine, probably into
+/sbin.  This utility program is run on the target machine to
+activate the kernel hooks for the debugger.  It is invoked as follows:
+
+    gdbstart [-s speed] [-t tty-dev]
+    defaults:  /dev/ttyS0 with speed unmodified by gdbstart
+
+Don't run the program just yet.  We'll get to that in a bit.
+
+Decide on which tty port you want the machines to communicate, then
+cable them up back-to-back using the null modem.  COM1 is /dev/ttyS0
+and COM2 is /dev/ttyS1.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+define rmt
+set remotebaud 38400
+target remote /dev/ttyS0
+end
+
+Assuming that you added my gdbinit stuff to your .gdbinit, edit .gdbinit
+and find the section that looks like this:
+
+	define rmt
+	set remotebaud 38400
+	target remote /dev/ttyS0
+	end
+
+Change the "target" definition so that it specifies the tty port that
+you intend to use.  Change the "remotebaud" definition to match the
+data rate that you are going to use for the com line.
+
+On the TARGET machine I find it helpful to create shell script file
+named "debug" in the root home directory with the following contents:
+
+	gdbstart -s 38400 -t /dev/ttyS0 <<EOF
+	<blank line>
+	EOF
+
+This runs the gdbstart program and gives it the carriage return that
+it prompts for.  This sets the data rate from the target machine's side.
+
+You are now ready to try it out.
+
+On your TARGET machine, freshly rebooted with your gdbstub-equipped
+kernel, type "debug" in the root home directory.  The system will appear
+to hang with some messages on the screen from the debug stub.  What
+it is doing is waiting for contact from the development machine.
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded and prompts you, enter "rmt" (that's
+the macro from the .gdbinit file that you just edited).  If everything
+is working correctly you should see gdb print out a few lines indicating
+that a breakpoint has been taken.  It will actually show a line of
+code in the target kernel inside the gdbstub activation code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux), 
+    Copyright 1995 Free Software Foundation, Inc...
+    (gdb) rmt
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb) 
+
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+
+Triggering gdbstub at Kernel Boot Time
+======================================
+
+The gdbstub patch now has the ability for gdb to connect to the kernel during
+bootup (as opposed to waiting for the system to come all the way up and then
+running the gdbstart program on the target machine).  This new functionality was
+added by Scott Foehner <sfoehner@engr.sgi.com> at SGI.
+
+To force a kernel that has been compiled with gdbstub to pause during the boot
+process and wait for a connection from gdb, the paramter "gdb" should be passed
+to the kernel. This can be done by typing "gdb" after the name of the kernel
+on the IPL command line.  The patch defaults to use ttyS0 at a baud rate of
+38400. These parameters can be changed by using "gdbttyS=<port number>" and
+"gdbbaud=<baud rate>" on the command line.
+
+Example:
+
+IPL boot command line: linux gdb gdbttyS=1 gdbbaud=38400
+
+Note that this command is entered on the TARGET machine as it is booting
+the kernel that was compiled on the DEVELOPMENT machine.
+
+If you use network booting, be sure to change palo.conf.
+
+
+The "gdbstart" Program
+=====================
+
+This utility program is used to set up the com port and data rate
+for the connection from the target system to the development system.
+Its usage has been described above.
+
+This version of the patch uses the same tty ioctl for kernel versions
+2.0.30 onwards.  Thus, the gdbstart utility does not need to be re-compiled
+to install the patch in a later version of the kernel.  The ioctl added
+to the kernel for this purpose is far enough "off the end" of existing
+ioctls (as of 2.1.120) that it should not interfere with any new kernel
+tty ioctls for quite some time (famous last words).
+
+The source for the gdbstart program resides in the arch/parisc/kernel directory.
+
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C.  If the target machine has interrupts enabled
+this will stop it in the kernel and enter the debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.
+
+When you are done debugging the kernel on the target machine it is
+a good idea to leave it in a running state.  This makes reboots
+faster, bypassing the fsck.  So do a gdb "continue" as the last gdb
+command if this is possible.  To terminate gdb itself on the development
+machine and leave the target machine running, type ^Z to suspend gdb
+and then kill it with "kill %1" or something similar.
+More cleanly, you can use the "detach" command
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy things
+first like double checking your cabling and data rates.  You might
+try some non-kernel based programs to see if the back-to-back connection
+works properly.  Just something simple like cat /etc/hosts >/dev/ttyS0
+on one machine and cat /dev/ttyS0 on the other will tell you if you
+can send data from one machine to the other.  There is no point in tearing
+out your hair in the kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/parisc/kernel/gdbstub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/linux/drivers/char/gdbserial.c
+That is the code that talks to the serial port on the target side.
+There might be a problem there.
+
+If you are really desperate you can use printk debugging in the
+gdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/gdbstub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.
+
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread related
+commands (info threads, thread n) can be used. 
+
+MP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb client,
+all the processors are forced to enter the debugger. Current thread
+corresponds to the thread running on the processor where breakpoint occured.
+Threads running on other processor(s) appear similar to other non running
+threads in the 'info threads' output.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and restarting
+another)
+If the target machine was not inside debugger when you killed gdb, gdb cannot
+connect because the target machine won't respond.
+In this case echo "Ctrl+C"(ascii 3) in the serial line.
+e.g. echo -e "\003" > /dev/ttyS1 
+This forces that target machine into debugger after which you can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+Final Items
+===========
+
+I picked up this code from Dave Grothe and enhanced it.
+
+If you make some really cool modification to this stuff, or if you 
+fix a bug, please let me know.
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
+
+(modified by Laurent Canet <canetl@esiee.fr>)
+    Modified i386 doc to reflect PA-RISC modifications
+
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/Makefile linux-2.4.22-pa12/Makefile
--- linux-2.4.22-pa12.orig/Makefile	2003-10-03 05:01:32.000000000 +0200
+++ linux-2.4.22-pa12/Makefile	2003-10-04 15:56:58.000000000 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION = -pa12
+EXTRAVERSION = -pa12-kgdb
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -112,6 +112,9 @@
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
 	  -fno-strict-aliasing -fno-common
+ifeq ($(CONFIG_PARISC_REMOTE_DEBUG),y)
+CFLAGS += -g
+endif
 ifndef CONFIG_FRAME_POINTER
 CFLAGS += -fomit-frame-pointer
 endif
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/config.in linux-2.4.22-pa12/arch/parisc/config.in
--- linux-2.4.22-pa12.orig/arch/parisc/config.in	2003-10-03 05:01:48.000000000 +0200
+++ linux-2.4.22-pa12/arch/parisc/config.in	2003-10-04 15:56:58.000000000 +0200
@@ -38,6 +38,7 @@
    dep_bool '32-bit PDC' CONFIG_PDC_NARROW $CONFIG_PARISC64
 else
    define_bool CONFIG_PA11 y
+   define_bool CONFIG_PARISC64 n
 fi
 endmenu
 
@@ -205,6 +206,15 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Debug spinlocks' CONFIG_DEBUG_SPINLOCK
 bool 'Compile kernel with frame pointers' CONFIG_FRAME_POINTER
+if [ "$CONFIG_PARISC64" = "n" -a "$CONFIG_GSC" = "y" -a "$CONFIG_SUPERIO" = "n" ]; then
+    bool 'KGDB: Remote (serial) kernel debugging with gdb' CONFIG_PARISC_REMOTE_DEBUG
+    if [ "$CONFIG_PARISC_REMOTE_DEBUG" != "n" ]; then
+        bool ' KGDB: Console messages through gdb' CONFIG_GDB_CONSOLE
+		bool ' KGDB: Thread analysis' CONFIG_KGDB_THREAD
+		bool ' KGDB: Enable kernel asserts' CONFIG_KERNEL_ASSERTS
+		bool ' KGDB: Add a /proc/bugme for SEGV handling presentation' CONFIG_PROC_BUGME
+    fi
+fi
 endmenu
 
 source crypto/Config.in
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/kernel/Makefile linux-2.4.22-pa12/arch/parisc/kernel/Makefile
--- linux-2.4.22-pa12.orig/arch/parisc/kernel/Makefile	2002-10-03 17:33:29.000000000 +0200
+++ linux-2.4.22-pa12/arch/parisc/kernel/Makefile	2003-10-04 15:56:58.000000000 +0200
@@ -7,10 +7,20 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+ifeq ($(CONFIG_PARISC_REMOTE_DEBUG),y)
+#GDBSTART=gdbstart
+# KGDB XXX: gdbstart is not yet on plans
+GDBSTART=
+GDBCLEAN= -rm -f gdbstart /sbin/gdbstart
+else
+GDBSTART=
+GDBCLEAN=
+endif
+
 ifdef CONFIG_PARISC64
 all: kernel.o init_task.o pdc_cons.o process.o head64.o unaligned.o perf.o perf_asm.o
 else
-all: kernel.o init_task.o pdc_cons.o process.o head.o unaligned.o
+all: kernel.o init_task.o pdc_cons.o process.o head.o unaligned.o $(GDBSTART)
 endif
 
 O_TARGET = kernel.o
@@ -47,5 +57,6 @@
 		ioctl32.o signal32.o
 # only supported for PCX-W/U in 64-bit mode at the moment
 obj-$(CONFIG_PARISC64) += perf.o perf_asm.o
+obj-$(CONFIG_PARISC_REMOTE_DEBUG) += gdbstub.o
 
 include $(TOPDIR)/Rules.make
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/kernel/entry.S linux-2.4.22-pa12/arch/parisc/kernel/entry.S
--- linux-2.4.22-pa12.orig/arch/parisc/kernel/entry.S	2003-09-25 05:01:45.000000000 +0200
+++ linux-2.4.22-pa12/arch/parisc/kernel/entry.S	2003-10-04 15:56:58.000000000 +0200
@@ -766,7 +766,7 @@
 	b	do_softirq
 	ldo	R%intr_check_resched(%r2), %r2
 
-	.import schedule,code
+	.import user_schedule,code
 intr_do_resched:
 	/* Only do reschedule if we are returning to user space */
 	LDREG   PT_IASQ0(%r16), %r20
@@ -781,7 +781,7 @@
 #endif
 
 	ldil	L%intr_check_sig, %r2
-	b	schedule
+	b	user_schedule
 	ldo	R%intr_check_sig(%r2), %r2
 
 
@@ -2401,9 +2401,9 @@
 	b       syscall_check_resched
 	ssm     PSW_SM_I, %r0  /* do_softirq returns with I bit off */
 
-	.import schedule,code
+	.import user_schedule,code
 syscall_do_resched:
-	bl	schedule,%r2
+	bl	user_schedule,%r2
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
 #else
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/kernel/gdbstart.c linux-2.4.22-pa12/arch/parisc/kernel/gdbstart.c
--- linux-2.4.22-pa12.orig/arch/parisc/kernel/gdbstart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/arch/parisc/kernel/gdbstart.c	2003-10-04 15:56:59.000000000 +0200
@@ -0,0 +1,148 @@
+/*
+ * This program opens a tty file and issues the GDB stub activating
+ * ioctl on it.
+ *
+ * KGDB XXX: testing needed, add a build command in the makefile
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <asm/ioctls.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+char		*tty_name = "/dev/ttyS0" ;	/* COM1 port */
+int		 speed = 9600 ;			/* default speed */
+struct termios	 save_ts ;			/* original term struct */
+
+void print_usage(void)
+{
+    printf("gdbstub [-s speed] [-t tty-dev]\n") ;
+    printf("  defaults:  /dev/ttyS0 with speed unmodified by this program\n");
+
+} /* print_usage */
+
+void tty_err(char *msg)
+{
+    char	buf[100] ;
+
+    strcpy(buf, msg) ;
+    strcat(buf, ": ") ;
+    strcat(buf, tty_name) ;
+    perror(buf) ;
+    exit(1) ;
+
+} /* tty_err */
+
+
+void setup_term(int fd)
+{
+    struct termios	ts ;
+    int			speed_code ;
+
+    if (tcgetattr(fd, &ts) < 0) tty_err("tcgetattr") ;
+
+    save_ts = ts ;
+    switch (speed)
+    {
+    case 4800:
+	speed_code = B4800 ;
+	break ;
+    case 9600:
+	speed_code = B9600 ;
+	break ;
+    case 19200:
+	speed_code = B19200 ;
+	break ;
+    case 38400:
+	speed_code = B38400 ;
+	break ;
+    case 57600:
+	speed_code = B57600 ;
+	break ;
+    case 115200:
+	speed_code = B115200 ;
+	break ;
+    case 230400:
+	speed_code = B230400 ;
+	break ;
+    default:
+	printf("Invalid speed: %d\n", speed) ;
+	exit(1) ;
+    }
+
+    ts.c_cflag = CS8 | CREAD | CLOCAL ;
+    if (cfsetospeed(&ts, speed_code) < 0) tty_err("cfsetospeed") ;
+    if (cfsetispeed(&ts, speed_code) < 0) tty_err("cfsetispeed") ;
+
+    if (tcsetattr(fd, TCSANOW, &ts) < 0) tty_err("tcsetattr") ;
+
+} /* setup_term */
+
+void main(int argc, char **argv)
+{
+    int		opt ;
+    int		fil ;
+    int		rslt ;
+
+    while ((opt = getopt(argc, argv, "hs:t:")) > 0)
+    {
+	switch (opt)
+	{
+	case 's':
+	    speed = atol(optarg) ;
+	    break ;
+	case 't':
+	    tty_name = optarg ;
+	    break ;
+	case ':':
+	    printf("Invalid option\n") ;
+	    break ;
+	case '?':
+	case 'h':
+	default:
+	    print_usage() ;
+	    return ;
+	}
+    }
+
+    fil = open(tty_name, O_RDWR) ;
+    if (fil < 0)
+    {
+	perror(tty_name) ;
+	return ;
+    }
+
+
+    setup_term(fil) ;
+
+    /*
+     * When we issue this ioctl, control will not return until
+     * the debugger running on the remote host machine says "go".
+     */
+    printf("\nAbout to activate GDB stub in the kernel on %s\n", tty_name) ;
+    printf("Hit CR to continue, kill program to abort -- ") ;
+    getchar() ;
+    sync() ;
+    rslt = ioctl(fil, TIOCGDB, 0) ;
+    if (rslt < 0)
+    {
+	perror("TIOCGDB ioctl") ;
+	return ;
+    }
+
+    printf("\nGDB stub successfully activated\n") ;
+
+    for (;;)
+    {
+	pause() ;
+    }
+
+    if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
+
+} /* main */
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/kernel/gdbstub.c linux-2.4.22-pa12/arch/parisc/kernel/gdbstub.c
--- linux-2.4.22-pa12.orig/arch/parisc/kernel/gdbstub.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/arch/parisc/kernel/gdbstub.c	2003-10-04 15:56:59.000000000 +0200
@@ -0,0 +1,1237 @@
+/*
+ * KGDB stubs for hppa.
+ *
+ * Copyright (c) 2003 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2003 Thibaut Varene <varenet@esiee.fr>
+ *
+ * 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.
+ *
+ * KGDB XXX:
+ * - hardware breakpoints (at least see if we can have the debug sfu
+ *   working)
+ * - test SMP locks
+ * - see if we can use single stepping
+ * - a 64 bit KGDB ! :)
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ */
+/*
+ *  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.
+ *
+ *************
+ * command          function                               Return value
+ *
+ *    The following gdb commands are supported:
+ *
+ *    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
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ * 	  O				Used by GDB console (reports printk
+ * 	  				to the remote gdb)	
+ *
+ *	  The following gdb commands are not yet supported because we don't have
+ *	  threads supports:
+ *	  
+ *    k             kill 								 
+ * 	  Hct			switch to thread t					   OK or eNN
+ * 	  qL			list threads
+ *	 
+ *	  The following gdb commands are NOT supported due to lack of hardware
+ *	  support or because it won't work
+ *
+ *	  z/Z			set/remove hardware {break,watch}points
+ *	  F				call system call
+ *	  
+ * 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/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/gdb.h>
+
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+
+
+/* asm macros */
+#define MEMB(no)	{ int __mi = no; while (--__mi) __asm__ volatile (""::: "memory"); }
+
+#define BREAKPOINT()	asm("break 5,8");
+
+/*
+ * 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		4096
+
+/* Number of bytes of registers.  */
+#define NUMREGS		128
+#define NUMREGBYTES	NUMREGS*4
+/* masks for 64 bit registers */
+#define MASK_32LOW	0x00000000ffffffff
+#define MASK_32HIGH	0xffffffff00000000
+
+#undef KGDB_HPPA_HAVE_HWBREAKPOINT
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+static const char hexchars[] = "0123456789abcdef";
+
+/*
+ * 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.
+ *
+ * FIXME: This image is from gdb521, check for gdb5.3
+ */
+enum gdb_regpacket {
+	flags,  r1,      rp,      r3,    r4,     r5,      r6,     r7,    
+	r8,     r9,      r10,     r11,   r12,    r13,     r14,    r15,   
+	r16,    r17,     r18,     r19,   r20,    r21,     r22,    r23,   
+	r24,    r25,     r26,     dp,    ret0,   ret1,    sp,     r31,  
+	sar,    pcoqh,   pcsqh,   pcoqt, pcsqt,  eiem,    iir,    isr,   
+	ior,    ipsw,    gotoreg, sr4,   sr0,    sr1,     sr2,    sr3,   
+	sr5,    sr6,     sr7,     cr0,   cr8,    cr9,     ccr,    cr12,  
+	cr13,   cr24,    cr25,    cr26,  mpsfu_high,mpsfu_low,mpsfu_ovflo,pad,
+	fpsr,    fpe1,   fpe2,    fpe3,  fpe4,   fpe5,    fpe6,   fpe7,  
+	fr4,     fr4R,   fr5,     fr5R,  fr6,    fr6R,    fr7,    fr7R,  
+	fr8,     fr8R,   fr9,     fr9R,  fr10,   fr10R,   fr11,   fr11R, 
+	fr12,    fr12R,  fr13,    fr13R, fr14,   fr14R,   fr15,   fr15R, 
+	fr16,    fr16R,  fr17,    fr17R, fr18,   fr18R,   fr19,   fr19R, 
+	fr20,    fr20R,  fr21,    fr21R, fr22,   fr22R,   fr23,   fr23R, 
+	fr24,    fr24R,  fr25,    fr25R, fr26,   fr26R,   fr27,   fr27R, 
+	fr28,    fr28R,  fr29,    fr29R, fr30,   fr30R,   fr31,   fr31R
+};
+
+
+/* *****************
+ * Global variables
+ * *****************/
+/* Put the error code here just in case the user cares.  */
+
+int gdb_arg_enter = 0;		/* do not enter by default */
+int gdb_arg_baud = 38400;
+int gdb_arg_ttyS = 0;
+int gdb_arg_gdbcons = 0;	/* do not use the gdbconsole */
+
+#ifdef CONFIG_SMP
+#error kgdb does not yet support SMP systems
+#endif
+
+#if KGDB_MAX_NO_CPUS != 8
+#error change the initialisation of slavecpulocks
+#endif
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS] = { SPIN_LOCK_UNLOCKED,
+	SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	SPIN_LOCK_UNLOCKED };
+volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+volatile unsigned kgdb_lock = 0;
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+static char initialized = 0;	/* boolean flag. != 0 means we've been initialized */
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an error. */
+static volatile int kgdb_memerr = 0;
+volatile int kgdb_memerr_expected = 0;
+static volatile int kgdb_memerr_cnt = 0;
+
+/* We don't have hardware breakpoints on the currently supported hw.
+ * FIXME: find a better way to initialize them eventually.
+ */
+#ifdef KGDB_HPPA_HAVE_HWBREAKPOINT
+static struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+}
+breakinfo[8] = {
+{enabled:0},{enabled:0},{enabled:0},{enabled:0},{enabled:0},{enabled:0},{enabled:0},{enabled:0}
+};
+#endif
+
+
+/* Those two are in driver/char/gdbserial.c */
+extern int putDebugChar (int);	/* write a single character      */
+extern int getDebugChar (void);	/* read and return a single char */
+
+
+/* Returns the integer equivalent of a hexadecimal character. */
+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);
+}
+
+/* Awaits the sequence $<data>#<checksum> and stores <data> in the array buffer returned */
+static void getpacket (char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	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;
+		}
+		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.  */
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+static void putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+	do {
+		putDebugChar ('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count])) {
+			if (!putDebugChar (ch))
+				return;
+			checksum += ch;
+			count += 1;
+		}
+
+		putDebugChar ('#');
+		putDebugChar (hexchars[checksum >> 4]);
+		putDebugChar (hexchars[checksum % 16]);
+
+	} while ((getDebugChar () & 0x7f) != '+');
+}
+
+
+static void regs_to_gdb_regs (int *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[flags] = regs->gr[0];
+	gdb_regs[r1] = regs->gr[1];
+	gdb_regs[rp] = regs->gr[2];
+	gdb_regs[r3] = regs->gr[3];
+	gdb_regs[r4] = regs->gr[4];
+	gdb_regs[r5] = regs->gr[5];
+	gdb_regs[r6] = regs->gr[6];
+	gdb_regs[r7] = regs->gr[7];
+	gdb_regs[r8] = regs->gr[8];
+	gdb_regs[r9] = regs->gr[9];
+	gdb_regs[r10] = regs->gr[10];
+	gdb_regs[r11] = regs->gr[11];
+	gdb_regs[r12] = regs->gr[12];
+	gdb_regs[r13] = regs->gr[13];
+	gdb_regs[r14] = regs->gr[14];
+	gdb_regs[r15] = regs->gr[15];
+	gdb_regs[r16] = regs->gr[16];
+	gdb_regs[r17] = regs->gr[17];
+	gdb_regs[r18] = regs->gr[18];
+	gdb_regs[r19] = regs->gr[19];
+	gdb_regs[r20] = regs->gr[20];
+	gdb_regs[r21] = regs->gr[21];
+	gdb_regs[r22] = regs->gr[22];
+	gdb_regs[r23] = regs->gr[23];
+	gdb_regs[r24] = regs->gr[24];
+	gdb_regs[r25] = regs->gr[25];
+	gdb_regs[r26] = regs->gr[26];
+	gdb_regs[dp] = regs->gr[27];
+	gdb_regs[ret0] = regs->gr[28];
+	gdb_regs[ret1] = regs->gr[29];
+	gdb_regs[sp] = regs->gr[30];
+	gdb_regs[r31] = regs->gr[31];
+	gdb_regs[sar] = regs->sar;
+	gdb_regs[pcoqh] = regs->iaoq[0];
+	gdb_regs[pcsqh] = regs->iasq[0];
+	gdb_regs[pcoqt] = regs->iaoq[1];
+	gdb_regs[pcsqh] = regs->iasq[1];
+	gdb_regs[eiem] = 0;		/* eiem is cr15, not in pt_regs */
+	gdb_regs[iir] = regs->iir;
+	gdb_regs[isr] = regs->isr;
+	gdb_regs[ior] = regs->ior;
+	gdb_regs[ipsw] = regs->ipsw;
+	gdb_regs[gotoreg] = 0;		/* wtf is goto register in gdb ? */
+	gdb_regs[sr4] = regs->sr[4];
+	gdb_regs[sr0] = regs->sr[0];
+	gdb_regs[sr1] = regs->sr[1];
+	gdb_regs[sr2] = regs->sr[2];
+	gdb_regs[sr3] = regs->sr[3];
+	gdb_regs[sr5] = regs->sr[5];
+	gdb_regs[sr6] = regs->sr[6];
+	gdb_regs[sr7] = regs->sr[7];
+	gdb_regs[cr0] = 0;		/* not available in pt_regs */
+	gdb_regs[cr8] = 0;		/* not available in pt_regs */
+	gdb_regs[cr9] = 0;		/* not available in pt_regs */
+	gdb_regs[ccr] = 0;		/* not available in pt_regs */
+	gdb_regs[cr12] = 0;		/* not available in pt_regs */
+	gdb_regs[cr13] = 0;		/* not available in pt_regs */
+	gdb_regs[cr24] = 0;		/* not available in pt_regs */
+	gdb_regs[cr26] = 0;		/* not available in pt_regs */
+	gdb_regs[mpsfu_high] = 0;	/* not available in pt_regs */
+	gdb_regs[mpsfu_low] = 0;	/* not available in pt_regs */
+	gdb_regs[mpsfu_ovflo] = 0;	/* not available in pt_regs */
+	gdb_regs[pad] = regs->pad0;
+	gdb_regs[fpsr] = (__u32) (regs->fr[0] & MASK_32LOW);
+	gdb_regs[fpe1] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe2] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe3] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe4] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe5] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe6] = 0;		/* not used according to PA1.1doc */
+	gdb_regs[fpe7] = 0;		/* not used according to PA1.1doc */
+
+	/* floating point registers are in 64bit format */
+	gdb_regs[fr4] = (__u32) (regs->fr[4] & MASK_32LOW);
+	gdb_regs[fr4R] = (__u32) (regs->fr[4] & MASK_32HIGH);
+	gdb_regs[fr5] = (__u32) (regs->fr[5] & MASK_32LOW);
+	gdb_regs[fr5R] = (__u32) (regs->fr[5] & MASK_32HIGH);
+	gdb_regs[fr6] = (__u32) (regs->fr[6] & MASK_32LOW);
+	gdb_regs[fr6R] = (__u32) (regs->fr[6] & MASK_32HIGH);
+	gdb_regs[fr7] = (__u32) (regs->fr[7] & MASK_32LOW);
+	gdb_regs[fr7R] = (__u32) (regs->fr[7] & MASK_32HIGH);
+	gdb_regs[fr8] = (__u32) (regs->fr[8] & MASK_32LOW);
+	gdb_regs[fr8R] = (__u32) (regs->fr[8] & MASK_32HIGH);
+	gdb_regs[fr9] = (__u32) (regs->fr[9] & MASK_32LOW);
+	gdb_regs[fr9R] = (__u32) (regs->fr[9] & MASK_32HIGH);
+	gdb_regs[fr10] = (__u32) (regs->fr[10] & MASK_32LOW);
+	gdb_regs[fr10R] = (__u32) (regs->fr[10] & MASK_32HIGH);
+	gdb_regs[fr11] = (__u32) (regs->fr[11] & MASK_32LOW);
+	gdb_regs[fr11R] = (__u32) (regs->fr[11] & MASK_32HIGH);
+	gdb_regs[fr12] = (__u32) (regs->fr[12] & MASK_32LOW);
+	gdb_regs[fr12R] = (__u32) (regs->fr[12] & MASK_32HIGH);
+	gdb_regs[fr13] = (__u32) (regs->fr[13] & MASK_32LOW);
+	gdb_regs[fr13R] = (__u32) (regs->fr[13] & MASK_32HIGH);
+	gdb_regs[fr14] = (__u32) (regs->fr[14] & MASK_32LOW);
+	gdb_regs[fr14R] = (__u32) (regs->fr[14] & MASK_32HIGH);
+	gdb_regs[fr15] = (__u32) (regs->fr[15] & MASK_32LOW);
+	gdb_regs[fr15R] = (__u32) (regs->fr[15] & MASK_32HIGH);
+	gdb_regs[fr16] = (__u32) (regs->fr[16] & MASK_32LOW);
+	gdb_regs[fr16R] = (__u32) (regs->fr[16] & MASK_32HIGH);
+	gdb_regs[fr17] = (__u32) (regs->fr[17] & MASK_32LOW);
+	gdb_regs[fr17R] = (__u32) (regs->fr[17] & MASK_32HIGH);
+	gdb_regs[fr18] = (__u32) (regs->fr[18] & MASK_32LOW);
+	gdb_regs[fr18R] = (__u32) (regs->fr[18] & MASK_32HIGH);
+	gdb_regs[fr19] = (__u32) (regs->fr[19] & MASK_32LOW);
+	gdb_regs[fr19R] = (__u32) (regs->fr[19] & MASK_32HIGH);
+	gdb_regs[fr20] = (__u32) (regs->fr[20] & MASK_32LOW);
+	gdb_regs[fr20R] = (__u32) (regs->fr[20] & MASK_32HIGH);
+	gdb_regs[fr21] = (__u32) (regs->fr[21] & MASK_32LOW);
+	gdb_regs[fr21R] = (__u32) (regs->fr[21] & MASK_32HIGH);
+	gdb_regs[fr22] = (__u32) (regs->fr[22] & MASK_32LOW);
+	gdb_regs[fr22R] = (__u32) (regs->fr[22] & MASK_32HIGH);
+	gdb_regs[fr23] = (__u32) (regs->fr[23] & MASK_32LOW);
+	gdb_regs[fr23R] = (__u32) (regs->fr[23] & MASK_32HIGH);
+	gdb_regs[fr24] = (__u32) (regs->fr[24] & MASK_32LOW);
+	gdb_regs[fr24R] = (__u32) (regs->fr[24] & MASK_32HIGH);
+	gdb_regs[fr25] = (__u32) (regs->fr[25] & MASK_32LOW);
+	gdb_regs[fr25R] = (__u32) (regs->fr[25] & MASK_32HIGH);
+	gdb_regs[fr26] = (__u32) (regs->fr[26] & MASK_32LOW);
+	gdb_regs[fr26R] = (__u32) (regs->fr[26] & MASK_32HIGH);
+	gdb_regs[fr27] = (__u32) (regs->fr[27] & MASK_32LOW);
+	gdb_regs[fr27R] = (__u32) (regs->fr[27] & MASK_32HIGH);
+	gdb_regs[fr28] = (__u32) (regs->fr[28] & MASK_32LOW);
+	gdb_regs[fr28R] = (__u32) (regs->fr[28] & MASK_32HIGH);
+	gdb_regs[fr29] = (__u32) (regs->fr[29] & MASK_32LOW);
+	gdb_regs[fr29R] = (__u32) (regs->fr[29] & MASK_32HIGH);
+	gdb_regs[fr30] = (__u32) (regs->fr[30] & MASK_32LOW);
+	gdb_regs[fr30R] = (__u32) (regs->fr[30] & MASK_32HIGH);
+	gdb_regs[fr31] = (__u32) (regs->fr[31] & MASK_32LOW);
+	gdb_regs[fr31R] = (__u32) (regs->fr[31] & MASK_32HIGH);
+} /* regs_to_gdb_regs */
+
+static void gdb_regs_to_regs (int *gdb_regs, struct pt_regs *regs)
+{
+	regs->gr[0] = gdb_regs[flags];
+	regs->gr[1] = gdb_regs[r1];
+	regs->gr[2] = gdb_regs[rp];
+	regs->gr[3] = gdb_regs[r3];
+	regs->gr[4] = gdb_regs[r4];
+	regs->gr[5] = gdb_regs[r5];
+	regs->gr[6] = gdb_regs[r6];
+	regs->gr[7] = gdb_regs[r7];
+	regs->gr[8] = gdb_regs[r8];
+	regs->gr[9] = gdb_regs[r9];
+	regs->gr[10] = gdb_regs[r10];
+	regs->gr[11] = gdb_regs[r11];
+	regs->gr[12] = gdb_regs[r12];
+	regs->gr[13] = gdb_regs[r13];
+	regs->gr[14] = gdb_regs[r14];
+	regs->gr[15] = gdb_regs[r15];
+	regs->gr[16] = gdb_regs[r16];
+	regs->gr[17] = gdb_regs[r17];
+	regs->gr[18] = gdb_regs[r18];
+	regs->gr[19] = gdb_regs[r19];
+	regs->gr[20] = gdb_regs[r20];
+	regs->gr[21] = gdb_regs[r21];
+	regs->gr[22] = gdb_regs[r22];
+	regs->gr[23] = gdb_regs[r23];
+	regs->gr[24] = gdb_regs[r24];
+	regs->gr[25] = gdb_regs[r25];
+	regs->gr[26] = gdb_regs[r26];
+	regs->gr[27] = gdb_regs[dp];
+	regs->gr[28] = gdb_regs[ret0];
+	regs->gr[29] = gdb_regs[ret1];
+	regs->gr[30] = gdb_regs[sp];
+	regs->gr[31] = gdb_regs[r31];
+	regs->sar = gdb_regs[sar];
+	regs->iaoq[0] = gdb_regs[pcoqh];
+	regs->iasq[0] = gdb_regs[pcsqh];
+	regs->iaoq[1] = gdb_regs[pcoqt];
+	regs->iasq[1] = gdb_regs[pcsqt];
+	regs->iir = gdb_regs[iir];
+	regs->isr = gdb_regs[isr];
+	regs->ior = gdb_regs[ior];
+	regs->ipsw = gdb_regs[ipsw];
+	regs->sr[4] = gdb_regs[sr4];
+	regs->sr[0] = gdb_regs[sr0];
+	regs->sr[1] = gdb_regs[sr1];
+	regs->sr[2] = gdb_regs[sr2];
+	regs->sr[3] = gdb_regs[sr3];
+	regs->sr[5] = gdb_regs[sr5];
+	regs->sr[6] = gdb_regs[sr6];
+	regs->sr[7] = gdb_regs[sr7];
+	regs->pad0 = gdb_regs[pad];
+	regs->fr[0] |= gdb_regs[fpsr];
+
+	/* floating point registers are in 64bit format */
+	regs->fr[4] = (__u64) gdb_regs[fr4];
+	regs->fr[4] |= ((__u64) gdb_regs[fr4R]) << 32;
+	regs->fr[5] = (__u64) gdb_regs[fr5];
+	regs->fr[5] |= ((__u64) gdb_regs[fr5R]) << 32;
+	regs->fr[6] = (__u64) gdb_regs[fr6];
+	regs->fr[6] |= ((__u64) gdb_regs[fr6R]) << 32;
+	regs->fr[7] = (__u64) gdb_regs[fr7];
+	regs->fr[7] |= ((__u64) gdb_regs[fr7R]) << 32;
+	regs->fr[8] = (__u64) gdb_regs[fr8];
+	regs->fr[8] |= ((__u64) gdb_regs[fr8R]) << 32;
+	regs->fr[9] = (__u64) gdb_regs[fr9];
+	regs->fr[9] |= ((__u64) gdb_regs[fr9R]) << 32;
+	regs->fr[10] = (__u64) gdb_regs[fr10];
+	regs->fr[10] |= ((__u64) gdb_regs[fr10R]) << 32;
+	regs->fr[11] = (__u64) gdb_regs[fr11];
+	regs->fr[11] |= ((__u64) gdb_regs[fr11R]) << 32;
+	regs->fr[12] = (__u64) gdb_regs[fr12];
+	regs->fr[12] |= ((__u64) gdb_regs[fr12R]) << 32;
+	regs->fr[13] = (__u64) gdb_regs[fr13];
+	regs->fr[13] |= ((__u64) gdb_regs[fr13R]) << 32;
+	regs->fr[14] = (__u64) gdb_regs[fr14];
+	regs->fr[14] |= ((__u64) gdb_regs[fr14R]) << 32;
+	regs->fr[15] = (__u64) gdb_regs[fr15];
+	regs->fr[15] |= ((__u64) gdb_regs[fr15R]) << 32;
+	regs->fr[16] = (__u64) gdb_regs[fr16];
+	regs->fr[16] |= ((__u64) gdb_regs[fr16R]) << 32;
+	regs->fr[17] = (__u64) gdb_regs[fr17];
+	regs->fr[17] |= ((__u64) gdb_regs[fr17R]) << 32;
+	regs->fr[18] = (__u64) gdb_regs[fr18];
+	regs->fr[18] |= ((__u64) gdb_regs[fr18R]) << 32;
+	regs->fr[19] = (__u64) gdb_regs[fr19];
+	regs->fr[19] |= ((__u64) gdb_regs[fr19R]) << 32;
+	regs->fr[20] = (__u64) gdb_regs[fr20];
+	regs->fr[20] |= ((__u64) gdb_regs[fr20R]) << 32;
+	regs->fr[21] = (__u64) gdb_regs[fr21];
+	regs->fr[21] |= ((__u64) gdb_regs[fr21R]) << 32;
+	regs->fr[22] = (__u64) gdb_regs[fr22];
+	regs->fr[22] |= ((__u64) gdb_regs[fr22R]) << 32;
+	regs->fr[23] = (__u64) gdb_regs[fr23];
+	regs->fr[23] |= ((__u64) gdb_regs[fr23R]) << 32;
+	regs->fr[24] = (__u64) gdb_regs[fr24];
+	regs->fr[24] |= ((__u64) gdb_regs[fr24R]) << 32;
+	regs->fr[25] = (__u64) gdb_regs[fr25];
+	regs->fr[25] |= ((__u64) gdb_regs[fr25R]) << 32;
+	regs->fr[26] = (__u64) gdb_regs[fr26];
+	regs->fr[26] |= ((__u64) gdb_regs[fr26R]) << 32;
+	regs->fr[27] = (__u64) gdb_regs[fr27];
+	regs->fr[27] |= ((__u64) gdb_regs[fr27R]) << 32;
+	regs->fr[28] = (__u64) gdb_regs[fr28];
+	regs->fr[28] |= ((__u64) gdb_regs[fr28R]) << 32;
+	regs->fr[29] = (__u64) gdb_regs[fr29];
+	regs->fr[29] |= ((__u64) gdb_regs[fr29R]) << 32;
+	regs->fr[30] = (__u64) gdb_regs[fr30];
+	regs->fr[30] |= ((__u64) gdb_regs[fr30R]) << 32;
+	regs->fr[31] = (__u64) gdb_regs[fr31];
+	regs->fr[31] |= ((__u64) gdb_regs[fr31R]) << 32;
+} /* gdb_regs_to_regs */
+
+
+static int get_char (char *addr)
+{
+	return *addr;
+}
+
+static void set_char (char *addr, int val)
+{
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf
+ * return a pointer to the last char put in buf (null)
+ * If MAY_FAULT is non-zero, then we should set kgdb_memerr in response to
+ * a fault; if zero treat a fault like any other fault in the stub.
+ */
+static char * mem2hex (char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		kgdb_memerr_expected = 1;
+		kgdb_memerr = 0;
+	}
+
+	/* don't enter in mem trapping if we know it's bad */
+	if (mem == NULL) {
+		*buf = 0;
+		return buf;
+	}
+
+	for (i = 0; i < count; i++) {
+		ch = get_char (mem++);
+
+		if (may_fault && kgdb_memerr) {
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+
+	*buf = 0;
+	if (may_fault)
+		kgdb_memerr_expected = 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, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		kgdb_memerr_expected = 1;
+		kgdb_memerr = 0;
+	}
+
+	for (i = 0; i < count; i++) {
+		ch = hex (*buf++) << 4;
+		ch = ch + hex (*buf++);
+		set_char (mem++, ch);
+		if (may_fault && kgdb_memerr)
+			return (mem);
+	}
+	if (may_fault)
+		kgdb_memerr_expected = 0;
+
+	return mem;
+}
+
+/* build an int from hex chars */
+static int hexToInt (char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		}
+		else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#if defined(CONFIG_KGDB_THREAD) || defined(CONFIG_GDB_CONSOLE)
+static char * pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+#endif
+
+#ifdef CONFIG_KGDB_THREAD
+/* needed to get a valid code adress */
+static void kgdb_usercode(void)
+{
+}
+
+static int stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = hex (*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+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;
+}
+
+static char * unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int (buf, 2);
+	return buf + 2;
+}
+
+static char * unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+	while (inbuf < limit) {
+		x = hex(*inbuf++);
+		y = hex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+
+static void int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	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);
+}
+
+static int threadref_to_int(threadref *ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+	
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+
+
+struct task_struct * getthread(int pid)
+{
+	struct task_struct *thread;
+	thread = find_task_by_pid(pid);
+	if (thread)
+		return thread;
+	
+	thread = init_tasks[0];
+	do {
+		if (thread->pid == pid) {
+			return thread;
+		}
+		thread = thread->next_task;
+	} while (thread != init_tasks[0]);
+		
+	kgdb_dprintk(KERN_ERR "Didn't found thread id %d\n", pid);
+	
+	return NULL;
+}
+#endif /* CONFIG_KGDB_THREAD */
+
+/* these functions will be only useful with hardware breakpoints
+ */
+#ifdef KGDB_HPPA_HAVE_HWBREAKPOINT
+static void correct_hw_break (void)
+{
+	/* should be long asm code */
+	kgdb_dprintk(KERN_ERR "Correct HW break\n");
+}
+
+static int remove_hw_break (unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled)
+		return -1;
+	
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+static 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;
+
+	kgdb_dprintk(KERN_INFO "Set hw break %u: %u %u %u\n", breakno, type,
+		      len, addr);
+	return 0;
+}
+#endif /* KGDB_HAVE_HWBREAKPOINT */
+
+static void printexceptioninfo (int exceptionNo, int errorcode, char *buffer)
+{
+	switch (exceptionNo) {
+		case KGDB_TRAP_BKPT:	/* gdb break insn (break 4,8) */
+			sprintf(buffer, "GDB Breakpoint");
+			break;
+		case KGDB_TRAP_DIE:		/* die_if_kernel(); */
+			sprintf(buffer, "die_if_kernel() err=%d", errorcode);
+			break;
+		case KGDB_TRAP_BREAK:		/* breakpoint (break 5,8) */
+			sprintf(buffer, "forced break or kernel assertion failed");
+			break;
+		case KGDB_TRAP_PAGEFAULT:	/* TLB page errors in kernel space */
+			sprintf(buffer, "page fault");
+			break;
+		default:
+			sprintf(buffer, "break/trap unknown");
+			break;
+	}
+
+	return;
+}
+
+/* This function does all command procesing for interfacing to gdb. */
+static void handle_exception (int exception, int signo, int err_code,
+		  struct pt_regs *linux_regs)
+{
+	struct task_struct	*usethread = NULL;
+	int			addr, length;
+	char			*ptr;
+	unsigned long		flags;
+	int			gdb_regs[NUMREGBYTES / 4];
+	int			i;
+#ifdef CONFIG_KGDB_THREAD
+	struct pt_regs		*tempregs;
+	int			nothreads;
+	int			maxthreads;
+	int			threadid;
+	threadref		thref;
+	struct task_struct	*thread = NULL;
+#endif
+	unsigned		procid;
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if (user_mode(linux_regs))
+		return;
+
+	kgdb_dprintk(KERN_ERR "Entering kgdb because of excep=%d signo=%d err=%d\n",
+		      exception, signo, err_code);
+
+	if (kgdb_memerr_expected) {
+		kgdb_dprintk(KERN_ERR "kgdb: memerr!\n");
+		/*
+		 * This fault occured because of the get_char or set_char
+		 * routines.  These two routines use either eax of edx to
+		 * indirectly reference the location in memory that they
+		 * are working with.  For a page fault, when we return
+		 * the instruction will be retried, so we have to make
+		 * sure that these registers point to valid memory.
+		 */
+		kgdb_memerr = 1;	/* set mem error flag */
+		kgdb_memerr_expected = 0;
+		kgdb_memerr_cnt++;	/* helps in debugging */
+		return;
+	}
+	/* Hold kgdb_lock */
+	procid = smp_processor_id();
+	while (cmpxchg (&kgdb_lock, 0, (procid + 1)) != 0)
+		MEMB(50);	
+
+	local_irq_save(flags);
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* KGDB TODO */
+
+	for (i = 0; i < smp_num_cpus; i++)
+		spin_lock(&slavecpulocks[i]);
+
+	/* spin_lock code is good enough as a barrier so we don't
+	 * need one here */
+	procindebug[smp_processor_id()] = 1;
+
+	/* Master processor is completely in the debugger */
+
+	/* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+	
+	printk("...(%s)...", remcomOutBuffer);
+	putpacket (remcomOutBuffer);
+
+	while (1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'g' : /* return the value of the CPU registers */
+			if (!usethread || usethread == current)
+				regs_to_gdb_regs(gdb_regs, linux_regs);
+#ifdef CONFIG_KGDB_THREAD 
+			else {
+				memset(gdb_regs, 0, NUMREGBYTES);
+				if (usethread->thread.gotregs) {
+					printk(KERN_ERR "Gotregs!\n");
+					kgdb_memerr = 0;
+					kgdb_memerr_expected = 1;
+					get_char((char *) &usethread->thread.regs);
+					kgdb_memerr_expected = 0;
+					if (kgdb_memerr) {
+						*(((char *)&tempregs) + i) = '\0';
+						gdb_regs[pcoqt] = (unsigned long) &kgdb_usercode;
+						gdb_regs[pcoqh] = gdb_regs[pcoqt] + 4;
+					} else {
+						regs_to_gdb_regs(gdb_regs, &usethread->thread.regs);
+					}
+				} else {
+					gdb_regs[pcoqt] = (unsigned long) &kgdb_usercode;
+					gdb_regs[pcoqh] = gdb_regs[pcoqt] + 4;
+				}
+			}
+#endif /* CONFIG_KGDB_THREAD */
+			mem2hex ((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem (&remcomInBuffer[1], (char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs (gdb_regs, linux_regs);
+				strcpy (remcomOutBuffer, "OK");
+			}
+			else 
+				strcpy (remcomOutBuffer, "E00");
+			break;
+
+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+
+			if (hexToInt(&ptr, &addr) 
+					&& (*(ptr++) == ',') 
+					&& hexToInt(&ptr, &length)) {
+				kgdb_dprintk (KERN_ERR "transferring mem add=%lx - %lx\n",
+					      (unsigned long) addr, (unsigned long) addr + length);
+				ptr = 0;
+				mem2hex ((char *) addr,	remcomOutBuffer, length, 1);
+				if (kgdb_memerr)
+					strcpy (remcomOutBuffer, "E03");
+			}
+
+			if (ptr)
+				strcpy (remcomOutBuffer, "E01");
+			break;
+
+			/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) && (*(ptr++) == ',') && hexToInt(&ptr, &length)
+				&& (*(ptr++) == ':')) {
+				kgdb_dprintk (KERN_ERR "Writing to memory %lx - %lx\n",
+					      (unsigned long) ptr, (unsigned long) ptr + length);
+				hex2mem (ptr, (char *) addr, length, 1);
+
+				if (kgdb_memerr)
+					strcpy (remcomOutBuffer, "E03");
+				else
+					strcpy (remcomOutBuffer, "OK");
+				
+				ptr = 0;
+			}
+			if (ptr)
+				strcpy (remcomOutBuffer, "E02");
+			break;
+		
+			/* cAA..AA    Continue at address AA..AA(optional) */
+			/* sAA..AA   Step one instruction from AA..AA(optional) */
+			/* D             Detach from debugger */
+		case 'c':
+		case 's':
+		case 'D':
+			/* try to read optional parameter, pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt (&ptr, &addr))
+				linux_regs->iaoq[0] = addr;
+		
+			/* goodbye' */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer,"+");
+				putpacket(remcomOutBuffer);
+			}
+
+			procindebug[smp_processor_id()] = 0;
+
+			/* Wait till all the processors have quit
+			 * from the debugger */
+			for (i = 0; i < smp_num_cpus; i++)
+				while (procindebug[i])
+					MEMB(10);
+			
+			/* Release kgdb_lock */
+			while (cmpxchg (&kgdb_lock, 1, 0) != 1)
+				MEMB(50);
+			
+			
+			local_irq_restore (flags);
+			return;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* General querys */
+		case 'q':
+			switch (remcomInBuffer[1]) {
+#ifdef CONFIG_KGDB_THREAD
+			case 'L':	
+				/* List threads */
+				unpack_byte(remcomInBuffer+3, &maxthreads);
+				unpack_threadid(remcomInBuffer+5, &thref);
+
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer+5, &thref);	
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0; nothreads < maxthreads && threadid< PID_MAX; threadid++ ) {
+					read_lock(&tasklist_lock);
+					thread = getthread(threadid);
+					read_unlock(&tasklist_lock);
+					if (thread) {
+						int_to_threadref(&thref, threadid);
+						pack_threadid(remcomOutBuffer+21+nothreads*16, &thref);
+						nothreads++;
+					}
+				}
+				if (threadid == PID_MAX)
+					remcomOutBuffer[4] = '1';
+				pack_hex_byte(remcomOutBuffer+2, nothreads);
+				remcomOutBuffer[21+nothreads*16] = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer+2, &thref);	
+				remcomOutBuffer[18] = '\0';
+				break;
+#endif /* CONFIG_KGDB_THREAD */
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo (exception, err_code, remcomOutBuffer);
+				break;
+			case 'R':
+				/* commands */
+				if (strncmp(&remcomInBuffer[2], "cmd,7265626f6f74", 17) == 0) {
+					printk(KERN_ERR "Remote debugger asked reboot!\n");
+					
+					/* reply before rebooting */
+					strcpy (remcomOutBuffer, "OK");
+					putpacket (remcomOutBuffer);
+					
+					machine_restart(NULL);
+				}
+				break;
+
+			}
+			break;
+
+#ifdef CONFIG_KGDB_THREAD
+		/* task related */
+		case 'H' :	 
+			switch (remcomInBuffer[1]) {
+				case 'g':
+					ptr = &remcomInBuffer[2];
+					hexToInt(&ptr, &threadid);
+					thread = getthread(threadid);
+					if (!thread) {
+						remcomOutBuffer[0] = 'E';
+						remcomOutBuffer[1] = '\0';
+						break;
+					}
+					usethread = thread;
+					/* follow through */
+				case 'c':
+					remcomOutBuffer[0] = 'O';
+					remcomOutBuffer[1] = 'K';
+					remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+		/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+#endif /* CONFIG_KGDB_THREAD */
+
+		} /* switch */
+
+		/* reply to the request */
+		putpacket (remcomOutBuffer);
+	} /* while */
+}
+
+/* this function is used to set up exception handlers for tracing and
+   breakpoints */
+void set_debug_traps (void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+	 */
+	linux_debug_hook = handle_exception;
+
+	/*
+	 * In case GDB is started before us, ack any packets (presumably
+	 * "$?#xx") sitting there.  */
+	putDebugChar ('+');
+
+	initialized = 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. Called by init/main.c */
+
+void breakpoint ()
+{
+	if (initialized)
+		BREAKPOINT ();
+}
+
+#ifdef CONFIG_GDB_CONSOLE
+/* KGDB XXX : check if the buffer is large enough to contain console printk's */
+char gdbconbuf[BUFMAX];
+
+void gdb_console_write (struct console *co, const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+
+	if (!gdb_initialized)
+		return;
+	
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2))
+			wcount = (BUFMAX - 2) >> 1;
+		else
+			wcount = count;
+		
+		count -= wcount;
+		for (i = 0; i < wcount; i++)
+			bufptr = pack_hex_byte (bufptr, s[i]);
+		
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+	}
+}
+
+static int __init kgdb_opt_gdbconsole (char *str)
+{
+	gdb_arg_gdbcons = 1;
+	return 1;
+}
+#endif /* CONFIG_GDB_CONSOLE */
+
+static int __init kgdb_opt_gdb (char *str)
+{
+	gdb_arg_enter = 1;
+	return 1;
+}
+
+static int __init kgdb_opt_gdbttyS (char *str)
+{
+	gdb_arg_ttyS = simple_strtoul (str, NULL, 10);
+	return 1;
+}
+
+static int __init kgdb_opt_gdbbaud (char *str)
+{
+	gdb_arg_baud = simple_strtoul (str, NULL, 10);
+	return 1;
+}
+
+/* Sequence of these lines has to be maintained because gdb option is a prefix
+ * of the other two options
+ */
+
+__setup ("gdbttyS=", kgdb_opt_gdbttyS);
+#ifdef CONFIG_GDB_CONSOLE
+__setup ("gdbcons", kgdb_opt_gdbconsole);
+#endif
+__setup ("gdbbaud=", kgdb_opt_gdbbaud);
+__setup ("gdb", kgdb_opt_gdb);
+
+
+
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/kernel/traps.c linux-2.4.22-pa12/arch/parisc/kernel/traps.c
--- linux-2.4.22-pa12.orig/arch/parisc/kernel/traps.c	2002-12-18 09:19:14.000000000 +0100
+++ linux-2.4.22-pa12/arch/parisc/kernel/traps.c	2003-10-04 15:56:59.000000000 +0200
@@ -10,6 +10,11 @@
  * state in 'asm.s'.
  */
 
+/* KGDB XXX:
+ * - check if kGDB could possibly do unaligned access. If so, put CHK_REMOTE
+ *   _DEBUG where it happens.
+ */
+ 
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -26,6 +31,10 @@
 #include <linux/interrupt.h>
 #include <linux/console.h>
 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#include <asm/gdb.h>
+#endif
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -39,6 +48,20 @@
 
 #include "../math-emu/math-emu.h"	/* for handle_fpe() */
 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+gdb_debug_hook * linux_debug_hook;
+
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) {\
+		(*linux_debug_hook)(trapnr, signr, error_code, regs);	\
+		after;							\
+	}								\
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
+#endif /* CONFIG_PARISC_REMOTE_DEBUG */
+
 #define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
 			  /*  dumped to the console via printk)          */
 
@@ -253,8 +276,13 @@
 	return syscall(regs);
 }
 
-/* gdb uses break 4,8 */
+/* gdb uses break 4,8 
+ * kgdb uses break 5,8
+ */
+
 #define GDB_BREAK_INSN 0x10004
+#define KGDB_BREAK_INSN 0x10005
+
 void handle_gdb_break(struct pt_regs *regs, int wot)
 {
 	struct siginfo si;
@@ -266,6 +294,27 @@
 	force_sig_info(SIGTRAP, &si, current);
 }
 
+static void handle_kgdb_break(struct pt_regs *regs, int why)
+{
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+	/* userland, stay off! */
+	if (user_mode(regs))
+		return;
+	
+	switch (why) {
+		case GDB_BREAK_INSN:
+			CHK_REMOTE_DEBUG(KGDB_TRAP_BKPT, SIGTRAP, 0, regs, INCREASE_IAOQ(regs));
+			break;
+		case KGDB_BREAK_INSN:
+			CHK_REMOTE_DEBUG(KGDB_TRAP_BREAK, SIGTRAP, 0, regs, INCREASE_IAOQ(regs));
+			break;
+	}
+#else
+	printk(KERN_ERR "Attempt to handle breakpoint without KGDB stubs!\n");
+	die_if_kernel("Breakpoint", regs, 0);
+#endif /* CONFIG_PARISC_REMOTE_DEBUG */
+}
+
 void handle_break(unsigned iir, struct pt_regs *regs)
 {
 	struct siginfo si;
@@ -286,9 +335,23 @@
 		force_sig_info(SIGTRAP, &si, current);
 		break;
 
+	/* this break was caused by a break 5, 8 instruction : this
+	 * is the code used by kGDB to recognize fixed source-breakpoints
+	 * (in kernel faults or init). In this case, we jump into the debugger
+	 * handle_exception routine and increment IAOQ after.
+	 */
+	case KGDB_BREAK_INSN:
+		if (user_mode(regs))
+			printk(KERN_DEBUG "KGDB Hook in user mode\n");
+		else
+			handle_kgdb_break(regs, iir);
+		break;
+		
 	case GDB_BREAK_INSN:
-		die_if_kernel("Breakpoint", regs, 0);
+		if (user_mode(regs))
 		handle_gdb_break(regs, TRAP_BRKPT);
+		else
+			handle_kgdb_break(regs, iir);
 		break;
 
 	default:
@@ -712,16 +775,21 @@
 	    /*
 	     * The kernel should never fault on its own address space.
 	     */
-
 	    if (fault_space == 0) {
+			CHK_REMOTE_DEBUG(KGDB_TRAP_PAGEFAULT,SIGSEGV,0,regs,goto skip_trap);
 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
 		parisc_terminate("Kernel Fault", regs, code, fault_address);
-		/** NOT REACHED **/
 	    }
 	}
 
 	local_irq_enable();
 	do_page_fault(regs, code, fault_address);
+	return;
+
+	/* skip page fault messages & terminare when kGDB is active */
+skip_trap:
+	INCREASE_IAOQ(regs);
+	local_irq_enable();
 }
 
 
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/arch/parisc/mm/fault.c linux-2.4.22-pa12/arch/parisc/mm/fault.c
--- linux-2.4.22-pa12.orig/arch/parisc/mm/fault.c	2002-11-04 00:18:19.000000000 +0100
+++ linux-2.4.22-pa12/arch/parisc/mm/fault.c	2003-10-04 15:56:59.000000000 +0200
@@ -16,6 +16,10 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#include <asm/gdb.h>
+#endif
+
 #include <asm/uaccess.h>
 #include <asm/traps.h>
 
@@ -155,6 +159,18 @@
 	vma = find_vma_prev(mm, address, &prev_vma);
 	if (!vma || address < vma->vm_start)
 		goto check_expansion;
+		
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		printk(KERN_WARNING "memerr in do_page_fault\n");
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(KGDB_TRAP_PAGEFAULT, SIGSEGV, code, regs) ;
+			INCREASE_IAOQ(regs);	
+			return;            /* return w/modified regs */
+		}
+	}
+#endif
+
 /*
  * Ok, we have a good vm_area for this memory access. We still need to
  * check the access permissions.
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/drivers/char/Makefile linux-2.4.22-pa12/drivers/char/Makefile
--- linux-2.4.22-pa12.orig/drivers/char/Makefile	2003-08-25 20:06:03.000000000 +0200
+++ linux-2.4.22-pa12/drivers/char/Makefile	2003-10-04 15:56:59.000000000 +0200
@@ -165,6 +165,7 @@
   KEYBD = dummy_keyb.o
 endif
 
+obj-$(CONFIG_PARISC_REMOTE_DEBUG) += gdbserial.o
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
 obj-$(CONFIG_SERIAL) += $(SERIAL)
 obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/drivers/char/gdbserial.c linux-2.4.22-pa12/drivers/char/gdbserial.c
--- linux-2.4.22-pa12.orig/drivers/char/gdbserial.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/drivers/char/gdbserial.c	2003-10-04 15:56:59.000000000 +0200
@@ -0,0 +1,477 @@
+/*
+ * Serial interface GDB stub for hppa
+ *
+ * Copyright (c) 2003 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2003 Thibaut Varene <varenet@esiee.fr>
+ *
+ * KGDB originally Written by David Grothe (dave@gcom.com)
+ * Modified by Scott Foehner (sfoehner@engr.sgi.com) to allow connect
+ * on boot-up
+ * GSC Serial device initialisation by Helge Deller (deller@gmx.de)
+ *
+ *	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.
+ *
+ * KGDB TODO: SuperIO.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serialP.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/delay.h>
+
+#include <asm/gdb.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#ifdef CONFIG_GSC
+ #include <asm/gsc.h>
+ #define GDB_OUTB(x,y)	gsc_writeb(x,y)
+ #define GDB_INB(x)	gsc_readb(x)
+ static void gdb_probe_gsc(void);
+#else /* We can deal with only one serial subsystem at the same time */
+ #ifdef CONFIG_SUPERIO
+ #include <asm/superio.h>	/* for superio_serial_init() proto */
+ #include <linux/pci.h>
+ #define GDB_OUTB(x,y)	outb(x,y)
+ #define GDB_INB(x)	inb(x)
+ #endif /* CONFIG_SUPERIO */
+#endif /* CONFIG_GSC */
+
+#define	GDB_BUF_SIZE	512		/* power of 2, please */
+#define MAX_SER_PORTS	4
+
+static char	gdb_buf[GDB_BUF_SIZE];
+static int	gdb_buf_in_inx;
+static atomic_t	gdb_buf_in_cnt;
+static int	gdb_buf_out_inx;
+
+/* Those two are in arch/parisc/kernel/gdbstub.c */
+extern void	set_debug_traps(void);		/* GDB routine */
+extern void	shutdown_for_gdb(struct async_struct * info);
+
+struct serial_state *ser_table[MAX_SER_PORTS];
+struct serial_state *ser;
+
+int gdb_enter = 0;	/* Default: do not do gdb_hook on boot */
+int gdb_initialized = 0;
+
+int serports_initialized = 0;
+
+
+
+/* 
+ *  Takes:
+ *	ttyS - integer specifying which serial port to use for debugging
+ *	baud - baud rate of specified serial port
+ */
+
+int gdb_serial_setup(int ttyS, int baud)
+{
+	unsigned cval;
+	int bits = 8;
+	int parity = 'n';
+	int cflag = CREAD | HUPCL | CLOCAL;
+	int quot = 0;
+
+	ser = ser_table[ttyS];
+	if (ser == NULL) {
+		kgdb_dprintk(KERN_ERR "No ser_table entry for %d\n", ttyS);
+		return -ENODEV;
+	}
+	
+	if (ser->port == 0) 
+		return -ENODEV;
+	
+	/* Now construct a cflag setting */
+	switch(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;
+		case 9600:
+		default:
+			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 */
+	ser->flags &= ~ASYNC_BOOT_AUTOCONF;
+	quot = ser->baud_base / baud;
+	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;
+	
+	GDB_OUTB(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
+	GDB_OUTB(quot & 0xff, ser->port + UART_DLL);         /* LS of divisor */
+	GDB_OUTB(quot >> 8, ser->port + UART_DLM);           /* MS of divisor */
+	GDB_OUTB(cval, ser->port + UART_LCR);                /* reset DLAB */
+	GDB_OUTB(UART_IER_RDI, ser->port + UART_IER);        /* turn on interrupts*/
+	GDB_OUTB(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+
+	/* If we read 0xff from the LSR, there is no UART here */
+	if (GDB_INB(ser->port + UART_LSR) == 0xff)
+		return -EIO;
+	return 0;
+}
+
+
+
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int read_data_bfr(void)
+{
+	unsigned long gdb_port = ser->port;
+	
+	if (GDB_INB(gdb_port + UART_LSR) & UART_LSR_DR)
+		return(GDB_INB(gdb_port + UART_RX));
+
+	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 read_char(void)
+{
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+ 		int chr ;
+		chr = gdb_buf[gdb_buf_out_inx++] ;
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
+		atomic_dec(&gdb_buf_in_cnt) ;
+		return chr ;
+	}
+	return read_data_bfr();	/* read from hardware */
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void write_char(int chr)
+{
+	unsigned long gdb_port = ser->port;
+	
+	while ( !(GDB_INB(gdb_port + UART_LSR) & UART_LSR_THRE) );
+
+   	GDB_OUTB(chr, gdb_port+UART_TX);
+}
+
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static void gdb_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int	chr, iir;
+	unsigned long gdb_port = ser->port;
+	
+	do {
+		chr = read_data_bfr() ;
+		iir = GDB_INB(gdb_port + UART_IIR) ;
+		
+		if (chr < 0)
+			continue ;
+		
+		if (chr == 3) {		/* Ctrl-C means remote interrupt */
+			breakpoint();
+			continue ;
+		}
+		
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			kgdb_dprintk(KERN_ERR "GDB Received buffer overflow\n");
+			gdb_buf_in_inx = 0 ;
+			atomic_set(&gdb_buf_in_cnt, 0) ;
+			gdb_buf_out_inx = 0 ;
+			break ;
+		}
+		
+		gdb_buf[gdb_buf_in_inx++] = chr ;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
+		atomic_inc(&gdb_buf_in_cnt) ;
+	} while (iir & UART_IIR_RDI);
+}
+
+/*
+ * Just a NULL routine for testing.
+ */
+void gdb_null(void)
+{
+}
+
+/* main kGDB hook function
+ *
+ * This is called from init/main.c when "gdb" arg is passed 
+ * on command line. It probes serial ports and initialize
+ * one to use for remote debugging.
+ */
+int gdb_hook(void)
+{
+	int retval;
+	
+#ifdef CONFIG_SMP
+	if (smp_num_cpus > KGDB_MAX_NO_CPUS) { 
+		printk("kgdb: too manu cpus. Cannot enable debugger with more than %u cpus\n",
+			KGDB_MAX_NO_CPUS);
+		return (-1);
+	}
+#endif
+	
+	/* Here we call probe() functions that probe serial ports (dino/lasi
+	 * or superio) and fill the ser_table structure with informations
+	 * related to all ports
+	 */
+#ifdef	CONFIG_GSC
+	gdb_probe_gsc();
+#else
+ #ifdef CONFIG_SUPERIO
+	superio_serial_init();
+ #endif /* CONFIG_SUPERIO */
+#endif /*CONFIG_GSC */
+	 
+
+	/* then we initialize only the serial port associated with kGDB */
+	if (gdb_serial_setup(gdb_arg_ttyS, gdb_arg_baud) != 0) {
+		printk ("gdb_serial_setup() error");
+		return(-1);
+	}
+	
+	retval = request_irq(ser->irq, gdb_interrupt, SA_INTERRUPT, "GDB-stub", NULL);
+	if (retval != 0)
+		printk("gdb_hook: request_irq(irq=%d) failed: %d\n", ser->irq, retval);
+	
+	/* Call GDB routine to setup the exception vectors for the debugger */
+	set_debug_traps() ;
+	
+	/* Call the breakpoint() routine in GDB to start the debugging session */
+	printk("Waiting for connection from remote gdb... ") ;
+	breakpoint() ;
+	gdb_null() ;
+	
+	printk("Connected.\n");
+	
+	gdb_initialized = 1;
+	return(0) ;
+}
+
+/*
+ * getDebugChar
+ *
+ * This is a GDB stub routine.  It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.
+ */
+int getDebugChar(void)
+{
+	volatile int chr;
+	
+#ifdef DEBUG_KGDB_SERIAL
+	printk("getDebugChar: ");
+#endif
+	while ( (chr = read_char()) < 0 );
+	
+	
+#ifdef DEBUG_KGDB_SERIAL
+	printk("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ');
+#endif
+	
+	return(chr);
+}
+
+/*
+ * putDebugChar
+ *
+ * This is a GDB stub routine.  It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.
+ */
+void putDebugChar(int chr)
+{
+#ifdef DEBUG_KGDB_SERIAL
+	printk("putDebugChar: chr=%02x '%c'\n", chr,
+		chr > ' ' && chr < 0x7F ? chr : ' ');
+#endif
+
+	write_char(chr) ;	/* this routine will wait */
+}
+
+/*
+ * GSC specific initialisation stuff.
+ * This function is called by register_paris_driver. It 
+ * fills the ser_table structure with info related to GSC 
+ * serial ports. Later gdb_serial_setup will use these.
+ */
+#ifdef CONFIG_GSC
+static int serial_init_chip(struct parisc_device *dev)
+{
+	static int serial_line_nr;
+	unsigned long address;
+	
+	if (!dev->irq) {
+		if (dev->parent->id.hw_type != HPHW_IOA) {
+			printk(KERN_INFO "Serial: device 0x%lx not configured.\n", dev->hpa);
+		}
+		return -ENODEV;
+	}
+	
+	if (serports_initialized > MAX_SER_PORTS)
+		return -ENOMEM;
+	
+	ser = kmalloc(sizeof(*ser), GFP_KERNEL);
+	if (!ser)
+		return -ENOMEM;
+	memset(ser, 0, sizeof(*ser));
+
+	address = dev->hpa;
+	if (dev->id.sversion != 0x8d)
+		address += 0x800;
+	
+	ser->type = PORT_16550A;
+		
+	ser->line = serial_line_nr++;
+	ser->port = ioremap(address, 0x8);
+	ser->irq = dev->irq;
+	ser->type = SERIAL_IO_MEM;	/* define access method */
+	ser->flags = 0;
+	ser->xmit_fifo_size = 16;
+	ser->custom_divisor = 0;
+	ser->baud_base = LASI_BASE_BAUD;
+	
+	ser_table[serports_initialized] = ser; 
+	serports_initialized++;
+	
+	return 0;
+}
+
+static struct parisc_device_id serial_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
+	{ 0 }
+};
+
+/* Hack.  Dino's serial port will get listed first on some machines.
+ * So we register this driver first which knows about Lasi's serial port.
+ * This needs to get fixed properly somehow.
+ */
+static struct parisc_device_id serial1_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
+	{ 0 }
+};
+
+static struct parisc_driver serial1_driver = {
+	name:		"KGDB Serial RS232",
+	id_table:	serial1_tbl,
+	probe:		serial_init_chip,
+};
+
+static struct parisc_driver serial_driver = {
+	name:		"KGDB Serial RS232",
+	id_table:	serial_tbl,
+	probe:		serial_init_chip,
+};
+
+static void gdb_probe_gsc(void)
+{
+	register_parisc_driver(&serial1_driver);
+	register_parisc_driver(&serial_driver);
+}
+
+#endif /* CONFIG_GSC */
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/drivers/char/serial.c linux-2.4.22-pa12/drivers/char/serial.c
--- linux-2.4.22-pa12.orig/drivers/char/serial.c	2003-08-25 20:06:03.000000000 +0200
+++ linux-2.4.22-pa12/drivers/char/serial.c	2003-10-04 15:56:59.000000000 +0200
@@ -214,7 +214,7 @@
 #include <asm/uaccess.h>
 #endif
 #include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined (CONFIG_GDB_CONSOLE)
 #include <linux/console.h>
 #endif
 #ifdef ENABLE_SERIAL_PCI
@@ -235,6 +235,10 @@
 #include "serial_compat.h"
 #endif
 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#include <asm/gdb.h>
+#endif
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1680,6 +1684,12 @@
 	info->flags &= ~ASYNC_INITIALIZED;
 	restore_flags(flags);
 }
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+void shutdown_for_gdb(struct async_struct * info)
+{
+    shutdown(info) ;
+}
+#endif
 
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 static int baud_table[] = {
@@ -2791,7 +2801,13 @@
 			/* "setserial -W" is called in Debian boot */
 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
 			return 0;
-
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+		case TIOCGDB:
+			printk(KERN_ERR "TIOGDB in rs_ioctl\n");
+			gdb_arg_ttyS = MINOR(tty->device) & 0x03F ;
+			gdb_arg_baud = tty_get_baud_rate(tty) ;
+			return gdb_hook();
+#endif
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -6144,6 +6160,35 @@
 #endif
 
 /*
+ * ------------------------------------------------------------
+ * Serial GDB driver (most in gdbserial.c)
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#ifdef CONFIG_GDB_CONSOLE
+static struct console gdbcons = {
+	name:	"gdb",				/* name */
+	write:	gdb_console_write,	/* write */
+	flags: CON_PRINTBUFFER | CON_ENABLED,	/* flags */
+	index: -1,					/* cflags */
+};
+
+/* la console GDB n'est la que pour renvoyer
+ * les printks vers le remote gdb
+ */
+
+void __init gdb_console_init(void)
+{
+	if (gdb_arg_gdbcons) {
+		printk(KERN_INFO "GDB Console Init\n");
+		register_console(&gdbcons);
+	}
+}
+#endif
+#endif /* CONFIG_PARISC_REMOTE_DEBUG */
+
+/*
   Local variables:
   compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
   End:
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/drivers/gsc/serial.c linux-2.4.22-pa12/drivers/gsc/serial.c
--- linux-2.4.22-pa12.orig/drivers/gsc/serial.c	2002-03-26 06:19:53.000000000 +0100
+++ linux-2.4.22-pa12/drivers/gsc/serial.c	2003-10-04 15:56:59.000000000 +0200
@@ -29,6 +29,7 @@
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/gsc.h>
+#include <asm/gdb.h>
 
 #include "busdevice.h"
 
@@ -76,8 +77,12 @@
 		address += 0x800;
 	}
 
-	setup_parisc_serial(serial, address, dev->irq, serial_line_nr++);
+	if (serial_line_nr == gdb_arg_ttyS) {
+		printk(KERN_WARNING "Not registering serial port already allocated to KGDB\n");
+		return -ENODEV;
+	}
 
+	setup_parisc_serial(serial, address, dev->irq, serial_line_nr++);
 	if (register_serial(serial) < 0) {
 		printk(KERN_WARNING "register_serial returned error\n");
 		kfree(serial);
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/fs/proc/proc_misc.c linux-2.4.22-pa12/fs/proc/proc_misc.c
--- linux-2.4.22-pa12.orig/fs/proc/proc_misc.c	2003-08-25 20:06:37.000000000 +0200
+++ linux-2.4.22-pa12/fs/proc/proc_misc.c	2003-10-04 15:56:59.000000000 +0200
@@ -150,6 +150,17 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+static int bugme_read_proc(char *page, char **start, off_t off,
+				 int count, int *eof, void *data)
+{
+	char *a = NULL;
+
+	*a = '0';
+
+	return 0;
+}
+
+
 static int meminfo_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -575,6 +586,7 @@
 	} *p, simple_ones[] = {
 		{"loadavg",     loadavg_read_proc},
 		{"uptime",	uptime_read_proc},
+		{"bugme",	bugme_read_proc},
 		{"meminfo",	meminfo_read_proc},
 		{"version",	version_read_proc},
 #ifdef CONFIG_PROC_HARDWARE
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/include/asm-parisc/gdb.h linux-2.4.22-pa12/include/asm-parisc/gdb.h
--- linux-2.4.22-pa12.orig/include/asm-parisc/gdb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pa12/include/asm-parisc/gdb.h	2003-10-04 15:56:59.000000000 +0200
@@ -0,0 +1,94 @@
+#ifndef _GDB_H_
+#define _GDB_H_
+
+/*
+ * Copyright (C) 2001 Amit S. Kale
+ * 
+ * hppa bits are
+ * Copyright (c) 2003 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2003 Thibaut Varene <varenet@esiee.fr>
+ *
+ * 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.
+ */
+
+#include <asm/ptrace.h>	/* struct pt_regs */
+#include <asm/psw.h>		/* PSW_B */
+#include <linux/console.h>
+
+/* define to debug KGDB itself */
+#undef KGDB_DEBUG
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS	8
+
+#define KGDB_TRAP_DIE		1		/* kernel dies */
+#define KGDB_TRAP_BREAK	2		/* break 5,8 */
+#define KGDB_TRAP_PAGEFAULT	3		/* kernel page faults : mostly kgdb mem erri */
+#define KGDB_TRAP_BKPT		4		/* GDB breakpoint */
+
+/* this increases the IAOQ registers (pc) for next, continue and mem err */
+#define INCREASE_IAOQ(regs)		{ \
+	regs->iaoq[0] = regs->iaoq[1]; \
+	regs->iaoq[1] = regs->iaoq[0] + 4; \
+	regs->gr[0] &= ~PSW_B; } 
+
+#define KGDB_ASSERT(message, condition)	do {			\
+	if (!(condition)) {					\
+		printk("kgdb assertion failed: %s\n", message); \
+		asm ("break 5,8");		\
+	}							\
+} while (0)
+
+#ifdef CONFIG_KERNEL_ASSERTS
+ #define KERNEL_ASSERT(message, condition) KGDB_ASSERT(message, condition)
+#else
+ #define KERNEL_ASSERT(message, condition)
+#endif
+
+#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))
+
+#ifndef CONFIG_SMP
+ #define KA_HELD_GKL()	1
+#else
+ #define KA_HELD_GKL()	(current->lock_depth >= 0)
+#endif
+
+#ifdef KGDB_DEBUG
+ #define kgdb_dprintk(fmt, args...)	printk(fmt, ##args)
+#else
+ #define kgdb_dprintk(x,...)
+#endif
+
+extern int gdb_arg_enter;	/* 1 = enter debugger on boot */
+extern int gdb_arg_ttyS;
+extern int gdb_arg_baud;
+extern int gdb_arg_gdbcons;
+extern int gdb_initialized;
+
+extern int gdb_hook(void);
+extern void breakpoint(void);
+
+typedef void gdb_debug_hook(int trapno, int signo, int err_code, struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+
+extern volatile unsigned kgdb_lock;
+extern volatile int kgdb_memerr_expected;
+
+struct console;
+void gdb_console_write(struct console *co, const char *s, unsigned count);
+void gdb_console_init(void);
+
+void gdb_wait(struct pt_regs *regs);
+
+#endif /* _GDB_H_ */
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/include/asm-parisc/ioctls.h linux-2.4.22-pa12/include/asm-parisc/ioctls.h
--- linux-2.4.22-pa12.orig/include/asm-parisc/ioctls.h	2001-10-27 01:24:55.000000000 +0200
+++ linux-2.4.22-pa12/include/asm-parisc/ioctls.h	2003-10-04 15:56:59.000000000 +0200
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TIOCGDB	0x547F	/* enable GDB stub mode on this terminal */
 #define FIOQSIZE	0x5460	/* Get exact space used by quota */
 
 /* Used for packet mode */
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/include/asm-parisc/page.h linux-2.4.22-pa12/include/asm-parisc/page.h
--- linux-2.4.22-pa12.orig/include/asm-parisc/page.h	2002-08-05 00:59:52.000000000 +0200
+++ linux-2.4.22-pa12/include/asm-parisc/page.h	2003-10-04 15:56:59.000000000 +0200
@@ -10,6 +10,7 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/cache.h>
+#include <asm/gdb.h>
 
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)      copy_user_page_asm((void *)(to), (void *)(from))
@@ -88,10 +89,16 @@
  * see^H^H^Hhear bugs in early bootup as well!
  *
  * We don't beep yet.  prumpf
+ * Run KGDB if compiled.
  */
+ 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#define BUG() KGDB_ASSERT("BUG", 0)
+#else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 } while (0)
+#endif
 
 #define PAGE_BUG(page) do { \
 	BUG(); \
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/include/asm-parisc/processor.h linux-2.4.22-pa12/include/asm-parisc/processor.h
--- linux-2.4.22-pa12.orig/include/asm-parisc/processor.h	2003-03-20 16:04:36.000000000 +0100
+++ linux-2.4.22-pa12/include/asm-parisc/processor.h	2003-10-04 15:56:59.000000000 +0200
@@ -120,6 +120,9 @@
 	unsigned long  task_size;
 	unsigned long  map_base;
 	unsigned long  flags;
+#ifdef CONFIG_KGDB_THREAD
+	int gotregs;
+#endif
 }; 
 
 /* Thread struct flags. */
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/include/linux/sched.h linux-2.4.22-pa12/include/linux/sched.h
--- linux-2.4.22-pa12.orig/include/linux/sched.h	2003-06-26 17:08:08.000000000 +0200
+++ linux-2.4.22-pa12/include/linux/sched.h	2003-10-04 15:56:59.000000000 +0200
@@ -146,7 +146,18 @@
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
-asmlinkage void schedule(void);
+
+asmlinkage void do_schedule(void);
+asmlinkage void kern_do_schedule(void);
+
+static inline void schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	kern_do_schedule();
+#else
+	do_schedule();
+#endif
+}
 
 extern int schedule_task(struct tq_struct *task);
 extern void flush_scheduled_tasks(void);
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/init/main.c linux-2.4.22-pa12/init/main.c
--- linux-2.4.22-pa12.orig/init/main.c	2003-08-25 20:07:12.000000000 +0200
+++ linux-2.4.22-pa12/init/main.c	2003-10-04 15:56:59.000000000 +0200
@@ -73,6 +73,10 @@
 #include <asm/smp.h>
 #endif
 
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+#include <asm/gdb.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -443,6 +447,11 @@
 	 *	make syscalls (and thus be locked).
 	 */
 	smp_init();
+#ifdef CONFIG_PARISC_REMOTE_DEBUG
+	if (gdb_arg_enter) {
+		gdb_hook();		/* right at boot time */
+	}
+#endif
 	rest_init();
 }
 
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/kernel/ksyms.c linux-2.4.22-pa12/kernel/ksyms.c
--- linux-2.4.22-pa12.orig/kernel/ksyms.c	2003-08-25 20:07:12.000000000 +0200
+++ linux-2.4.22-pa12/kernel/ksyms.c	2003-10-04 15:56:59.000000000 +0200
@@ -455,7 +455,8 @@
 EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
-EXPORT_SYMBOL(schedule);
+EXPORT_SYMBOL(do_schedule);
+EXPORT_SYMBOL(kern_do_schedule);
 EXPORT_SYMBOL(schedule_timeout);
 #if CONFIG_SMP
 EXPORT_SYMBOL(set_cpus_allowed);
diff -EbBNaur -x CVS linux-2.4.22-pa12.orig/kernel/sched.c linux-2.4.22-pa12/kernel/sched.c
--- linux-2.4.22-pa12.orig/kernel/sched.c	2003-08-25 20:07:12.000000000 +0200
+++ linux-2.4.22-pa12/kernel/sched.c	2003-10-04 15:57:00.000000000 +0200
@@ -544,7 +544,7 @@
  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
  * information in task[0] is never used.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	struct schedule_data * sched_data;
 	struct task_struct *prev, *next, *p;
@@ -702,6 +702,22 @@
 	return;
 }
 
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.gotregs = 0;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(void)
+{
+	current->thread.gotregs = 1;
+	do_schedule();
+}
+#endif
+
 /*
  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
  * up.  If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the
