diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/Documentation/i386/gdb-serial.txt 200-kgdb/Documentation/i386/gdb-serial.txt
--- 141-no_vma_sort/Documentation/i386/gdb-serial.txt	Wed Dec 31 16:00:00 1969
+++ 200-kgdb/Documentation/i386/gdb-serial.txt	Sun Apr 20 21:28:58 2003
@@ -0,0 +1,386 @@
+Version
+=======
+
+This version of the gdbstub package was developed and tested on
+kernel version 2.3.48.  It will not install on a 2.2 kernel.  It may
+not work on earlier versions of 2.3 kernels.  It is possible that
+it will continue to work on later versions of 2.3 and then
+versions of 2.4 (I hope).
+
+
+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 LILO command line.  The patch defaults to use ttyS1 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:
+
+LILO boot: 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.
+
+An alternate approach is to place a line in the /etc/lilo.conf file on
+your TARGET machine.  Under the heading for the kernel that you intend
+to boot, place a line that looks like this:
+
+    append = "gdb gdbttyS=1 gdbbaud=38400"
+
+This will cause the kernel to enter the gdbstub automatically at boot
+time.
+
+BE SURE to run "lilo" after changing the /etc/lilo.conf file.
+
+
+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/i386/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.
+
+There is a copy of an e-mail in the kgdb distribution directory which
+describes how to create an NMI on an ISA bus machine using a paper
+clip.  I have a sophisticated version of this made by wiring a push
+button switch into a PC104/ISA bus adapter card.  The adapter card
+nicely furnishes wire wrap pins for all the ISA bus signals.
+
+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.
+
+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/i386/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.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory with kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread related
+commands (info threads, thread n) can be used. 
+
+ia-32 hardware breakpoints
+==========================
+
+gdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+1. Execution breakpoint - An Execution breakpoint is triggered when code at the
+	breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is advisable
+	to use software breakpoints ( break command ) instead of execution
+	hardware breakpoints, unless modification of code is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory location at the
+	breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of a write
+	breakpoint indicates length of the datatype to be watched. Length is 1
+	for 1 byte data , 2 for 2 byte data, 3 for 4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory location at
+	the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occured.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occured.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+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.
+
+ia-32 hardware debugging registers on all processors are set to same values.
+Hence any hardware breakpoints may occur on any processor.
+
+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.
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/Documentation/sysrq.txt 200-kgdb/Documentation/sysrq.txt
--- 141-no_vma_sort/Documentation/sysrq.txt	Wed Mar 26 22:54:28 2003
+++ 200-kgdb/Documentation/sysrq.txt	Sun Apr 20 21:28:58 2003
@@ -77,6 +77,8 @@ On all -  write a character to /proc/sys
 'l'     - Send a SIGKILL to all processes, INCLUDING init. (Your system
           will be non-functional after this.)
 
+'g'	- Enter the kernel debugger (if configured and supported).
+
 'h'     - Will display help ( actually any other key than those listed
           above will display help. but 'h' is easy to remember :-)
 
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/Makefile 200-kgdb/Makefile
--- 141-no_vma_sort/Makefile	Sun Apr 20 19:34:55 2003
+++ 200-kgdb/Makefile	Sun Apr 20 21:28:58 2003
@@ -287,6 +287,10 @@ endif
 endif
 endif
 
+ifdef CONFIG_X86_REMOTE_DEBUG
+CFLAGS += -g
+endif
+
 #
 # INSTALL_PATH specifies where to place the updated kernel and system map
 # images.  Uncomment if you want to place them anywhere other than root.
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/Kconfig 200-kgdb/arch/i386/Kconfig
--- 141-no_vma_sort/arch/i386/Kconfig	Sun Apr 20 21:09:40 2003
+++ 200-kgdb/arch/i386/Kconfig	Sun Apr 20 21:28:58 2003
@@ -1521,6 +1521,17 @@ config DEBUG_SLAB
 	  allocation as well as poisoning memory on free to catch use of freed
 	  memory.
 
+config X86_REMOTE_DEBUG
+	bool "KGDB: Remote (serial) kernel debugging with gdb"
+
+config KGDB_THREAD
+	bool "KGDB: Thread analysis"
+	depends on X86_REMOTE_DEBUG
+
+config GDB_CONSOLE
+	bool "KGDB: Console messages through gdb"
+	depends on X86_REMOTE_DEBUG
+
 config DEBUG_IOVIRT
 	bool "Memory mapped I/O debugging"
 	depends on DEBUG_KERNEL
@@ -1596,7 +1607,9 @@ config DEBUG_SPINLOCK_SLEEP
 	  noisy if they are called with a spinlock held.	
 
 config FRAME_POINTER
-	bool "Compile the kernel with frame pointers"
+	bool
+	default y if X86_REMOTE_DEBUG
+	default n if !X86_REMOTE_DEBUG
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
 	  and slower, but it will give very useful debugging information.
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/Makefile 200-kgdb/arch/i386/kernel/Makefile
--- 141-no_vma_sort/arch/i386/kernel/Makefile	Mon Mar 17 21:43:38 2003
+++ 200-kgdb/arch/i386/kernel/Makefile	Sun Apr 20 21:28:58 2003
@@ -17,6 +17,7 @@ obj-$(CONFIG_MCA)		+= mca.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
+obj-$(CONFIG_X86_REMOTE_DEBUG)	+= gdbstub.o
 obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o
 obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
@@ -29,6 +30,14 @@ obj-$(CONFIG_EDD)             	+= edd.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
+
+ifdef CONFIG_X86_REMOTE_DEBUG
+GDBSTART=gdbstart
+GDBCLEAN= -rm -f gdbstart /sbin/gdbstart
+else
+GDBSTART=
+GDBCLEAN=
+endif
 
 EXTRA_AFLAGS   := -traditional
 
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/entry.S 200-kgdb/arch/i386/kernel/entry.S
--- 141-no_vma_sort/arch/i386/kernel/entry.S	Wed Mar 26 22:54:28 2003
+++ 200-kgdb/arch/i386/kernel/entry.S	Sun Apr 20 21:28:58 2003
@@ -224,7 +224,7 @@ need_resched:
 	jz restore_all
 	movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
 	sti
-	call schedule
+	call user_schedule
 	movl $0,TI_PRE_COUNT(%ebp)
 	cli
 	jmp need_resched
@@ -306,7 +306,7 @@ work_pending:
 	testb $_TIF_NEED_RESCHED, %cl
 	jz work_notifysig
 work_resched:
-	call schedule
+	call user_schedule
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
@@ -549,6 +549,31 @@ ENTRY(coprocessor_segment_overrun)
 ENTRY(invalid_TSS)
 	pushl $do_invalid_TSS
 	jmp error_code
+
+#ifdef CONFIG_KGDB_THREAD
+ENTRY(kern_schedule)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ss		
+	pushl	%ebp
+	pushfl
+	pushl	%cs
+	pushl	4(%ebp)
+	pushl	%eax		
+	pushl	%es
+	pushl	%ds
+	pushl	%eax
+	pushl	(%ebp)
+	pushl	%edi
+	pushl	%esi
+	pushl	%edx
+	pushl	%ecx
+	pushl	%ebx
+	call	kern_do_schedule
+	movl	%ebp, %esp
+	pop	%ebp
+	ret
+#endif
 
 ENTRY(segment_not_present)
 	pushl $do_segment_not_present
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/gdbstart.c 200-kgdb/arch/i386/kernel/gdbstart.c
--- 141-no_vma_sort/arch/i386/kernel/gdbstart.c	Wed Dec 31 16:00:00 1969
+++ 200-kgdb/arch/i386/kernel/gdbstart.c	Sun Apr 20 21:28:58 2003
@@ -0,0 +1,147 @@
+/*
+ * This program opens a tty file and issues the GDB stub activating
+ * ioctl on it.
+ */
+
+#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 */
+
+int 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 1;
+	}
+    }
+
+    fil = open(tty_name, O_RDWR) ;
+    if (fil < 0)
+    {
+	perror(tty_name) ;
+	return 1;
+    }
+
+
+    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 1;
+    }
+
+    printf("\nGDB stub successfully activated\n") ;
+
+    for (;;)
+    {
+	pause() ;
+    }
+
+    if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
+
+    exit(0);
+} /* main */
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/gdbstub.c 200-kgdb/arch/i386/kernel/gdbstub.c
--- 141-no_vma_sort/arch/i386/kernel/gdbstub.c	Wed Dec 31 16:00:00 1969
+++ 200-kgdb/arch/i386/kernel/gdbstub.c	Sun Apr 20 21:28:58 2003
@@ -0,0 +1,1208 @@
+/*
+ *
+ * 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.
+ */
+/****************************************************************************
+ *  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 $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  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>
+ *      thread support,
+ *      support for multiple processors,
+ *  	support for ia-32(x86) hardware debugging,
+ *  	Console support,
+ *  	handling nmi watchdog
+ *  	Amit S. Kale ( akale@veritas.com )
+ *
+ *
+ *  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 an int 3.
+ *
+ *************
+ *
+ *    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)
+ *
+ * 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 <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/gdb.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int putDebugChar(int);	/* write a single character      */
+extern int getDebugChar(void);	/* read and return a single char */
+
+extern int pid_max;
+
+/************************************************************************/
+/* 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
+
+static char initialized;	/* boolean flag. != 0 means we've been initialized */
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * 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 */
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/* 									   */
+
+#define BREAKPOINT() asm("   int $3");
+
+/* 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;
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#ifdef CONFIG_SMP
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+spinlock_t kgdb_nmispinlock = SPIN_LOCK_UNLOCKED;
+#else
+unsigned kgdb_spinlock = 0;
+unsigned kgdb_nmispinlock = 0;
+#endif
+
+static void
+kgdb_usercode(void)
+{
+}
+
+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>     */
+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.  */
+
+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 char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+static void
+regs_to_gdb_regs(int *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;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(int *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];
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+
+/* 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;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+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.  */
+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;
+	}
+	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 */
+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);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED           */
+/**********************************************/
+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);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+static int
+stubhex(int 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;
+}
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+#ifdef CONFIG_KGDB_THREAD
+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 = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+
+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);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+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;
+	}
+#if 0
+	thread = init_tasks[0];
+	do {
+		if (thread->pid == pid) {
+			return thread;
+		}
+		thread = thread->next_task;
+	} while (thread != init_tasks[0]);
+#endif
+	return NULL;
+}
+#endif
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {
+enabled:0}, {
+enabled:0}, {
+enabled:0}, {
+enabled:0}};
+
+void
+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));
+	}
+}
+
+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
+gdb_wait(void *arg)
+{
+	unsigned flags;
+	int processor;
+
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.kgdbregs = arg;
+	spin_lock(slavecpulocks + processor);
+	correct_hw_break();
+	procindebug[processor] = 0;
+	local_irq_restore(flags);
+}
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *        enable flag UNCHANGED.  That means that when this routine
+ *        is entered via a breakpoint (INT 3) instruction from code
+ *        that has interrupts enabled, then interrupts will STILL BE
+ *        enabled when this routine is entered.  The first thing that
+ *        we do here is disable interrupts so as to prevent recursive
+ *        entries and bothersome serial interrupts while we are
+ *        trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+handle_exception(int exceptionVector,
+		 int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	int addr, length;
+	int breakno, breaktype;
+	char *ptr;
+	int newPC;
+	unsigned long flags = ~0UL;
+	int gdb_regs[NUMREGBYTES / 4];
+	int i;
+	int dr6;
+	int reboot = 0;
+#ifdef CONFIG_KGDB_THREAD
+	int nothreads;
+	int maxthreads;
+	int threadid;
+	threadref thref;
+	struct task_struct *thread = NULL;
+#endif
+#define	regs	(*linux_regs)
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		return (0);
+	}
+
+	if (kgdb_memerr_expected) {
+		/*
+		 * 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 */
+		regs.eax = (long) &garbage_loc;	/* make valid address */
+		regs.edx = (long) &garbage_loc;	/* make valid address */
+		return (0);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_nmispinlock))
+#else
+	if (!kgdb_nmispinlock)
+#endif
+	{
+
+		/* Get kgdb spinlock */
+#ifdef CONFIG_SMP
+		_raw_spin_lock(&kgdb_spinlock);
+#else
+		kgdb_spinlock = 1;
+#endif
+
+		local_irq_save(flags);
+
+		/* Disable hardware debugging while we are in kgdb */
+	      __asm__("movl %0,%%db7":	/* no output */
+	      :"r"(0));
+
+		for (i = 0; i < NR_CPUS; i++) {
+			spin_lock_init(&slavecpulocks[i]);
+			_raw_spin_lock(&slavecpulocks[i]);
+		}
+
+		if (num_online_cpus() > 1) {
+			/* Force other cpus in debugger */
+			if (smp_call_function(gdb_wait, NULL, 0, 99) != 0) {
+				return (1);
+			}
+		}
+
+		procindebug[smp_processor_id()] = 1;
+	}
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+
+	/* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 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, &regs);
+			} else {
+				memset(gdb_regs, 0, NUMREGBYTES);
+				if (usethread->thread.kgdbregs) {
+					kgdb_memerr_expected = 1;
+					kgdb_memerr = 0;
+					get_char((char *) usethread->thread.
+						 kgdbregs);
+					kgdb_memerr_expected = 0;
+					if (kgdb_memerr) {
+						gdb_regs[_PC] =
+						    (int) kgdb_usercode;
+					} else {
+						regs_to_gdb_regs(gdb_regs,
+								 usethread->
+								 thread.
+								 kgdbregs);
+					}
+				} else {
+					gdb_regs[_PC] = (int) kgdb_usercode;
+				}
+			}
+			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, &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))
+				if (*(ptr++) == ',')
+					if (hexToInt(&ptr, &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))
+				if (*(ptr++) == ',')
+					if (hexToInt(&ptr, &length))
+						if (*(ptr++) == ':') {
+							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) */
+		case 'c':
+		case 's':
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock)
+#endif
+			{
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* try to read optional parameter, pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			asm volatile ("movl %%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 */
+							regs.eflags |= 0x10000;
+							break;
+						}
+					}
+				}
+			}
+			correct_hw_break();
+			asm volatile ("movl %0, %%db6\n"::"r" (0));
+			for (i = 0; i < NR_CPUS; i++) {
+				_raw_spin_unlock(&slavecpulocks[i]);
+			}
+
+			procindebug[smp_processor_id()] = 0;
+			/* Release kgdb spinlock */
+#ifdef CONFIG_SMP
+			_raw_spin_unlock(&kgdb_spinlock);
+#else
+			kgdb_spinlock = 0;
+#endif
+			if (flags != ~0UL)
+				local_irq_restore(flags);
+			return (0);
+
+			/* kill the program */
+		case 'k':
+			break;
+
+			/* query */
+		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++) {
+					thread = getthread(threadid);
+					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
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector, err_code,
+						   remcomOutBuffer);
+				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
+
+		case 'r':
+			reboot = 1;
+			strcpy(remcomOutBuffer, "OK");
+			break;
+		case 'Y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&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];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+		if (reboot == 1) {
+			static long no_idt[2];
+			__asm__ __volatile__("lidt %0"::"m"(no_idt));
+			__asm__ __volatile__("int3");
+		}
+	}
+}
+
+/* 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. */
+
+void
+breakpoint(void)
+{
+	if (initialized)
+		BREAKPOINT();
+}
+
+#ifdef CONFIG_GDB_CONSOLE
+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);
+
+	}
+}
+#endif
+static int __init
+kgdb_opt_gdb(char *dummy)
+{
+	gdb_enter = 1;
+	return 1;
+}
+static int __init
+kgdb_opt_gdbttyS(char *str)
+{
+	gdb_ttyS = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+static int __init
+kgdb_opt_gdbbaud(char *str)
+{
+	gdb_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);
+__setup("gdbbaud=", kgdb_opt_gdbbaud);
+__setup("gdb", kgdb_opt_gdb);
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/i386_ksyms.c 200-kgdb/arch/i386/kernel/i386_ksyms.c
--- 141-no_vma_sort/arch/i386/kernel/i386_ksyms.c	Sun Apr 20 19:34:56 2003
+++ 200-kgdb/arch/i386/kernel/i386_ksyms.c	Sun Apr 20 21:28:58 2003
@@ -149,6 +149,20 @@ EXPORT_SYMBOL(smp_num_siblings);
 EXPORT_SYMBOL(cpu_sibling_map);
 #endif
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+void __this_fixmap_does_not_exist(void)
+{
+	BUG();
+}
+EXPORT_SYMBOL(__this_fixmap_does_not_exist);
+
+void __br_lock_usage_bug(void)
+{
+	BUG();
+}
+EXPORT_SYMBOL(__br_lock_usage_bug);
+#endif
+
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(cpu_online_map);
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/nmi.c 200-kgdb/arch/i386/kernel/nmi.c
--- 141-no_vma_sort/arch/i386/kernel/nmi.c	Sun Apr 20 19:34:57 2003
+++ 200-kgdb/arch/i386/kernel/nmi.c	Sun Apr 20 21:28:58 2003
@@ -23,6 +23,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/module.h>
+#include <linux/gdb.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
@@ -33,6 +34,20 @@ static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 extern void show_registers(struct pt_regs *regs);
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+extern 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
+
 #define K7_EVNTSEL_ENABLE	(1 << 22)
 #define K7_EVNTSEL_INT		(1 << 20)
 #define K7_EVNTSEL_OS		(1 << 17)
@@ -390,12 +405,59 @@ void nmi_watchdog_tick (struct pt_regs *
 	sum = irq_stat[cpu].apic_timer_irqs;
 
 	if (last_irq_sums[cpu] == sum) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+		if (spin_is_locked(&kgdb_spinlock))
+#else
+		if (kgdb_spinlock) 
+#endif
+		{
+			/* We are inside kgdb, this isn't a stuck cpu */
+			alert_counter[cpu] = 0;
+		} else {
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock) 
+#endif
+			{
+				if (!procindebug[cpu]) {
+					procindebug[cpu] = 1;
+					current->thread.kgdbregs = regs;
+					while (1) {
+						/* nothing */
+					}
+				}
+				return;
+			}
+		}
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+			if (spin_trylock(&kgdb_nmispinlock))
+#else
+			kgdb_nmispinlock = 1;
+#endif
+			{
+				procindebug[cpu] = 1;
+				CHK_REMOTE_DEBUG(2,SIGBUS,0,regs,)
+			} 
+#ifdef CONFIG_SMP
+			else {
+				procindebug[cpu] = 1;
+				current->thread.kgdbregs = regs;
+				while (1) {
+					/* nothing */
+				}
+			}
+#endif
+#endif
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/smp.c 200-kgdb/arch/i386/kernel/smp.c
--- 141-no_vma_sort/arch/i386/kernel/smp.c	Tue Apr  8 14:38:14 2003
+++ 200-kgdb/arch/i386/kernel/smp.c	Sun Apr 20 21:28:58 2003
@@ -509,10 +509,17 @@ int smp_call_function (void (*func) (voi
 {
 	struct call_data_struct data;
 	int cpus = num_online_cpus()-1;
+	int count = 0;
+	int gdb;
 
-	if (!cpus)
+	if (cpus <= 0)
 		return 0;
 
+	gdb = 0;
+	if (wait == 99) {
+		wait = 0;
+		gdb = 1;
+	}
 	data.func = func;
 	data.info = info;
 	atomic_set(&data.started, 0);
@@ -528,12 +535,27 @@ int smp_call_function (void (*func) (voi
 	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
 	/* Wait for response */
-	while (atomic_read(&data.started) != cpus)
+	while (atomic_read(&data.started) != cpus) {
+		if (gdb) {
+			if (count++ == 2000000) {
+				printk("%s: timeout\n", __FUNCTION__);
+				break;
+			}
+			if (count == 1000000) {
+				printk("looks bad\n");
+				printk("cpus=%d, started=%d\n", cpus,
+					atomic_read(&data.started));
+			}
+			if (count > 1000000)
+				udelay(1);
+		}
 		barrier();
+	}
 
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
 			barrier();
+
 	spin_unlock(&call_lock);
 
 	return 0;
@@ -575,9 +597,9 @@ asmlinkage void smp_reschedule_interrupt
 	ack_APIC_irq();
 }
 
-asmlinkage void smp_call_function_interrupt(void)
+asmlinkage void smp_call_function_interrupt(struct pt_regs regs)
 {
-	void (*func) (void *info) = call_data->func;
+	void (*func) (void *info, struct pt_regs *) = (void (*)(void *, struct pt_regs*))call_data->func;
 	void *info = call_data->info;
 	int wait = call_data->wait;
 
@@ -592,7 +614,7 @@ asmlinkage void smp_call_function_interr
 	 * At this point the info structure may be out of scope unless wait==1
 	 */
 	irq_enter();
-	(*func)(info);
+	(*func)(info, &regs);
 	irq_exit();
 
 	if (wait) {
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/kernel/traps.c 200-kgdb/arch/i386/kernel/traps.c
--- 141-no_vma_sort/arch/i386/kernel/traps.c	Sun Apr 20 19:34:57 2003
+++ 200-kgdb/arch/i386/kernel/traps.c	Sun Apr 20 21:28:58 2003
@@ -53,6 +53,24 @@
 
 #include "mach_traps.h"
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
+#ifdef CONFIG_X86_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
+ 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
@@ -259,6 +277,7 @@ void die(const char * str, struct pt_reg
 	bust_spinlocks(1);
 	handle_BUG(regs);
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+	CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,);
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -328,6 +347,7 @@ static inline void do_trap(int trapnr, i
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -345,7 +365,9 @@ asmlinkage void do_##name(struct pt_regs
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,return)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -388,8 +410,10 @@ gp_in_vm86:
 	return;
 
 gp_in_kernel:
-	if (!fixup_exception(regs))
+	if (!fixup_exception(regs)) {
+		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,);
 		die("general protection fault", regs, error_code);
+	}
 }
 
 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
@@ -551,8 +575,10 @@ asmlinkage void do_debug(struct pt_regs 
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifndef CONFIG_X86_REMOTE_DEBUG
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -564,11 +590,13 @@ asmlinkage void do_debug(struct pt_regs 
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
-	/* If this is a kernel mode trap, save the user PC on entry to 
-	 * the kernel, that's what the debugger can make sense of.
-	 */
-	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
-	                                        (void *)regs->eip;
+
+	/* If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+	info.si_addr = (void *)regs->eip;
 	force_sig_info(SIGTRAP, &info, tsk);
 
 	/* Disable additional traps. They'll be re-enabled when
@@ -578,13 +606,16 @@ clear_dr7:
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
 	return;
 
+#ifndef CONFIG_X86_REMOTE_DEBUG
 clear_TF_reenable:
+#endif
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 clear_TF:
 	regs->eflags &= ~TF_MASK;
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/i386/mm/fault.c 200-kgdb/arch/i386/mm/fault.c
--- 141-no_vma_sort/arch/i386/mm/fault.c	Mon Mar 17 21:43:39 2003
+++ 200-kgdb/arch/i386/mm/fault.c	Sun Apr 20 21:28:58 2003
@@ -2,6 +2,11 @@
  *  linux/arch/i386/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Change History
+ *
+ *	Tigran Aivazian <tigran@sco.com>	Remote debugging support.
+ *
  */
 
 #include <linux/signal.h>
@@ -20,6 +25,9 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/module.h>
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -193,6 +201,15 @@ asmlinkage void do_page_fault(struct pt_
 	if (in_atomic() || !mm)
 		goto no_context;
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs) ;
+			return;            /* return w/modified regs */
+		}
+	}
+#endif
+
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
@@ -291,6 +308,19 @@ bad_area:
 		force_sig_info(SIGSEGV, &info, tsk);
 		return;
 	}
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+			return; /* Return with modified registers */
+		}
+	} else {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+		}
+	}
+#endif
 
 #ifdef CONFIG_X86_F00F_BUG
 	/*
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/sparc64/kernel/rtrap.S 200-kgdb/arch/sparc64/kernel/rtrap.S
--- 141-no_vma_sort/arch/sparc64/kernel/rtrap.S	Tue Apr  8 14:38:15 2003
+++ 200-kgdb/arch/sparc64/kernel/rtrap.S	Sun Apr 20 21:28:58 2003
@@ -33,7 +33,7 @@ __handle_softirq:
 		ba,a,pt			%xcc, __handle_softirq_continue
 		 nop
 __handle_preemption:
-		call			schedule
+		call			user_schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		ba,pt			%xcc, __handle_preemption_continue
 		 wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
@@ -48,7 +48,7 @@ __handle_user_windows:
 
 		be,pt			%xcc, 1f
 		 nop
-		call			schedule
+		call			user_schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldx			[%g6 + TI_FLAGS], %l0
@@ -92,7 +92,7 @@ __handle_perfctrs:
 		be,pt			%xcc, 1f
 
 		 nop
-		call			schedule
+		call			user_schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldx			[%g6 + TI_FLAGS], %l0
@@ -273,7 +273,7 @@ to_kernel:
 		 sethi			%hi(PREEMPT_ACTIVE), %l6
 		stw			%l6, [%g6 + TI_PRE_COUNT]
 		wrpr			0, %pil
-		call			schedule
+		call			user_schedule
 		 nop
 		ba,pt			%xcc, rtrap
 		 stw			%g0, [%g6 + TI_PRE_COUNT]
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/arch/x86_64/kernel/entry.S 200-kgdb/arch/x86_64/kernel/entry.S
--- 141-no_vma_sort/arch/x86_64/kernel/entry.S	Tue Apr  8 14:38:15 2003
+++ 200-kgdb/arch/x86_64/kernel/entry.S	Sun Apr 20 21:28:58 2003
@@ -187,7 +187,7 @@ sysret_careful:
 	jnc sysret_signal
 	sti
 	pushq %rdi
-	call schedule
+	call user_schedule
 	popq  %rdi
 	jmp sysret_check
 
@@ -256,7 +256,7 @@ int_careful:
 	jnc  int_very_careful
 	sti
 	pushq %rdi
-	call schedule
+	call user_schedule
 	popq %rdi
 	jmp int_with_check
 
@@ -425,7 +425,7 @@ retint_careful:
 	jnc   retint_signal
 	sti
 	pushq %rdi
-	call  schedule
+	call  user_schedule
 	popq %rdi		
 	GET_THREAD_INFO(%rcx)
 	cli
@@ -459,7 +459,7 @@ retint_kernel:	
 	jc   retint_restore_args
 	movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx)
 	sti
-	call schedule
+	call user_schedule
 	cli
 	GET_THREAD_INFO(%rcx)
 	movl $0,threadinfo_preempt_count(%rcx) 
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/char/Makefile 200-kgdb/drivers/char/Makefile
--- 141-no_vma_sort/drivers/char/Makefile	Wed Mar 26 22:54:30 2003
+++ 200-kgdb/drivers/char/Makefile	Sun Apr 20 21:28:58 2003
@@ -25,6 +25,7 @@ obj-$(CONFIG_COMPUTONE) += ip2.o ip2main
 obj-$(CONFIG_RISCOM8) += riscom8.o
 obj-$(CONFIG_ISI) += isicom.o
 obj-$(CONFIG_ESPSERIAL) += esp.o
+obj-$(CONFIG_X86_REMOTE_DEBUG) += gdbserial.o
 obj-$(CONFIG_SYNCLINK) += synclink.o
 obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/char/gdbserial.c 200-kgdb/drivers/char/gdbserial.c
--- 141-no_vma_sort/drivers/char/gdbserial.c	Wed Dec 31 16:00:00 1969
+++ 200-kgdb/drivers/char/gdbserial.c	Sun Apr 20 21:28:58 2003
@@ -0,0 +1,274 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ *
+ * Modified by Scott Foehner (sfoehner@engr.sgi.com) to allow connect
+ * on boot-up
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.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/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/gdb.h>
+#include <linux/nmi.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#undef	PRNT			/* define for debug printing */
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+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;
+
+extern void set_debug_traps(void);	/* GDB routine */
+extern int gdb_serial_setup(int ttyS, int baud, int *port, int *irq);
+extern void shutdown_for_gdb(struct async_struct *info);
+						/* in serial.c */
+
+int gdb_irq;
+int gdb_port;
+int gdb_ttyS = 1;		/* Default: ttyS1 */
+int gdb_baud = 38400;
+int gdb_enter = 0;		/* Default: do not do gdb_hook on boot */
+int gdb_initialized = 0;
+
+static int initialized = -1;
+
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(void)
+{
+	if (inb(gdb_port + UART_LSR) & UART_LSR_DR)
+		return (inb(gdb_port + UART_RX));
+
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * 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 */
+
+}				/* read_char */
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(int chr)
+{
+	while (!(inb(gdb_port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb(chr, gdb_port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * 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;
+	int iir;
+
+	do {
+		chr = read_data_bfr();
+		iir = inb(gdb_port + UART_IIR);
+#ifdef PRNT
+		printk("gdb_interrupt: chr=%02x '%c'  after read iir=%02x\n",
+		       chr, chr > ' ' && chr < 0x7F ? chr : ' ', iir);
+#endif
+		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 */
+			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);
+
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+extern int serial8250_init(void);
+
+int
+gdb_hook(void)
+{
+	int retval;
+
+#ifdef CONFIG_SMP
+	if (NR_CPUS > KGDB_MAX_NO_CPUS) {
+		printk
+		    ("kgdb: too manu cpus. Cannot enable debugger with more than 8 cpus\n");
+		return (-1);
+	}
+#endif
+
+	/*
+	 * Call first time just to get the ser ptr
+	 */
+
+	serial8250_init();
+
+	if (gdb_serial_setup(gdb_ttyS, gdb_baud, &gdb_port, &gdb_irq)) {
+		printk("gdb_serial_setup() error");
+		return (-1);
+	}
+
+	retval = request_irq(gdb_irq,
+			     gdb_interrupt, SA_INTERRUPT, "GDB-stub", NULL);
+	if (retval == 0)
+		initialized = 1;
+	else {
+		initialized = 0;
+		printk("gdb_hook: request_irq(irq=%d) failed: %d\n", gdb_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);
+
+}				/* gdb_hook_interrupt2 */
+
+/*
+ * 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 PRNT
+	printk("getDebugChar: ");
+#endif
+
+	while ((chr = read_char()) < 0)
+		touch_nmi_watchdog();
+
+#ifdef PRNT
+	printk("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ');
+#endif
+	return (chr);
+
+}				/* getDebugChar */
+
+/*
+ * 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 PRNT
+	printk("putDebugChar: chr=%02x '%c'\n", chr,
+	       chr > ' ' && chr < 0x7F ? chr : ' ');
+#endif
+
+	write_char(chr);	/* this routine will wait */
+
+}				/* putDebugChar */
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/char/sysrq.c 200-kgdb/drivers/char/sysrq.c
--- 141-no_vma_sort/drivers/char/sysrq.c	Tue Feb 25 23:03:46 2003
+++ 200-kgdb/drivers/char/sysrq.c	Sun Apr 20 21:28:58 2003
@@ -107,6 +107,18 @@ static struct sysrq_key_op sysrq_reboot_
 	.action_msg	= "Resetting",
 };
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs,
+			struct tty_struct *tty) {
+	int gdb_hook(void);
+	gdb_hook();
+}
+static struct sysrq_key_op sysrq_gdb_op = {
+	handler:	sysrq_handle_gdb,
+	help_msg:	"Gdb",
+	action_msg:	"Entering debugger",
+};
+#endif
 
 
 /* SYNC SYSRQ HANDLERS BLOCK */
@@ -352,7 +364,11 @@ static struct sysrq_key_op *sysrq_key_ta
 /* d */	NULL,
 /* e */	&sysrq_term_op,
 /* f */	NULL,
+#ifdef CONFIG_X86_REMOTE_DEBUG
+/* g */	&sysrq_gdb_op,
+#else /* CONFIG_X86_REMOTE_DEBUG */
 /* g */	NULL,
+#endif /* CONFIG_X86_REMOTE_DEBUG */
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
 /* j */	NULL,
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/char/tty_io.c 200-kgdb/drivers/char/tty_io.c
--- 141-no_vma_sort/drivers/char/tty_io.c	Sun Apr 20 19:34:59 2003
+++ 200-kgdb/drivers/char/tty_io.c	Sun Apr 20 21:28:58 2003
@@ -91,6 +91,9 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/gdb.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -2252,6 +2255,9 @@ void __init console_init(void)
 		(*call)();
 		call++;
 	}
+#ifdef CONFIG_GDB_CONSOLE
+	gdb_console_init();
+#endif
 }
 
 static struct tty_driver dev_tty_driver, dev_syscons_driver;
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/serial/8250.c 200-kgdb/drivers/serial/8250.c
--- 141-no_vma_sort/drivers/serial/8250.c	Mon Mar 17 21:43:46 2003
+++ 200-kgdb/drivers/serial/8250.c	Sun Apr 20 21:28:58 2003
@@ -2119,9 +2119,116 @@ void serial8250_resume_port(int line, u3
 	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port, level);
 }
 
-static int __init serial8250_init(void)
+#ifdef CONFIG_X86_REMOTE_DEBUG
+/* 
+ *  Takes:
+ *	ttyS - integer specifying which serial port to use for debugging
+ *	baud - baud rate of specified serial port
+ *  Returns:
+ *	port for use by the gdb serial driver
+ */
+int gdb_serial_setup(int ttyS, int baud, int *port, int *irq)
+{
+        struct uart_8250_port *up;
+        unsigned cval;
+        int     bits = 8;
+        int     parity = 'n';
+        int     cflag = CREAD | HUPCL | CLOCAL;
+        int     quot = 0;
+
+        /*
+         *      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
+         */
+
+        up =  &serial8250_ports[ttyS];
+//	ser->flags &= ~ASYNC_BOOT_AUTOCONF;
+        quot = ( 1843200 / 16 ) / 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;
+        serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);       /* set DLAB */
+        serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
+        serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
+        serial_outp(up, UART_LCR, cval);                /* reset DLAB */
+        serial_outp(up, UART_IER, UART_IER_RDI);        /* turn on interrupts*/
+        serial_outp(up, UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
+
+        /*
+         *      If we read 0xff from the LSR, there is no UART here.
+         */
+        if (serial_inp(up, UART_LSR) == 0xff)
+                return 1;
+	*port = up->port.iobase;
+	*irq = up->port.irq;
+//	serial8250_shutdown(&up->port);
+        return 0;
+}
+#endif
+
+int serial8250_init(void)
 {
 	int ret, i;
+	static int didit = 0;
+
+	if (didit++)
+		return 0;
 
 	printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
 		"IRQ sharing %sabled\n", share_irqs ? "en" : "dis");
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/drivers/serial/core.c 200-kgdb/drivers/serial/core.c
--- 141-no_vma_sort/drivers/serial/core.c	Sun Apr 20 19:35:03 2003
+++ 200-kgdb/drivers/serial/core.c	Sun Apr 20 21:44:50 2003
@@ -33,6 +33,10 @@
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
@@ -1127,6 +1131,16 @@ uart_ioctl(struct tty_struct *tty, struc
 	 * protected against the tty being hung up.
 	 */
 	switch (cmd) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	case TIOCGDB:
+		ret = -ENOTTY;
+		if (capable(CAP_SYS_ADMIN)) {
+			gdb_ttyS = minor(tty->device) & 0x03F;
+			gdb_baud = tty_get_baud_rate(tty);
+			ret = gdb_hook();
+		}
+		break;
+#endif
 	case TIOCSERGETLSR: /* Get line status register */
 		ret = uart_get_lsr_info(state, (unsigned int *)arg);
 		break;
@@ -1143,6 +1157,30 @@ uart_ioctl(struct tty_struct *tty, struc
  out:
 	return ret;
 }
+
+ /*
+ * ------------------------------------------------------------
+ * Serial GDB driver (most in gdbserial.c)
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_GDB_CONSOLE
+static struct console gdbcons = {
+	name:		"gdb",
+	write:		gdb_console_write,
+	flags:		CON_PRINTBUFFER | CON_ENABLED,
+	index:		-1,
+};
+#endif
+
+#ifdef CONFIG_GDB_CONSOLE
+void __init gdb_console_init(void)
+{
+	register_console(&gdbcons);
+}
+#endif
+#endif /* CONFIG_X86_REMOTE_DEBUG */
 
 static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/include/asm-i386/bug.h 200-kgdb/include/asm-i386/bug.h
--- 141-no_vma_sort/include/asm-i386/bug.h	Mon Mar 17 21:43:48 2003
+++ 200-kgdb/include/asm-i386/bug.h	Sun Apr 20 21:28:58 2003
@@ -9,6 +9,11 @@
  * undefined" opcode for parsing in the trap handler.
  */
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#define BUG() do {                                            \
+	asm ("int $0x3");                                       \
+} while (0)
+#else
 #if 1	/* Set to zero for a slightly smaller kernel */
 #define BUG()				\
  __asm__ __volatile__(	"ud2\n"		\
@@ -17,6 +22,7 @@
 			 : : "i" (__LINE__), "i" (__FILE__))
 #else
 #define BUG() __asm__ __volatile__("ud2\n")
+#endif
 #endif
 
 #define PAGE_BUG(page) do { \
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/include/asm-i386/ioctls.h 200-kgdb/include/asm-i386/ioctls.h
--- 141-no_vma_sort/include/asm-i386/ioctls.h	Tue Apr  8 14:38:20 2003
+++ 200-kgdb/include/asm-i386/ioctls.h	Sun Apr 20 21:28:58 2003
@@ -68,6 +68,7 @@
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
 #define FIOQSIZE	0x5460
+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/include/asm-i386/processor.h 200-kgdb/include/asm-i386/processor.h
--- 141-no_vma_sort/include/asm-i386/processor.h	Sun Apr 20 21:09:40 2003
+++ 200-kgdb/include/asm-i386/processor.h	Sun Apr 20 21:28:58 2003
@@ -409,6 +409,9 @@ struct thread_struct {
 	unsigned int		saved_fs, saved_gs;
 /* IO permissions */
 	unsigned long	*ts_io_bitmap;
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	struct pt_regs *kgdbregs;
+#endif
 };
 
 #define INIT_THREAD  {							\
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/include/linux/gdb.h 200-kgdb/include/linux/gdb.h
--- 141-no_vma_sort/include/linux/gdb.h	Wed Dec 31 16:00:00 1969
+++ 200-kgdb/include/linux/gdb.h	Sun Apr 20 21:28:58 2003
@@ -0,0 +1,67 @@
+#ifndef _GDB_H_
+#define _GDB_H_
+
+/*
+ * Copyright (C) 2001 Amit S. Kale
+ */
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS NR_CPUS
+
+extern int gdb_enter;	/* 1 = enter debugger on boot */
+extern int gdb_ttyS;
+extern int gdb_baud;
+extern int gdb_initialized;
+
+extern int gdb_hook(void);
+extern void breakpoint(void);
+
+typedef int     gdb_debug_hook(int trapno,
+                               int signo,
+                               int err_code,
+                               struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+extern spinlock_t kgdb_nmispinlock;
+#else
+extern unsigned kgdb_spinlock;
+extern unsigned kgdb_nmispinlock;
+#endif
+
+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);
+
+extern volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#define KGDB_ASSERT(message, condition)	do {			\
+	if (!(condition)) {					\
+		printk("kgdb assertion failed: %s\n", message); \
+		asm ("int $0x3");				\
+	}							\
+} 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))
+
+#define KA_HELD_GKL()	(current->lock_depth >= 0)
+
+#endif /* _GDB_H_ */
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/include/linux/sched.h 200-kgdb/include/linux/sched.h
--- 141-no_vma_sort/include/linux/sched.h	Sun Apr 20 19:35:07 2003
+++ 200-kgdb/include/linux/sched.h	Sun Apr 20 21:28:58 2003
@@ -166,7 +166,9 @@ extern unsigned long cache_decay_ticks;
 
 #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_schedule(void);
+asmlinkage void kern_do_schedule(struct pt_regs);
 
 struct namespace;
 
@@ -685,6 +687,12 @@ static inline int thread_group_empty(tas
 		(thread_group_leader(p) && !thread_group_empty(p))
 
 extern void unhash_process(struct task_struct *p);
+
+#ifdef CONFIG_KGDB_THREAD
+#define schedule() kern_schedule()
+#else
+#define schedule() do_schedule()
+#endif
 
 /* Protects ->fs, ->files, ->mm, and synchronises with wait4().
  * Nests both inside and outside of read_lock(&tasklist_lock).
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/init/main.c 200-kgdb/init/main.c
--- 141-no_vma_sort/init/main.c	Sun Apr 20 21:09:39 2003
+++ 200-kgdb/init/main.c	Sun Apr 20 21:28:58 2003
@@ -55,6 +55,10 @@
 #include <asm/smp.h>
 #endif
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/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.
@@ -460,6 +464,12 @@ asmlinkage void __init start_kernel(void
 	 *	make syscalls (and thus be locked).
 	 */
 	init_idle(current, smp_processor_id());
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (gdb_enter) {
+		gdb_hook();		/* right at boot time */
+	}
+#endif
 
 	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/kernel/ksyms.c 200-kgdb/kernel/ksyms.c
--- 141-no_vma_sort/kernel/ksyms.c	Sun Apr 20 19:35:08 2003
+++ 200-kgdb/kernel/ksyms.c	Sun Apr 20 21:28:58 2003
@@ -465,7 +465,10 @@ EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
-EXPORT_SYMBOL(schedule);
+EXPORT_SYMBOL(do_schedule);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
 #ifdef CONFIG_PREEMPT
 EXPORT_SYMBOL(preempt_schedule);
 #endif
diff -urpN -X /home/fletch/.diff.exclude 141-no_vma_sort/kernel/sched.c 200-kgdb/kernel/sched.c
--- 141-no_vma_sort/kernel/sched.c	Sun Apr 20 21:16:42 2003
+++ 200-kgdb/kernel/sched.c	Sun Apr 20 21:28:58 2003
@@ -1392,7 +1392,7 @@ void scheduling_functions_start_here(voi
 /*
  * schedule() is the main scheduler function.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	task_t *prev, *next;
 	runqueue_t *rq;
@@ -1626,6 +1626,22 @@ void complete_all(struct completion *x)
 	__wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, 0);
 	spin_unlock_irqrestore(&x->wait.lock, flags);
 }
+
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.kgdbregs = NULL;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(struct pt_regs regs)
+{
+	current->thread.kgdbregs = &regs;
+	do_schedule();
+}
+#endif
 
 void wait_for_completion(struct completion *x)
 {