diff -Nru linux/CREDITS linux-2.4.19-pre5-mjc/CREDITS
--- linux/CREDITS	Sat Apr  6 15:26:31 2002
+++ linux-2.4.19-pre5-mjc/CREDITS	Sat Apr  6 16:07:14 2002
@@ -434,6 +434,7 @@
 E: lars@nocrew.org
 W: http://lars.nocrew.org/
 D: dsp56k device driver
+D: ptrace proxy in user mode kernel port
 S: Kopmansg 2
 S: 411 13  Goteborg
 S: Sweden
@@ -721,7 +722,7 @@
 E: jdike@karaya.com
 W: http://user-mode-linux.sourceforge.net
 D: User mode kernel port
-S: RR1 Box 67C
+S: 375 Tubbs Hill Rd
 S: Deering NH 03244
 S: USA
 
diff -Nru linux/Documentation/Configure.help linux-2.4.19-pre5-mjc/Documentation/Configure.help
--- linux/Documentation/Configure.help	Sat Apr  6 15:26:31 2002
+++ linux-2.4.19-pre5-mjc/Documentation/Configure.help	Sat Apr  6 16:07:15 2002
@@ -14054,7 +14054,7 @@
   Synchronous operation (i.e. always writing data to the host's disk
   immediately) is configurable on a per-UBD basis by using a special
   kernel command line option.  Alternatively, you can say Y here to
-  turn on synchronous operation by default for all block.
+  turn on synchronous operation by default for all block devices.
 
   If you're running a journalling file system (like reiserfs, for
   example) in your virtual machine, you will want to say Y here.  If
@@ -14066,6 +14066,7 @@
 CONFIG_PT_PROXY
   This option enables a debugging interface which allows gdb to debug
   the kernel without needing to actually attach to kernel threads.
+  CONFIG_XTERM_CHAN must be enabled in order to enable CONFIG_PT_PROXY.
   If you want to do kernel debugging, say Y here; otherwise say N.
 
 Management console
@@ -14260,25 +14261,115 @@
 
 SLIP transport
 CONFIG_UML_NET_SLIP
-  The Slip User-Mode Linux network transport allows a running UML to
+  The slip User-Mode Linux network transport allows a running UML to
   network with its host over a point-to-point link.  Unlike Ethertap,
   which can carry any Ethernet frame (and hence even non-IP packets),
-  the Slip transport can only carry IP packets.
+  the slip transport can only carry IP packets.
 
-  To use this, your host must support Slip devices.
+  To use this, your host must support slip devices.
 
   For more information, see
   <http://user-mode-linux.sourceforge.net/networking.html>.  That site
-  has examples of the UML command line to use to enable Slip
+  has examples of the UML command line to use to enable slip
   networking, and details of a few quirks with it.
 
-  The Ethertap Transport is preferred over Slip because of its
-  limitation.  If you prefer Slip, however, say Y here.  Otherwise
+  The Ethertap Transport is preferred over slip because of its
+  limitations.  If you prefer slip, however, say Y here.  Otherwise
   choose the Multicast transport (to network multiple UMLs on 
   multiple hosts), Ethertap (to network with the host and the
   outside world), and/or the Daemon transport (to network multiple
   UMLs on a single host).  You may choose more than one without
   conflict.  If you don't need UML networking, say N.
+
+Default main console channel initialization
+CONFIG_CON_ZERO_CHAN
+  This is the string describing the channel to which the main console
+  will be attached by default.  This value can be overridden from the
+  command line.  The default value is "fd:0,fd:1", which attaches the
+  main console to stdin and stdout.
+  It is safe to leave this unchanged.
+
+Default console channel initialization
+CONFIG_CON_CHAN
+  This is the string describing the channel to which all consoles
+  except the main console will be attached by default.  This value can
+  be overridden from the command line.  The default value is "xterm",
+  which brings them up in xterms.
+  It is safe to leave this unchanged, although you may wish to change
+  this if you expect the UML that you build to be run in environments
+  which don't have X or xterm available.
+
+Default serial line channel initialization
+CONFIG_SSL_CHAN
+  This is the string describing the channel to which the serial lines
+  will be attached by default.  This value can be overridden from the
+  command line.  The default value is "pty", which attaches them to
+  traditional pseudo-terminals.
+  It is safe to leave this unchanged, although you may wish to change
+  this if you expect the UML that you build to be run in environments
+  which don't have a set of /dev/pty* devices.
+
+UML sound support
+CONFIG_UML_SOUND
+  This option enables UML sound support.  If enabled, it will pull in
+  soundcore and the UML hostaudio relay, which acts as a intermediary
+  between the host's dsp and mixer devices and the UML sound system.
+  It is safe to say 'Y' here.
+
+UML SMP support
+CONFIG_UML_SMP
+  This option enables UML SMP support.  UML implements virtual SMP by
+  allowing as many processes to run simultaneously on the host as
+  there are virtual processors configured.  Obviously, if the host is
+  a uniprocessor, those processes will timeshare, but, inside UML,
+  will appear to be running simultaneously.  If the host is a
+  multiprocessor, then UML processes may run simultaneously, depending
+  on the host scheduler.
+  CONFIG_SMP will be set to whatever this option is set to.
+  It is safe to leave this unchanged.
+
+file descriptor channel support
+CONFIG_FD_CHAN
+  This option enables support for attaching UML consoles and serial
+  lines to already set up file descriptors.  Generally, the main
+  console is attached to file descriptors 0 and 1 (stdin and stdout),
+  so it would be wise to leave this enabled unless you intend to
+  attach it to some other host device.
+
+port channel support
+CONFIG_PORT_CHAN
+  This option enables support for attaching UML consoles and serial
+  lines to host portals.  They may be accessed with 'telnet <host>
+  <port number>'.  Any number of consoles and serial lines may be
+  attached to a single portal, although what UML device you get when
+  you telnet to that portal will be unpredictable.
+  It is safe to say 'Y' here.
+
+pty channel support
+CONFIG_PTY_CHAN
+  This option enables support for attaching UML consoles and serial
+  lines to host pseudo-terminals.  Access to both traditional
+  pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
+  with this option.  The assignment of UML devices to host devices
+  will be announced in the kernel message log.
+  It is safe to say 'Y' here.
+
+tty channel support
+CONFIG_TTY_CHAN
+  This option enables support for attaching UML consoles and serial
+  lines to host terminals.  Access to both virtual consoles
+  (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
+  /dev/pts/*) are controlled by this option.
+  It is safe to say 'Y' here.
+
+xterm channel support
+CONFIG_XTERM_CHAN
+  This option enables support for attaching UML consoles and serial
+  lines to xterms.  Each UML device so assigned will be brought up in
+  its own xterm.
+  If you disable this option, then CONFIG_PT_PROXY will be disabled as
+  well, since UML's gdb currently requires an xterm.
+  It is safe to say 'Y' here.
 
 Microtek USB scanner support
 CONFIG_USB_MICROTEK
diff -Nru linux/MAINTAINERS linux-2.4.19-pre5-mjc/MAINTAINERS
--- linux/MAINTAINERS	Sat Apr  6 15:26:31 2002
+++ linux-2.4.19-pre5-mjc/MAINTAINERS	Sat Apr  6 16:07:15 2002
@@ -1824,6 +1824,14 @@
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://usb.in.tum.de
 S:	Maintained
+
+USER-MODE PORT
+P:	Jeff Dike
+M:	jdike@karaya.com
+L:	user-mode-linux-devel@lists.sourceforge.net
+L:	user-mode-linux-user@lists.sourceforge.net
+W:	http://user-mode-linux.sourceforge.net
+S:	Maintained
 	
 USB "USBNET" DRIVER
 P:	David Brownell
diff -Nru linux/Makefile linux-2.4.19-pre5-mjc/Makefile
--- linux/Makefile	Sat Apr  6 15:26:31 2002
+++ linux-2.4.19-pre5-mjc/Makefile	Sat Apr  6 16:16:00 2002
@@ -5,7 +5,15 @@
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+# SUBARCH tells the usermode build what the underlying arch is.  That is set
+# first, and if a usermode build is happening, the "ARCH=um" on the command
+# line overrides the setting of ARCH below.  If a native build is happening,
+# then ARCH is assigned, getting whatever value it gets normally, and 
+# SUBARCH is subsequently ignored.
+
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+ARCH := $(SUBARCH)
+
 KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
diff -Nru linux/arch/um/Makefile linux-2.4.19-pre5-mjc/arch/um/Makefile
--- linux/arch/um/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,121 @@
+ARCH_DIR = arch/um
+
+include arch/$(ARCH)/Makefile-$(SUBARCH)
+
+EXTRAVERSION := $(EXTRAVERSION)-13um
+include/linux/version.h: arch/$(ARCH)/Makefile
+
+# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE)
+# The way the toplevel Makefile is written EXTRAVERSION is not supposed
+# to be changed outside the toplevel Makefile, but recalculating MODLIB is
+# a sufficient workaround until we no longer need architecture dependent
+# EXTRAVERSION...
+MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+
+MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot
+
+ifeq ($(CONFIG_DEBUGSYM),y)
+DEBUG = -g
+CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
+endif
+
+ifeq ($(CONFIG_GCOV),y)
+CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+ifeq ($(CONFIG_GPROF), y)
+PROFILE += -pg -DPROFILING
+LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
+endif
+
+SUBDIRS += $(ARCH_DIR)/fs $(ARCH_DIR)/drivers \
+	$(ARCH_DIR)/kernel $(ARCH_DIR)/sys-$(SUBARCH)
+
+LIBS += $(shell [ -e $(ARCH_DIR)/fs/fs.o ] && echo $(ARCH_DIR)/fs/fs.o) \
+	$(ARCH_DIR)/kernel/um.o $(ARCH_DIR)/drivers/um_drivers.o \
+	$(ARCH_DIR)/sys-$(SUBARCH)/sys.o 
+
+ifeq ($(CONFIG_PT_PROXY), y)
+SUBDIRS += $(ARCH_DIR)/ptproxy
+LIBS += $(ARCH_DIR)/ptproxy/ptproxy.a
+endif
+
+NESTING = 0
+
+ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
+
+# -Derrno=kernel_errno - This turns all kernel references to errno into
+# kernel_errno to separate them from the libc errno.  This allows -fno-common
+# in CFLAGS.  Otherwise, it would cause ld to complain about the two different
+# errnos.
+
+CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \
+	-DSUBARCH=\"$(SUBARCH)\" -DNESTING=$(NESTING) -D_LARGEFILE64_SOURCE \
+	-I$(ARCH_INCLUDE) -Derrno=kernel_errno
+
+LINKFLAGS += -r
+
+LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
+
+$(ARCH_DIR)/link.ld: $(ARCH_DIR)/link.ld.in
+	m4 -DSTART=$(START_ADDR) -DSUBARCH=$(SUBARCH) \
+		-DELF_SUBARCH=$(ELF_SUBARCH) $< > $@
+
+SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
+	include/asm-um/sigcontext.h include/asm-um/processor.h \
+	include/asm-um/ptrace.h include/asm-um/arch-signal.h
+
+ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep $(SYMLINK_HEADERS)
+
+GEN_HEADERS = $(ARCH_DIR)/include/task.h
+
+linux: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) $(ARCH_DIR)/main.o \
+	vmlinux $(ARCH_DIR)/link.ld
+	mv vmlinux vmlinux.o
+	$(CC) -Wl,-T,$(ARCH_DIR)/link.ld $(LINK_PROFILE) $(LINK_WRAPS) \
+		-o linux -static $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib -lutil
+
+USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
+USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
+
+# To get a definition of F_SETSIG
+USER_CFLAGS += -D_GNU_SOURCE
+
+$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+archmrproper:
+	$(MAKE) -C $(ARCH_DIR)/sys-$(SUBARCH) archmrproper
+	rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
+		$(ARCH_DIR)/link.ld \
+		$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
+
+archclean: sysclean
+	$(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util clean
+	find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
+		-o -name '*.gcov' \) -type f -print | xargs rm -f
+	rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
+	@$(MAKEBOOT) clean
+
+archdep: 
+	@$(MAKEBOOT) dep
+
+$(SYMLINK_HEADERS):
+	cd $(TOPDIR)/$(dir $@) ; \
+	ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
+
+include/asm-um/arch:
+	cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
+
+arch/um/include/sysdep:
+	cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
+
+$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
+	$< > $@
+
+$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
+	$(ARCH_DIR)/util/mk_task_kern.c 
+	$(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util all
+
+export SUBARCH USER_CFLAGS
diff -Nru linux/arch/um/Makefile-i386 linux-2.4.19-pre5-mjc/arch/um/Makefile-i386
--- linux/arch/um/Makefile-i386	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/Makefile-i386	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,20 @@
+ifeq ($(CONFIG_HOST_2G_2G), y)
+START_ADDR = 0x60000000
+else
+START_ADDR = 0xa0000000
+endif
+
+ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) -DUM_FASTCALL
+ELF_SUBARCH = $(SUBARCH)
+
+SYS_HEADERS = $(ARCH_DIR)/include/sysdep-i386/sc.h
+
+$(ARCH_DIR)/include/sysdep-i386/sc.h : $(ARCH_DIR)/sys-i386/util/mk_sc
+	$(ARCH_DIR)/sys-i386/util/mk_sc > $@
+
+$(ARCH_DIR)/sys-i386/util/mk_sc : $(ARCH_DIR)/sys-i386/util/mk_sc.c
+	$(MAKE) -C $(ARCH_DIR)/sys-i386/util all
+
+sysclean :
+	rm -f $(SYS_HEADERS)
+	make -C $(ARCH_DIR)/sys-i386/util clean
diff -Nru linux/arch/um/Makefile-ia64 linux-2.4.19-pre5-mjc/arch/um/Makefile-ia64
--- linux/arch/um/Makefile-ia64	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/Makefile-ia64	Sat Apr  6 16:07:15 2002
@@ -0,0 +1 @@
+START_ADDR = 0x1000000000000000
diff -Nru linux/arch/um/Makefile-ppc linux-2.4.19-pre5-mjc/arch/um/Makefile-ppc
--- linux/arch/um/Makefile-ppc	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/Makefile-ppc	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,9 @@
+ifeq ($(CONFIG_HOST_2G_2G), y)
+START_ADDR = 0x60000000
+else
+START_ADDR = 0xa0000000
+endif
+ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
+
+# The arch is ppc, but the elf32 name is powerpc
+ELF_SUBARCH = powerpc
diff -Nru linux/arch/um/boot/Makefile linux-2.4.19-pre5-mjc/arch/um/boot/Makefile
--- linux/arch/um/boot/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/boot/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,3 @@
+dep:
+
+clean:
diff -Nru linux/arch/um/config.in linux-2.4.19-pre5-mjc/arch/um/config.in
--- linux/arch/um/config.in	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/config.in	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,123 @@
+define_bool CONFIG_USERMODE y
+
+mainmenu_name "Linux/Usermode Kernel Configuration"
+
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
+define_bool CONFIG_PCI n
+
+define_bool CONFIG_UID16 y
+
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'General Setup'
+define_bool CONFIG_STDIO_CONSOLE y
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+bool 'Virtual serial line' CONFIG_SSL
+tristate 'Host filesystem' CONFIG_HOSTFS
+bool 'Management console' CONFIG_MCONSOLE
+dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
+bool '2G/2G host address space split' CONFIG_HOST_2G_2G
+bool 'Symmetric multi-processing support' CONFIG_UML_SMP
+define_bool CONFIG_SMP $CONFIG_UML_SMP
+string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \
+	"fd:0,fd:1"
+string 'Default console channel initialization' CONFIG_CON_CHAN "xterm"
+string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty"
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+# MODVERSIONS does not yet work in this architecture
+#   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+    bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Devices'
+define_bool CONFIG_BLK_DEV_UBD y
+bool 'Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+	int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+fi
+dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
+tristate 'Example IO memory driver' CONFIG_MMAPPER
+
+tristate 'Sound support' CONFIG_UML_SOUND
+define_tristate CONFIG_SOUND $CONFIG_UML_SOUND
+define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND
+
+bool 'file descriptor channel support' CONFIG_FD_CHAN
+bool 'null channel support' CONFIG_NULL_CHAN
+bool 'port channel support' CONFIG_PORT_CHAN
+bool 'pty channel support' CONFIG_PTY_CHAN
+bool 'tty channel support' CONFIG_TTY_CHAN
+bool 'xterm channel support' CONFIG_XTERM_CHAN
+
+endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+fi
+
+if [ "$CONFIG_NET" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Network device support'
+
+   bool 'Virtual network device support' CONFIG_UML_NET
+   if [ "$CONFIG_UML_NET" != "n" ]; then
+      bool '    Ethertap transport' CONFIG_UML_NET_ETHERTAP
+      bool '    TUN/TAP transport' CONFIG_UML_NET_TUNTAP
+      bool '    SLIP transport' CONFIG_UML_NET_SLIP
+      bool '    Daemon transport' CONFIG_UML_NET_DAEMON
+      bool '    Multicast transport' CONFIG_UML_NET_MCAST
+   fi
+
+   bool 'Software network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+   fi
+
+   endmenu
+fi
+
+source fs/Config.in
+
+source drivers/md/Config.in
+
+source drivers/mtd/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
+bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM
+if [ "$CONFIG_XTERM_CHAN" = "y" ]; then
+   dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM
+else 
+   define_bool CONFIG_PT_PROXY n
+fi
+dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM
+dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM
+endmenu
diff -Nru linux/arch/um/config.release linux-2.4.19-pre5-mjc/arch/um/config.release
--- linux/arch/um/config.release	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/config.release	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,331 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_USERMODE=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General Setup
+#
+CONFIG_STDIO_CONSOLE=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_SSL=y
+CONFIG_HOSTFS=y
+CONFIG_MCONSOLE=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_HOST_2G_2G is not set
+# CONFIG_UML_SMP is not set
+# CONFIG_SMP is not set
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CON_CHAN="xterm"
+CONFIG_SSL_CHAN="pty"
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_KMOD=y
+
+#
+# Devices
+#
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_MMAPPER is not set
+CONFIG_UML_SOUND=y
+CONFIG_SOUND=y
+CONFIG_HOSTAUDIO=y
+CONFIG_FD_CHAN=y
+CONFIG_PORT_CHAN=y
+CONFIG_PTY_CHAN=y
+CONFIG_TTY_CHAN=y
+CONFIG_XTERM_CHAN=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_UML_NET=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_TUNTAP=y
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_MCAST=y
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=y
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_BFS_FS=m
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_UMSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_EFS_FS=m
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=m
+CONFIG_TMPFS=y
+CONFIG_RAMFS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_MINIX_FS=m
+CONFIG_VXFS_FS=m
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+CONFIG_HPFS_FS=m
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+CONFIG_SYSV_FS=m
+CONFIG_UDF_FS=m
+# CONFIG_UDF_RW is not set
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUGSYM is not set
+# CONFIG_PT_PROXY is not set
+# CONFIG_GPROF is not set
+# CONFIG_GCOV is not set
diff -Nru linux/arch/um/defconfig linux-2.4.19-pre5-mjc/arch/um/defconfig
--- linux/arch/um/defconfig	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/defconfig	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,386 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_USERMODE=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General Setup
+#
+CONFIG_STDIO_CONSOLE=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_SSL=y
+CONFIG_HOSTFS=m
+CONFIG_MCONSOLE=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_HOST_2G_2G is not set
+# CONFIG_UML_SMP is not set
+# CONFIG_SMP is not set
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CON_CHAN="xterm"
+CONFIG_SSL_CHAN="pty"
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_KMOD is not set
+
+#
+# Devices
+#
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_MMAPPER is not set
+CONFIG_UML_SOUND=y
+CONFIG_SOUND=y
+CONFIG_HOSTAUDIO=y
+CONFIG_FD_CHAN=y
+CONFIG_NULL_CHAN=y
+CONFIG_PORT_CHAN=y
+CONFIG_PTY_CHAN=y
+CONFIG_TTY_CHAN=y
+CONFIG_XTERM_CHAN=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_UML_NET=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_TUNTAP=y
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_MCAST=y
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+CONFIG_ETHERTAP=y
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_GEN_PROBE is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUGSYM=y
+CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
+# CONFIG_GCOV is not set
diff -Nru linux/arch/um/drivers/Makefile linux-2.4.19-pre5-mjc/arch/um/drivers/Makefile
--- linux/arch/um/drivers/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,50 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+OBJ := um_drivers.o
+
+CHAN_OBJS = chan_kern.o chan_user.o line.o 
+
+OBJS-y = 
+OBJS-$(CONFIG_SSL) += ssl.o 
+OBJS-$(CONFIG_UML_NET_SLIP) += slip_kern.o slip_user.o
+OBJS-$(CONFIG_UML_NET_ETHERTAP) += ethertap_kern.o ethertap_user.o 
+OBJS-$(CONFIG_UML_NET_TUNTAP) += tuntap_kern.o tuntap_user.o
+OBJS-$(CONFIG_UML_NET_DAEMON) += daemon_kern.o daemon_user.o 
+OBJS-$(CONFIG_UML_NET_MCAST) += mcast_user.o mcast_kern.o 
+OBJS-$(CONFIG_UML_NET) += net_kern.o net_user.o 
+OBJS-$(CONFIG_MCONSOLE) += mconsole_kern.o mconsole_user.o
+OBJS-$(CONFIG_MMAPPER) += mmapper_kern.o 
+OBJS-$(CONFIG_BLK_DEV_UBD) += ubd.o ubd_user.o 
+OBJS-$(CONFIG_HOSTAUDIO) += hostaudio_kern.o hostaudio_user.o
+OBJS-$(CONFIG_FD_CHAN) += fd.o 
+OBJS-$(CONFIG_NULL_CHAN) += null.o 
+OBJS-$(CONFIG_PORT_CHAN) += port.o port_kern.o
+OBJS-$(CONFIG_PTY_CHAN) += pty.o
+OBJS-$(CONFIG_TTY_CHAN) += tty.o 
+OBJS-$(CONFIG_XTERM_CHAN) += xterm.o 
+
+OBJS = stdio_console.o $(OBJS-y) $(CHAN_OBJS)
+
+USER_OBJS = $(filter %_user.o,$(OBJS)) fd.o null.o port.o pty.o socket.o \
+	tty.o xterm.o
+
+all : $(OBJ)
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+$(OBJ): $(OBJS) $(export-objs)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+
+clean:
+	rm -f $(OBJS) $(export-objs)
+
+modules:
+
+fastdep:
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/drivers/chan_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/chan_kern.c
--- linux/arch/um/drivers/chan_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/chan_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,446 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/irq.h>
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "sigio.h"
+
+static void *not_configged_init(char *str, int device, struct chan_opts *opts)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(NULL);
+}
+
+static int not_configged_open(int input, int output, int primary, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-ENODEV);
+}
+
+static void not_configged_close(int fd, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+}
+
+static int not_configged_read(int fd, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_write(int fd, const char *buf, int len, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_console_write(int fd, const char *buf, int len,
+				       void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_window_size(int fd, void *data, unsigned short *rows,
+				     unsigned short *cols)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-ENODEV);
+}
+
+static void not_configged_free(void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+}
+
+static struct chan_ops not_configged_ops = {
+	init:		not_configged_init,
+	open:		not_configged_open,
+	close:		not_configged_close,
+	read:		not_configged_read,
+	write:		not_configged_write,
+	console_write:	not_configged_console_write,
+	window_size:	not_configged_window_size,
+	free:		not_configged_free,
+	winch:		0,
+};
+
+static void tty_receive_char(struct tty_struct *tty, char ch)
+{
+	if(tty == NULL) return;
+
+	if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
+		if(ch == STOP_CHAR(tty)){
+			stop_tty(tty);
+			return;
+		}
+		else if(ch == START_CHAR(tty)){
+			start_tty(tty);
+			return;
+		}
+	}
+
+	if((tty->flip.flag_buf_ptr == NULL) || 
+	   (tty->flip.char_buf_ptr == NULL))
+		return;
+	tty_insert_flip_char(tty, ch, TTY_NORMAL);
+}
+
+static int open_one_chan(struct chan *chan, int input, int output, int primary)
+{
+	int fd;
+
+	if(chan->opened) return(0);
+	fd = (*chan->ops->open)(input, output, primary, chan->data);
+	if(fd < 0) return(fd);
+	chan->fd = fd;
+
+	chan->opened = 1;
+	return(0);
+}
+
+int open_chan(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int ret, err = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		ret = open_one_chan(chan, chan->input, chan->output,
+				    chan->primary);
+		if(chan->primary) err = ret;
+	}
+	return(err);
+}
+
+void chan_enable_winch(struct list_head *chans, void *line)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary && chan->output && chan->ops->winch){
+			register_winch(chan->fd, line);
+			return;
+		}
+	}
+}
+
+void enable_chan(struct list_head *chans, 
+		 int (*irq_setup)(int fd, int input, int output, void *data), 
+		 void *data)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->opened) continue;
+
+		(*irq_setup)(chan->fd, chan->input, chan->output, data);
+	}
+}
+
+void disable_chan(struct list_head *chans, int irq, void *dev)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->opened) continue;
+
+		free_irq(irq, dev);
+	}
+}
+
+void close_chan(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	/* Close in reverse order as open in case more than one of them
+	 * refers to the same device and they save and restore that device's
+	 * state.  Then, the first one opened will have the original state,
+	 * so it must be the last closed.
+	 */
+        for(ele = chans->prev; ele != chans; ele = ele->prev){
+                chan = list_entry(ele, struct chan, list);
+		if(chan->ops->close != NULL)
+			(*chan->ops->close)(chan->fd, chan->data);
+		free_irq_by_fd(chan->fd);
+		chan->opened = 0;
+	}
+}
+
+int write_chan(struct list_head *chans, const char *buf, int len, 
+	       int write_irq)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int n, ret = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->output) continue;
+		n = chan->ops->write(chan->fd, buf, len, chan->data);
+		if(chan->primary){
+			ret = n;
+			if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
+				reactivate_fd(chan->fd, write_irq);
+				if(ret == -EAGAIN) ret = 0;
+			}
+		}
+	}
+	return(ret);
+}
+
+int console_write_chan(struct list_head *chans, const char *buf, int len)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int n, ret = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->output) continue;
+		n = chan->ops->console_write(chan->fd, buf, len, chan->data);
+		if(chan->primary) ret = n;
+	}
+	return(ret);
+}
+
+int chan_window_size(struct list_head *chans, unsigned short *rows_out,
+		      unsigned short *cols_out)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary){
+			if(chan->ops->window_size == NULL) return(0);
+			return(chan->ops->window_size(chan->fd, chan->data,
+						      rows_out, cols_out));
+		}
+	}
+	return(0);
+}
+
+void free_one_chan(struct chan *chan)
+{
+	list_del(&chan->list);
+	(*chan->ops->free)(chan->data);
+	free_irq_by_fd(chan->fd);
+	if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
+	kfree(chan);
+}
+
+void free_chan(struct list_head *chans)
+{
+	struct list_head *ele, *next;
+	struct chan *chan;
+
+	list_for_each_safe(ele, next, chans){
+		chan = list_entry(ele, struct chan, list);
+		free_one_chan(chan);
+	}
+}
+
+struct chan_type {
+	char *key;
+	struct chan_ops *ops;
+};
+
+struct chan_type chan_table[] = {
+#ifdef CONFIG_FD_CHAN
+	{ "fd", &fd_ops },
+#else
+	{ "fd", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_NULL_CHAN
+	{ "null", &null_ops },
+#else
+	{ "null", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_PORT_CHAN
+	{ "port", &port_ops },
+#else
+	{ "port", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_PTY_CHAN
+	{ "pty", &pty_ops },
+	{ "pts", &pts_ops },
+#else
+	{ "pty", &not_configged_ops },
+	{ "pts", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_TTY_CHAN
+	{ "tty", &tty_ops },
+#else
+	{ "tty", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_XTERM_CHAN
+	{ "xterm", &xterm_ops },
+#else
+	{ "xterm", &not_configged_ops },
+#endif
+};
+
+static struct chan *parse_chan(char *str, int pri, int device, 
+			       struct chan_opts *opts)
+{
+	struct chan_type *entry;
+	struct chan_ops *ops;
+	struct chan *chan;
+	void *data;
+	int i;
+
+	ops = NULL;
+	data = NULL;
+	for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
+		entry = &chan_table[i];
+		if(!strncmp(str, entry->key, strlen(entry->key))){
+			ops = entry->ops;
+			str += strlen(entry->key);
+			break;
+		}
+	}
+	if(ops == NULL){
+		printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", 
+		       str);
+		return(NULL);
+	}
+	data = (*ops->init)(str, device, opts);
+	if(data == NULL) return(NULL);
+
+	chan = kmalloc(sizeof(*chan), GFP_KERNEL);
+	if(chan == NULL) return(NULL);
+	*chan = ((struct chan) { list :	 	LIST_HEAD_INIT(chan->list),
+				 primary :	1,
+				 input :	0,
+				 output :	0,
+				 opened : 	0,
+				 fd :		-1,
+				 pri :		pri,
+				 ops :		ops,
+				 data :		data });
+	return(chan);
+}
+
+int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
+		    struct chan_opts *opts)
+{
+	struct chan *new, *chan;
+	char *in, *out;
+
+	if(!list_empty(chans)){
+		chan = list_entry(chans->next, struct chan, list);
+		if(chan->pri >= pri) return(0);
+		free_chan(chans);
+		INIT_LIST_HEAD(chans);
+	}
+
+	if((out = strchr(str, ',')) != NULL){
+		in = str;
+		*out = '\0';
+		out++;
+		new = parse_chan(in, pri, device, opts);
+		if(new == NULL) return(-1);
+		new->input = 1;
+		list_add(&new->list, chans);
+
+		new = parse_chan(out, pri, device, opts);
+		if(new == NULL) return(-1);
+		list_add(&new->list, chans);
+		new->output = 1;
+	}
+	else {
+		new = parse_chan(str, pri, device, opts);
+		if(new == NULL) return(-1);
+		list_add(&new->list, chans);
+		new->input = 1;
+		new->output = 1;
+	}
+	return(0);
+}
+
+int chan_out_fd(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary && chan->output)
+			return(chan->fd);
+	}
+	return(-1);
+}
+
+void chan_interrupt(struct list_head *chans, struct tty_struct *tty, int irq)
+{
+	struct list_head *ele, *next;
+	struct chan *chan;
+	char c;
+
+	list_for_each_safe(ele, next, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->input) continue;
+		do {
+			c = chan->ops->read(chan->fd, chan->data);
+			if(c > 0) tty_receive_char(tty, c);
+		} while(c > 0);
+		if(c == 0) reactivate_fd(chan->fd, irq);
+		if(c == -EIO){
+			if(chan->primary){
+				if(tty != NULL) tty_hangup(tty);
+				close_chan(chans);
+				free_chan(chans);
+				return;
+			}
+			else {
+				chan->ops->close(chan->fd, chan->data);
+				free_one_chan(chan);
+			}
+		}
+	}
+	if(tty) tty_flip_buffer_push(tty);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/chan_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/chan_user.c
--- linux/arch/um/drivers/chan_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/chan_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,259 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include "kern_util.h"
+#include "user_util.h"
+#include "chan_user.h"
+#include "user.h"
+
+void generic_close(int fd, void *unused)
+{
+	close(fd);
+}
+
+int generic_read(int fd, void *unused)
+{
+	int n;
+	char c;
+
+	n = read(fd, &c, sizeof(c));
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-EIO);
+	return(c);
+}
+
+int generic_write(int fd, const char *buf, int n, void *unused)
+{
+	int count;
+
+	count = write(fd, buf, n);
+	if(count < 0) return(-errno);
+	return(count);
+}
+
+int generic_console_write(int fd, const char *buf, int n, void *state)
+{
+	struct termios save, *orig = state;
+	int err;
+
+	if(isatty(fd)){
+		tcgetattr(fd, &save);
+		tcsetattr(fd, TCSADRAIN, orig);
+	}
+	err = generic_write(fd, buf, n, NULL);
+	if(isatty(fd)) tcsetattr(fd, TCSADRAIN, &save);
+	return(err);
+}
+
+int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+			unsigned short *cols_out)
+{
+	struct winsize size;
+	int ret = 0;
+
+	if(ioctl(fd, TIOCGWINSZ, &size) == 0){
+		ret = ((*rows_out != size.ws_row) || 
+		       (*cols_out != size.ws_col));
+		*rows_out = size.ws_row;
+		*cols_out = size.ws_col;
+	}
+	return(ret);
+}
+
+void generic_free(void *data)
+{
+	kfree(data);
+}
+
+int getmaster(char *line)
+{
+	struct stat stb;
+	char *pty, *bank, *cp;
+	int master;
+
+	pty = &line[strlen("/dev/ptyp")];
+	for (bank = "pqrs"; *bank; bank++) {
+		line[strlen("/dev/pty")] = *bank;
+		*pty = '0';
+		if (stat(line, &stb) < 0)
+			break;
+		for (cp = "0123456789abcdef"; *cp; cp++) {
+			*pty = *cp;
+			master = open(line, O_RDWR);
+			if (master >= 0) {
+				char *tp = &line[strlen("/dev/")];
+				int ok;
+
+				/* verify slave side is usable */
+				*tp = 't';
+				ok = access(line, R_OK|W_OK) == 0;
+				*tp = 'p';
+				if (ok) return(master);
+				(void) close(master);
+			}
+		}
+	}
+	return(-1);
+}
+
+static void winch_handler(int sig)
+{
+}
+
+static int winch_thread(int pty_fd, int pipe_fd)
+{
+	sigset_t sigs;
+	char c = 1;
+
+	if(write(pipe_fd, &c, sizeof(c)) != sizeof(c))
+		printk("winch_thread : failed to write synchronization "
+		       "byte\n");
+
+	signal(SIGWINCH, winch_handler);
+	sigfillset(&sigs);
+	sigdelset(&sigs, SIGWINCH);
+	if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
+		printk("winch_thread : sigprocmask failed, errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	if(setsid() < 0){
+		printk("winch_thread : setsid failed, errno = %d\n", errno);
+		exit(1);
+	}
+
+	if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){
+		printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if(tcsetpgrp(pty_fd, getpid()) < 0){
+		printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
+		exit(1);
+	}
+
+	if(read(pipe_fd, &c, sizeof(c)) != sizeof(c))
+		printk("winch_thread : failed to read synchronization byte\n");
+
+	while(1){
+		pause();
+
+		if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){
+			printk("winch_thread : write failed, errno = %d\n",
+			       errno);
+		}
+	}
+}
+
+static int tracer_winch[2];
+
+static void tracer_winch_handler(int sig)
+{
+	char c = 1;
+
+	if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
+		printk("tracer_winch_handler - write failed, errno = %d\n",
+		       errno);
+}
+
+void setup_tracer_winch(void)
+{
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, tracer_winch) < 0){
+		printk("setup_tracer_winch : socketpair failed, errno = %d\n", 
+		       errno);
+		return;
+	}
+	signal(SIGWINCH, tracer_winch_handler);
+}
+
+struct winch_data {
+	int fd;
+	void *device_data;
+	int fd_out;
+	int pid_out;
+};
+
+static void winch_tramp(void *arg)
+{
+	struct winch_data *data = arg;
+	int fds[2], pid, n;
+	char c;
+
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0){
+		printk("winch_tramp : socketpair failed, errno = %d\n", errno);
+		return;
+	}
+	pid = fork();
+	if(pid == 0){
+		close(fds[0]);
+		winch_thread(data->fd, fds[1]);
+	}
+	else if(pid < 0){
+		printk("fork of winch_thread failed - errno = %d\n", errno);
+		return;
+	}
+	close(fds[1]);
+	data->fd_out = fds[0];
+	data->pid_out = pid;
+	n = read(fds[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("winch_tramp : failed to read synchronization byte\n");
+		printk("read returned %d, errno = %d\n", n, errno);
+		printk("fd %d will not support SIGWINCH\n", data->fd);
+		data->fd_out = -1;
+	}
+}
+
+void register_winch(int fd, void *device_data)
+{
+	struct winch_data data;
+	int pid;
+	char c = 1;
+
+	if(!isatty(fd)) return;
+	data = ((struct winch_data) { fd :		fd,
+				      device_data : 	device_data,
+				      fd_out :		-1,
+				      pid_out :		-1 });
+
+	pid = tcgetpgrp(fd);
+	if(pid == tracing_pid)
+		register_winch_irq(tracer_winch[0], fd, -1, device_data);
+	else if(pid == -1){
+		tracing_cb(winch_tramp, &data);
+		if(data.fd_out != -1){
+			register_winch_irq(data.fd_out, fd, data.pid_out, 
+					   data.device_data);
+
+			if(write(data.fd_out, &c, sizeof(c)) != sizeof(c))
+				printk("register_winch : failed to write "
+				       "synchronization byte\n");
+		}
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/daemon.h linux-2.4.19-pre5-mjc/arch/um/drivers/daemon.h
--- linux/arch/um/drivers/daemon.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/daemon.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,36 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct daemon_data {
+	char *sock_type;
+	char *ctl_sock;
+	void *ctl_addr;
+	void *data_addr;
+	void *local_addr;
+	unsigned char hwaddr[ETH_ADDR_LEN];
+	int hw_setup;
+	int control;
+	void *dev;
+};
+
+extern struct net_user_info daemon_user_info;
+
+extern int daemon_user_set_mac(struct daemon_data *pri, unsigned char *hwaddr,
+			       int len);
+extern int daemon_user_write(int fd, void *buf, int len, 
+			     struct daemon_data *pri);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/daemon_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_kern.c
--- linux/arch/um/drivers/daemon_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/kernel.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "daemon.h"
+#include "daemon_kern.h"
+
+struct daemon_data daemon_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		sock_type:	"unix",
+		ctl_sock:	"/tmp/uml.ctl",
+		hwaddr:		{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+		hw_setup:	0,
+		control:	-1,
+	}
+};
+
+struct net_device *daemon_init(int private_size, int index)
+{
+	struct net_device *dev;
+	struct uml_net_private *pri;
+	struct daemon_data *dpri;
+
+	dev = init_etherdev(NULL, private_size);
+	if(dev == NULL) return(NULL);
+	pri = dev->priv;
+	dpri = (struct daemon_data *) pri->user;
+	*dpri = daemon_priv[index];
+	memcpy(dev->dev_addr, dpri->hwaddr, ETH_ALEN);
+	printk("daemon backend");
+	if(dpri->hw_setup)
+		printk("- ethernet address = %x:%x:%x:%x:%x:%x\n",
+		       dpri->hwaddr[0], dpri->hwaddr[1], dpri->hwaddr[2], 
+		       dpri->hwaddr[3], dpri->hwaddr[4], dpri->hwaddr[5]);
+	printk("\n");
+	return(dev);
+}
+
+static unsigned short daemon_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int daemon_set_mac(struct sockaddr *addr, void *data)
+{
+	struct daemon_data *pri = data;
+	struct net_device *dev = pri->dev;
+	struct sockaddr *hwaddr = addr;
+
+	memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
+	return(daemon_user_set_mac(pri, hwaddr->sa_data, ETH_ALEN));
+}
+
+static int daemon_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_recvfrom(fd, (*skb)->mac.raw, 
+			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int daemon_write(int fd, struct sk_buff **skb,
+			struct uml_net_private *lp)
+{
+	return(daemon_user_write(fd, (*skb)->data, (*skb)->len, 
+				 (struct daemon_data *) &lp->user));
+}
+
+static struct net_kern_info daemon_kern_info = {
+	init:			daemon_init,
+	protocol:		daemon_protocol,
+	set_mac:		daemon_set_mac,
+	read:			daemon_read,
+	write:			daemon_write,
+};
+
+static int daemon_count = 0;
+
+void daemon_setup(char *str, struct uml_net *dev)
+{
+	int err, n = daemon_count;
+
+	dev->user = &daemon_user_info;
+	dev->kern = &daemon_kern_info;
+	dev->private_size = sizeof(struct daemon_data);
+	dev->transport_index = daemon_count++;
+	if(*str != ',') return;
+	str++;
+	if(*str != ','){
+		err = setup_etheraddr(str, daemon_priv[n].hwaddr);
+		if(!err) daemon_priv[n].hw_setup = 1;
+	}
+	str = strchr(str, ',');
+	if(str == NULL) return;
+	*str++ = '\0';
+	if(*str != ',') daemon_priv[n].sock_type = str;
+	str = strchr(str, ',');
+	if(str == NULL) return;
+	*str++ = '\0';
+	if(*str != ',') daemon_priv[n].ctl_sock = str;
+	str = strchr(str, ',');
+	if(str == NULL) return;
+	*str = '\0';
+	printk(KERN_WARNING "daemon_setup : Ignoring data socket "
+	       "specification\n");
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/daemon_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_kern.h
--- linux/arch/um/drivers/daemon_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_DAEMON_KERN_H
+#define __UM_DAEMON_KERN_H
+
+#include "net_kern.h"
+
+extern void daemon_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru linux/arch/um/drivers/daemon_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_user.c
--- linux/arch/um/drivers/daemon_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/daemon_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include "net_user.h"
+#include "daemon.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "user.h"
+
+#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+enum request_type { REQ_NEW_CONTROL };
+
+#define SWITCH_MAGIC 0xfeedface
+
+struct request_v1 {
+  unsigned long magic;
+  enum request_type type;
+  union {
+    struct {
+      unsigned char addr[ETH_ADDR_LEN];
+      struct sockaddr_un name;
+    } new_control;
+  } u;
+};
+
+static struct sockaddr_un *new_addr(void *name, int len)
+{
+	struct sockaddr_un *sun;
+
+	sun = um_kmalloc(sizeof(struct sockaddr_un));
+	if(sun == NULL){
+		printk("new_addr: allocation of sockaddr_un failed\n");
+		return(NULL);
+	}
+	sun->sun_family = AF_UNIX;
+	memcpy(sun->sun_path, name, len);
+	return(sun);
+}
+
+static void daemon_user_init(void *data, void *dev)
+{
+	struct daemon_data *pri = data;
+	struct timeval tv;
+	struct {
+		char zero;
+		int pid;
+		int usecs;
+	} name;
+
+	if(!strcmp(pri->sock_type, "unix"))
+		pri->ctl_addr = new_addr(pri->ctl_sock, 
+					 strlen(pri->ctl_sock) + 1);
+	name.zero = 0;
+	name.pid = getpid();
+	gettimeofday(&tv, NULL);
+	name.usecs = tv.tv_usec;
+	pri->local_addr = new_addr(&name, sizeof(name));
+	pri->dev = dev;
+}
+
+static int daemon_open(void *data)
+{
+	struct daemon_data *pri = data;
+	struct sockaddr_un *ctl_addr = pri->ctl_addr;
+	struct sockaddr_un *local_addr = pri->local_addr;
+	struct sockaddr_un *sun;
+	struct request_v1 req;
+	char addr[sizeof("255.255.255.255\0")];
+	int fd, n, err;
+
+	if(!pri->hw_setup){
+		pri->hwaddr[0] = 0xfe;
+		pri->hwaddr[1] = 0xfd;
+		pri->hwaddr[2] = 0x0;
+		pri->hwaddr[3] = 0x0;
+		pri->hwaddr[4] = 0x0;
+		pri->hwaddr[5] = 0x0;
+		dev_ip_addr(pri->dev, addr, &pri->hwaddr[2]);
+		set_ether_mac(pri->dev, pri->hwaddr);
+	}
+	if((ctl_addr == NULL) || (pri->local_addr == NULL))
+		return(-EINVAL);
+
+	if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
+		printk("daemon_open : control socket failed, errno = %d\n", 
+		       errno);		
+		return(-errno);
+	}
+
+	if(connect(pri->control, (struct sockaddr *) ctl_addr, 
+		   sizeof(*ctl_addr)) < 0){
+		printk("daemon_open : control connect failed, errno = %d\n",
+		       errno);
+		err = -errno;
+		goto out;
+	}
+
+	if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
+		printk("daemon_open : data socket failed, errno = %d\n", 
+		       errno);
+		err = -errno;
+		goto out;
+	}
+	if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
+		printk("daemon_open : data bind failed, errno = %d\n", 
+		       errno);
+		err = -errno;
+		goto out_close;
+	}
+
+	sun = um_kmalloc(sizeof(struct sockaddr_un));
+	if(sun == NULL){
+		printk("new_addr: allocation of sockaddr_un failed\n");
+		err = -ENOMEM;
+		goto out_close;
+	}
+
+	req.magic = SWITCH_MAGIC;
+	req.type = REQ_NEW_CONTROL;
+	memcpy(req.u.new_control.addr, pri->hwaddr, 
+	       sizeof(req.u.new_control.addr));
+	req.u.new_control.name = *local_addr;
+	n = write(pri->control, &req, sizeof(req));
+	if(n != sizeof(req)){
+		printk("daemon_open : control setup request returned %d, "
+		       "errno = %d\n", n, errno);
+		err = -ENOTCONN;
+		goto out;		
+	}
+
+	n = read(pri->control, sun, sizeof(*sun));
+	if(n != sizeof(*sun)){
+		printk("daemon_open : read of data socket returned %d, "
+		       "errno = %d\n", n, errno);
+		err = -ENOTCONN;
+		goto out_close;		
+	}
+	pri->data_addr = sun;
+
+	return(fd);
+
+ out_close:
+	close(fd);
+ out:
+	close(pri->control);
+	return(err);
+}
+
+static void daemon_close(int fd, void *data)
+{
+	struct daemon_data *pri = data;
+
+	close(fd);
+	close(pri->control);
+}
+
+int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
+{
+	struct sockaddr_un *data_addr = pri->data_addr;
+
+	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+}
+
+static int daemon_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+int daemon_user_set_mac(struct daemon_data *pri, unsigned char *hwaddr,
+			 int len)
+{
+	memcpy(pri->hwaddr, hwaddr, len);
+	return(0);
+}
+
+struct net_user_info daemon_user_info = {
+	init:		daemon_user_init,
+	open:		daemon_open,
+	close:	 	daemon_close,
+	set_mtu:	daemon_set_mtu,
+	add_address:	NULL,
+	delete_address: NULL,
+	max_packet:	MAX_PACKET - ETH_HEADER_OTHER
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/etap.h linux-2.4.19-pre5-mjc/arch/um/drivers/etap.h
--- linux/arch/um/drivers/etap.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/etap.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,29 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct ethertap_data {
+	char *dev_name;
+	char *gate_addr;
+	int data_fd;
+	int control_fd;
+	void *dev;
+	unsigned char hw_addr[ETH_ADDR_LEN];
+	int hw_setup;
+};
+
+extern struct net_user_info ethertap_user_info;
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/etap_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/etap_kern.h
--- linux/arch/um/drivers/etap_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/etap_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ETHERTAP_KERN_H
+#define __UM_ETHERTAP_KERN_H
+
+#include "net_kern.h"
+
+extern void ethertap_setup(char *arg, struct uml_net *dev);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ethertap_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/ethertap_kern.c
--- linux/arch/um/drivers/ethertap_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ethertap_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "etap.h"
+#include "etap_kern.h"
+
+struct ethertap_setup {
+	char *dev_name;
+	unsigned char hw_addr[ETH_ALEN];
+	int hw_setup;
+	char *gate_addr;
+};
+
+struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = { 
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		dev_name:	NULL,
+		hw_addr:	{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+		hw_setup:	0,
+		gate_addr:	NULL,
+	}
+};
+
+struct net_device *etap_init(int private_size, int index)
+{
+	struct net_device *dev;
+	struct uml_net_private *pri;
+	struct ethertap_data *epri;
+
+	dev = init_etherdev(NULL, private_size);
+	if(dev == NULL) return(NULL);
+	pri = dev->priv;
+	epri = (struct ethertap_data *) pri->user;
+	epri->dev_name = ethertap_priv[index].dev_name;
+	epri->gate_addr = ethertap_priv[index].gate_addr;
+	memcpy(dev->dev_addr, ethertap_priv[index].hw_addr, ETH_ALEN);
+	memcpy(epri->hw_addr, ethertap_priv[index].hw_addr, 
+	       sizeof(epri->hw_addr));
+	printk("ethertap backend - %s", epri->dev_name);
+	if(epri->gate_addr != NULL) 
+		printk(", IP = %s", epri->gate_addr);
+	epri->hw_setup = ethertap_priv[index].hw_setup;
+	if(epri->hw_setup)
+		printk(", ether = %x:%x:%x:%x:%x:%x",
+		       epri->hw_addr[0], epri->hw_addr[1], epri->hw_addr[2],
+		       epri->hw_addr[3], epri->hw_addr[4], epri->hw_addr[5]);
+	printk("\n");
+	epri->data_fd = -1;
+	epri->control_fd = -1;
+	return(dev);
+}
+
+static unsigned short etap_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int etap_set_mac(struct sockaddr *addr, void *data)
+{
+	struct ethertap_data *pri = data;
+	struct sockaddr *hwaddr = addr;
+
+	memcpy(pri->hw_addr, hwaddr->sa_data, ETH_ALEN);
+
+	return 0;
+}
+
+static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	int len;
+
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
+	if(*skb == NULL) return(-ENOMEM);
+	len = net_recvfrom(fd, (*skb)->mac.raw, 
+			   (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
+	if(len <= 0) return(len);
+	skb_pull(*skb, 2);
+	len -= 2;
+	return(len);
+}
+
+static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	if(skb_headroom(*skb) < 2){
+	  	struct sk_buff *skb2;
+
+		skb2 = skb_realloc_headroom(*skb, 2);
+		dev_kfree_skb(*skb);
+		if (skb2 == NULL) return(-ENOMEM);
+		*skb = skb2;
+	}
+	skb_push(*skb, 2);
+	return(net_send(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info ethertap_kern_info = {
+	init:			etap_init,
+	protocol:		etap_protocol,
+	set_mac:		etap_set_mac,
+	read:			etap_read,
+	write: 			etap_write,
+};
+
+static int ethertap_count = 0;
+
+void ethertap_setup(char *str, struct uml_net *dev)
+{
+	struct ethertap_setup *pri;
+
+	dev->user = &ethertap_user_info;
+	dev->kern = &ethertap_kern_info;
+	dev->private_size = sizeof(struct ethertap_data);
+	pri = &ethertap_priv[ethertap_count];
+	dev->transport_index = ethertap_count++;
+	tap_setup_common(str, "ethertap", &pri->dev_name, pri->hw_addr,  
+			 &pri->hw_setup, &pri->gate_addr);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ethertap_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/ethertap_user.c
--- linux/arch/um/drivers/ethertap_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ethertap_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include "user.h"
+#include "kern_util.h"
+#include "net_user.h"
+#include "etap.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void etap_user_init(void *data, void *dev)
+{
+	struct ethertap_data *pri = data;
+
+	pri->dev = dev;
+}
+
+struct etap_open_data {
+	char *name;
+	char *gate;
+	int data_remote;
+	int data_me;
+	int control_remote;
+	int control_me;
+	int err;
+	int output_len;
+	char *output;
+};
+
+struct addr_change {
+	enum { ADD_ADDR, DEL_ADDR } what;
+	unsigned char addr[4];
+	unsigned char netmask[4];
+};
+
+static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
+			int fd)
+{
+	struct addr_change change;
+	void *output;
+
+	change.what = op;
+	memcpy(change.addr, addr, sizeof(change.addr));
+	memcpy(change.netmask, netmask, sizeof(change.netmask));
+	if(write(fd, &change, sizeof(change)) != sizeof(change))
+		printk("etap_change - request failed, errno = %d\n",
+		       errno);
+	output = um_kmalloc(page_size());
+	if(output == NULL)
+		printk("etap_change : Failed to allocate output buffer\n");
+	read_output(fd, output, page_size());
+	if(output != NULL){
+		printk("%s", output);
+		kfree(output);
+	}
+}
+
+static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
+			   void *arg)
+{
+	etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
+}
+
+static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
+			    void *arg)
+{
+	etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
+}
+
+static void etap_tramp(void *arg)
+{
+	struct etap_open_data *data = arg;
+	int pid, status;
+	char version_buf[sizeof("nnnnn\0")];
+	char data_fd_buf[sizeof("nnnnnn\0")];
+	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+	char *setup_args[] = { "uml_net", version_buf, "ethertap", data->name,
+			       data_fd_buf, gate_buf, NULL };
+	char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 
+				 data->name, data_fd_buf, NULL };
+	char **args, c;
+
+	sprintf(data_fd_buf, "%d", data->data_remote);
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+	if(data->gate != NULL){
+		strcpy(gate_buf, data->gate);
+		args = setup_args;
+	}
+	else args = nosetup_args;
+	data->err = 0;
+	if((pid = fork()) == 0){
+		dup2(data->control_remote, 1);
+		close(data->data_me);
+		close(data->control_me);
+		execvp(args[0], args);
+		printk("Exec of '%s' failed - errno = %d\n", args[0], errno);
+		exit(1);
+	}
+	else if(pid < 0) data->err = errno;
+	close(data->data_remote);
+	close(data->control_remote);
+	data->output = NULL;
+	if(read(data->control_me, &c, sizeof(c)) != sizeof(c)){
+		printk("etap_tramp : read of status failed, errno = %d\n",
+		       errno);
+		data->err = EINVAL;
+		return;
+	}
+	if(c != 1){
+		printk("etap_tramp : uml_net failed\n");
+		data->err = EINVAL;
+		if(waitpid(pid, &status, 0) < 0) data->err = errno;
+		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){
+			printk("uml_net didn't exit with status 1\n");
+		}
+		return;
+	}
+	read_output(data->control_me, data->output, data->output_len);
+}
+
+static int etap_open(void *data)
+{
+	struct ethertap_data *pri = data;
+	struct etap_open_data tap_data;
+	int data_fds[2], control_fds[2], err;
+
+	err = tap_open_common(pri->dev, pri->hw_setup, pri->gate_addr);
+	if(err) return(err);
+
+	tap_data.name = pri->dev_name;
+
+	if(socketpair(PF_UNIX, SOCK_DGRAM, 0, data_fds) < 0){
+		printk("data socketpair failed - errno = %d\n", errno);
+		return(-errno);
+	}
+	tap_data.data_remote = data_fds[1];
+	tap_data.data_me = data_fds[0];
+
+	if(socketpair(PF_UNIX, SOCK_STREAM, 0, control_fds) < 0){
+		printk("data socketpair failed - errno = %d\n", errno);
+		return(-errno);
+	}
+	tap_data.control_remote = control_fds[1];
+	tap_data.control_me = control_fds[0];
+	
+	tap_data.gate = pri->gate_addr;
+	tap_data.output_len = page_size();
+	tap_data.output = um_kmalloc(tap_data.output_len);
+	if(tap_data.output == NULL)
+		printk("etap_open : failed to allocate output buffer\n");
+	tracing_cb(etap_tramp, &tap_data);
+
+	if(tap_data.output){
+		printk("%s", tap_data.output);
+		kfree(tap_data.output);
+	}
+	if(tap_data.err != 0){
+		printk("etap_tramp failed - errno = %d\n", tap_data.err);
+		return(-tap_data.err);
+	}
+	pri->data_fd = data_fds[0];
+	pri->control_fd = control_fds[0];
+	iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
+	return(data_fds[0]);
+}
+
+static void etap_close(int fd, void *data)
+{
+	struct ethertap_data *pri = data;
+
+	iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
+	close(fd);
+	shutdown(pri->data_fd, SHUT_RDWR);
+	close(pri->data_fd);
+	pri->data_fd = -1;
+	close(pri->control_fd);
+	pri->control_fd = -1;
+}
+
+static int etap_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
+			  void *data)
+{
+	struct ethertap_data *pri = data;
+
+	tap_check_mac(&pri->hw_setup, pri->hw_addr, pri->gate_addr, addr, 
+		      pri->dev);
+	if(pri->control_fd == -1) return;
+	etap_open_addr(addr, netmask, &pri->control_fd);
+}
+
+static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 
+			  void *data)
+{
+	struct ethertap_data *pri = data;
+
+	if(pri->control_fd == -1) return;
+	etap_close_addr(addr, netmask, &pri->control_fd);
+}
+
+struct net_user_info ethertap_user_info = {
+	init:		etap_user_init,
+	open:		etap_open,
+	close:	 	etap_close,
+	set_mtu:	etap_set_mtu,
+	add_address:	etap_add_addr,
+	delete_address: etap_del_addr,
+	max_packet:	MAX_PACKET - ETH_HEADER_ETHERTAP
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/fd.c linux-2.4.19-pre5-mjc/arch/um/drivers/fd.c
--- linux/arch/um/drivers/fd.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/fd.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,92 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include "user.h"
+#include "user_util.h"
+#include "chan_user.h"
+
+struct fd_chan {
+	int fd;
+	int raw;
+	struct termios tt;
+};
+
+void *fd_init(char *str, int device, struct chan_opts *opts)
+{
+	struct fd_chan *data;
+	char *end;
+	int n;
+
+	if(*str != ':'){
+		printk("fd_init : channel type 'fd' must specify a file "
+		       "descriptor\n");
+		return(NULL);
+	}
+	str++;
+	n = strtoul(str, &end, 0);
+	if(*end != '\0'){
+		printk("fd_init : couldn't parse file descriptor '%s'\n", str);
+		return(NULL);
+	}
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct fd_chan) { fd : 	n,
+				    raw : 	opts->raw });
+	return(data);
+}
+
+int fd_open(int input, int output, int primary, void *d)
+{
+	struct fd_chan *data = d;
+
+	if(data->raw && isatty(data->fd)){
+		tcgetattr(data->fd, &data->tt);
+		raw(data->fd, 0);
+	}
+	return(data->fd);
+}
+
+void fd_close(int fd, void *d)
+{
+	struct fd_chan *data = d;
+
+	if(data->raw && isatty(fd)){
+		tcsetattr(fd, TCSADRAIN, &data->tt);
+		data->raw = 0;
+	}
+}
+
+int fd_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct fd_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops fd_ops = {
+	init:		fd_init,
+	open:		fd_open,
+	close:		fd_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	fd_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		1,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/hostaudio_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/hostaudio_kern.c
--- linux/arch/um/drivers/hostaudio_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/hostaudio_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,262 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/module.h"
+#include "linux/version.h"
+#include "linux/init.h"
+#include "linux/slab.h"
+#include "linux/fs.h"
+#include "linux/sound.h"
+#include "linux/soundcard.h"
+#include "kern_util.h"
+#include "init.h"
+#include "hostaudio.h"
+
+char *dsp = HOSTAUDIO_DEV_DSP;
+char *mixer = HOSTAUDIO_DEV_MIXER;
+
+static int set_dsp(char *name, int *add)
+{
+	dsp = uml_strdup(name);
+	return(0);
+}
+
+__uml_setup("dsp=", set_dsp,
+"dsp=<dsp device>\n"
+"    This is used to specify the host dsp device to the hostaudio driver.\n"
+"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
+);
+
+static int set_mixer(char *name, int *add)
+{
+	mixer = uml_strdup(name);
+	return(0);
+}
+
+__uml_setup("mixer=", set_mixer,
+"mixer=<mixer device>\n"
+"    This is used to specify the host mixer device to the hostaudio driver.\n"
+"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
+);
+
+/* /dev/dsp file operations */
+
+static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
+			      loff_t *ppos)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: read called, count = %d\n", count);
+#endif
+
+        return(hostaudio_read_user(state, buffer, count, ppos));
+}
+
+static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+			       size_t count, loff_t *ppos)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: write called, count = %d\n", count);
+#endif
+        return(hostaudio_write_user(state, buffer, count, ppos));
+}
+
+static unsigned int hostaudio_poll(struct file *file, 
+				   struct poll_table_struct *wait)
+{
+        unsigned int mask = 0;
+
+#ifdef DEBUG
+        printk("hostaudio: poll called (unimplemented)\n");
+#endif
+
+        return(mask);
+}
+
+static int hostaudio_ioctl(struct inode *inode, struct file *file, 
+			   unsigned int cmd, unsigned long arg)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: ioctl called, cmd = %u\n", cmd);
+#endif
+
+        return(hostaudio_ioctl_user(state, cmd, arg));
+}
+
+static int hostaudio_open(struct inode *inode, struct file *file)
+{
+        struct hostaudio_state *state;
+        int r = 0, w = 0;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostaudio: open called (host: %s)\n", dsp);
+#endif
+
+        state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
+        if(state == NULL) return(-ENOMEM);
+
+        if(file->f_mode & FMODE_READ) r = 1;
+        if(file->f_mode & FMODE_WRITE) w = 1;
+
+        ret = hostaudio_open_user(state, r, w, dsp);
+        if(ret < 0){
+		kfree(state);
+		return(ret);
+        }
+
+        file->private_data = state;
+        return(0);
+}
+
+static int hostaudio_release(struct inode *inode, struct file *file)
+{
+        struct hostaudio_state *state = file->private_data;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostaudio: release called\n");
+#endif
+
+        ret = hostaudio_release_user(state);
+        kfree(state);
+
+        return(ret);
+}
+
+/* /dev/mixer file operations */
+
+static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, 
+				  unsigned int cmd, unsigned long arg)
+{
+        struct hostmixer_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostmixer: ioctl called\n");
+#endif
+
+        return(hostmixer_ioctl_mixdev_user(state, cmd, arg));
+}
+
+static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
+{
+        struct hostmixer_state *state;
+        int r = 0, w = 0;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostmixer: open called (host: %s)\n", mixer);
+#endif
+
+        state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
+        if(state == NULL) return(-ENOMEM);
+
+        if(file->f_mode & FMODE_READ) r = 1;
+        if(file->f_mode & FMODE_WRITE) w = 1;
+
+        ret = hostmixer_open_mixdev_user(state, r, w, mixer);
+        
+        if(ret < 0){
+		kfree(state);
+		return(ret);
+        }
+
+        file->private_data = state;
+        return(0);
+}
+
+static int hostmixer_release(struct inode *inode, struct file *file)
+{
+        struct hostmixer_state *state = file->private_data;
+	int ret;
+
+#ifdef DEBUG
+        printk("hostmixer: release called\n");
+#endif
+
+        ret = hostmixer_release_mixdev_user(state);
+        kfree(state);
+
+        return(ret);
+}
+
+
+/* kernel module operations */
+
+static struct file_operations hostaudio_fops = {
+        owner:          THIS_MODULE,
+        llseek:         no_llseek,
+        read:           hostaudio_read,
+        write:          hostaudio_write,
+        poll:           hostaudio_poll,
+        ioctl:          hostaudio_ioctl,
+        mmap:           NULL,
+        open:           hostaudio_open,
+        release:        hostaudio_release,
+};
+
+static struct file_operations hostmixer_fops = {
+        owner:          THIS_MODULE,
+        llseek:         no_llseek,
+        ioctl:          hostmixer_ioctl_mixdev,
+        open:           hostmixer_open_mixdev,
+        release:        hostmixer_release,
+};
+
+struct {
+	int dev_audio;
+	int dev_mixer;
+} module_data;
+
+MODULE_AUTHOR("Steve Schmidtke");
+MODULE_DESCRIPTION("UML Audio Relay");
+MODULE_LICENSE("GPL");
+
+static int __init hostaudio_init_module(void)
+{
+        printk(KERN_INFO "UML Audio Relay: " __DATE__ " " __TIME__ "\n");
+
+	module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
+        if(module_data.dev_audio < 0){
+                printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
+                return -ENODEV;
+        }
+
+	module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
+        if(module_data.dev_mixer < 0){
+                printk(KERN_ERR "hostmixer: couldn't register mixer "
+		       "device!\n");
+                unregister_sound_dsp(module_data.dev_audio);
+                return -ENODEV;
+        }
+
+        return 0;
+}
+
+static void __exit hostaudio_cleanup_module (void)
+{
+       unregister_sound_mixer(module_data.dev_mixer);
+       unregister_sound_dsp(module_data.dev_audio);
+}
+
+module_init(hostaudio_init_module);
+module_exit(hostaudio_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/hostaudio_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/hostaudio_user.c
--- linux/arch/um/drivers/hostaudio_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/hostaudio_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,160 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "hostaudio.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+
+/* /dev/dsp file operations */
+
+ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, 
+			    size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+
+#ifdef DEBUG
+        printk("hostaudio: read_user called, count = %d\n", count);
+#endif
+
+        ret = read(state->fd, buffer, count);
+
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
+			     size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+
+#ifdef DEBUG
+        printk("hostaudio: write_user called, count = %d\n", count);
+#endif
+
+        ret = write(state->fd, buffer, count);
+
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, 
+			 unsigned long arg)
+{
+	int ret;
+#ifdef DEBUG
+        printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
+#endif
+
+        ret = ioctl(state->fd, cmd, arg);
+	
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
+{
+	int flags = 0;
+
+#ifdef DEBUG
+        printk("hostaudio: open_user called\n");
+#endif
+
+	if(r && !w) flags = O_RDONLY;
+	else if(!r && w) flags = O_WRONLY;
+	else if(r && w) flags = O_RDWR;
+
+        state->fd = open(dsp, flags);
+
+        if(state->fd >= 0) return(0);
+
+        printk("hostaudio_open_user failed to open '%s', errno = %d\n",
+	       dsp, errno);
+        
+        return(-errno); 
+}
+
+int hostaudio_release_user(struct hostaudio_state *state)
+{
+#ifdef DEBUG
+        printk("hostaudio: release called\n");
+#endif
+        if(state->fd >= 0){
+		close(state->fd);
+		state->fd=-1;
+        }
+
+        return(0);
+}
+
+/* /dev/mixer file operations */
+
+int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
+				unsigned int cmd, unsigned long arg)
+{
+	int ret;
+#ifdef DEBUG
+        printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
+#endif
+
+        ret = ioctl(state->fd, cmd, arg);
+	if(ret < 0) 
+		return(-errno);
+	return(ret);
+}
+
+int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
+			       char *mixer)
+{
+	int flags = 0;
+
+#ifdef DEBUG
+        printk("hostmixer: open_user called\n");
+#endif
+
+	if(r && !w) flags = O_RDONLY;
+	else if(!r && w) flags = O_WRONLY;
+	else if(r && w) flags = O_RDWR;
+
+        state->fd = open(mixer, flags);
+
+        if(state->fd >= 0) return(0);
+
+        printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n",
+	       mixer, errno);
+        
+        return(-errno); 
+}
+
+int hostmixer_release_mixdev_user(struct hostmixer_state *state)
+{
+#ifdef DEBUG
+        printk("hostmixer: release_user called\n");
+#endif
+
+        if(state->fd >= 0){
+		close(state->fd);
+		state->fd = -1;
+        }
+
+        return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/line.c linux-2.4.19-pre5-mjc/arch/um/drivers/line.c
--- linux/arch/um/drivers/line.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/line.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,308 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/list.h"
+#include "asm/irq.h"
+#include "chan_kern.h"
+#include "irq_user.h"
+#include "line.h"
+#include "kern.h"
+#include "user_util.h"
+
+#define LINE_BUFSIZE 4096
+
+void line_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct line *dev = data;
+
+	if(dev->count > 0) chan_interrupt(&dev->chan_list, dev->tty, irq);
+}
+
+void buffer_data(struct line *line, const char *buf, int len)
+{
+	int end;
+
+	if(line->buffer == NULL){
+		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
+		if(line->buffer == NULL){
+			printk("buffer_data - atomic allocation failed\n");
+			return;
+		}
+		line->head = line->buffer;
+		line->tail = line->buffer;
+	}
+	end = line->buffer + LINE_BUFSIZE - line->tail;
+	if(len < end){
+		memcpy(line->tail, buf, len);
+		line->tail += len;
+	}
+	else {
+		memcpy(line->tail, buf, end);
+		buf += end;
+		len -= end;
+		memcpy(line->buffer, buf, len);
+		line->tail = line->buffer + len;
+	}
+}
+
+static int flush_buffer(struct line *line)
+{
+	int n, count;
+
+	if((line->buffer == NULL) || (line->head == line->tail)) return(1);
+
+	if(line->tail < line->head){
+		count = line->buffer + LINE_BUFSIZE - line->head;
+		n = write_chan(&line->chan_list, line->head, count,
+			       line->write_irq);
+		if(n < 0) return(n);
+		if(n == count) line->head = line->buffer;
+		else {
+			line->head += n;
+			return(0);
+		}
+	}
+
+	count = line->tail - line->head;
+	n = write_chan(&line->chan_list, line->head, count, line->write_irq);
+	if(n < 0) return(n);
+
+	line->head += n;
+	return(line->head == line->tail);
+}
+
+int line_write(struct line *line, const char *buf, int len)
+{
+	unsigned long flags;
+	int n, err;
+
+	if(line->head != line->tail){
+		local_irq_save(flags);
+		buffer_data(line, buf, len);
+		err = flush_buffer(line);
+		local_irq_restore(flags);
+		if(err <= 0) return(len);
+	}
+	else {
+		n = write_chan(&line->chan_list, buf, len, line->write_irq);
+		if(n < 0) return(n);
+		if(n < len) buffer_data(line, buf + n, len - n);
+	}
+	return(len);
+}
+
+void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct line *dev = data;
+	struct tty_struct *tty = dev->tty;
+	int err;
+
+	err = flush_buffer(dev);
+	if(err == 0) return;
+	else if(err < 0){
+		dev->head = dev->buffer;
+		dev->tail = dev->buffer;
+	}
+
+	if(tty == NULL) return;
+
+	if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
+	   (tty->ldisc.write_wakeup != NULL))
+		(tty->ldisc.write_wakeup)(tty);
+	
+	/* BLOCKING mode
+	 * In blocking mode, everything sleeps on tty->write_wait.
+	 * Sleeping in the console driver would break non-blocking
+	 * writes.
+	 */
+
+	if (waitqueue_active(&tty->write_wait))
+		wake_up_interruptible(&tty->write_wait);
+
+}
+
+int line_write_room(struct tty_struct *tty)
+{
+	struct line *dev = tty->driver_data;
+	int n;
+
+	if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
+
+	n = dev->head - dev->tail;
+	if(n <= 0) n = LINE_BUFSIZE + n;
+	return(n - 1);
+}
+
+int line_open(struct line *lines, int n, struct tty_struct *tty,
+	      int (*setup_irq)(int fd, int input, int output, void *data),
+	      struct chan_opts *opts)
+{
+	struct line *line = &lines[n];
+	int err = 0;
+
+	down(&line->sem);
+	if(line->count == 0){
+		if(!line->valid){
+			err = -ENODEV;
+			goto out;
+		}
+		if(list_empty(&line->chan_list)){
+			err = parse_chan_pair(line->init_str, &line->chan_list,
+					      line->init_pri, n, opts);
+			if(err) goto out;
+			err = open_chan(&line->chan_list);
+			if(err) goto out;
+		}
+		enable_chan(&line->chan_list, setup_irq, line);
+	}
+
+	if(!line->sigio){
+		chan_enable_winch(&line->chan_list, line);
+		line->sigio = 1;
+	}
+
+	/* This is outside the if because the initial console is opened
+	 * with tty == NULL
+	 */
+	line->tty = tty;
+
+	if(tty != NULL)	tty->driver_data = line;
+
+	line->count++;
+ out:
+	up(&line->sem);
+	return(err);
+}
+
+void line_close(struct line *lines, int n, int irq)
+{
+	struct line *line = &lines[n];
+
+	line->count--;
+	if(line->count == 0){
+		disable_chan(&line->chan_list, irq, line);
+		line->tty = NULL;
+	}
+}
+
+void line_setup(struct line *lines, int num, char *init)
+{
+	int i, n;
+	char *end;
+
+	if(*init == '=') n = -1;
+	else {
+		n = simple_strtoul(init, &end, 0);
+		if(*end != '='){
+			printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
+			       init);
+			return;
+		}
+		init = end;
+	}
+	init++;
+	if(n == -1){
+		for(i = 0; i < num; i++){
+			if(lines[i].init_pri <= INIT_ALL){
+				lines[i].init_pri = INIT_ALL;
+				if(!strcmp(init, "none")) lines[i].valid = 0;
+				else lines[i].init_str = init;
+			}
+		}
+	}
+	else if(lines[n].init_pri <= INIT_ONE){
+		lines[n].init_pri = INIT_ONE;
+		if(!strcmp(init, "none")) lines[n].valid = 0;
+		else lines[n].init_str = init;
+	}
+}
+
+struct winch {
+	struct list_head list;
+	int fd;
+	int tty_fd;
+	int pid;
+	struct line *line;
+};
+
+void winch_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct winch *winch = data;
+	struct tty_struct *tty;
+	char c;
+
+	c = generic_read(winch->fd, NULL);
+	if(c < 0){
+		if(c != -EAGAIN){
+			printk("winch_interrupt : read failed, errno = %d\n", 
+			       -c);
+			printk("fd %d is losing SIGWINCH support\n", 
+			       winch->tty_fd);
+			free_irq(irq, data);
+			return;
+		}
+		goto out;
+	}
+	tty = winch->line->tty;
+	if(tty != NULL){
+		chan_window_size(&winch->line->chan_list, 
+				 &tty->winsize.ws_row, 
+				 &tty->winsize.ws_col);
+		kill_pg(tty->pgrp, SIGWINCH, 1);
+	}
+ out:
+	reactivate_fd(winch->fd, WINCH_IRQ);
+}
+
+struct list_head winch_handlers = LIST_HEAD_INIT(winch_handlers);
+
+void register_winch_irq(int fd, int tty_fd, int pid, void *line)
+{
+	struct winch *winch;
+
+	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
+	if(winch == NULL){
+		printk("register_winch_irq - kmalloc failed\n");
+		return;
+	}
+	*winch = ((struct winch) { list : 	LIST_HEAD_INIT(winch->list),
+				   fd : 	fd,
+				   tty_fd :	tty_fd,
+				   pid : 	pid,
+				   line :	line });
+	list_add(&winch->list, &winch_handlers);
+	if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 
+			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+			  "winch", winch) < 0)
+		printk("register_winch_irq - failed to register IRQ\n");
+}
+
+static void winch_cleanup(void)
+{
+	struct list_head *ele;
+	struct winch *winch;
+
+	list_for_each(ele, &winch_handlers){
+		winch = list_entry(ele, struct winch, list);
+		close(winch->fd);
+		free_irq_by_fd(winch->fd);
+		if(winch->pid != -1) kill_pid(winch->pid);
+	}
+}
+
+__uml_exitcall(winch_cleanup);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mcast.h linux-2.4.19-pre5-mjc/arch/um/drivers/mcast.h
--- linux/arch/um/drivers/mcast.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mcast.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct mcast_data {
+	char *addr;
+	unsigned short port;
+	void *mcast_addr;
+	int ttl;
+	unsigned char hwaddr[ETH_ADDR_LEN];
+	int hw_setup;
+	void *dev;
+};
+
+extern struct net_user_info mcast_user_info;
+
+extern int mcast_user_set_mac(struct mcast_data *pri, unsigned char *hwaddr,
+			       int len);
+extern int mcast_user_write(int fd, void *buf, int len, 
+			    struct mcast_data *pri);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mcast_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_kern.c
--- linux/arch/um/drivers/mcast_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,167 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ */
+
+#include "linux/kernel.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/in.h"
+#include "linux/inet.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "mcast.h"
+#include "mcast_kern.h"
+
+struct mcast_data mcast_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		addr:		"239.192.168.1",
+		port:		1102,
+		ttl:		1,
+		hwaddr:		{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+		hw_setup:	0,
+	}
+};
+
+struct net_device *mcast_init(int private_size, int index)
+{
+	struct net_device *dev;
+	struct uml_net_private *pri;
+	struct mcast_data *dpri;
+
+	dev = init_etherdev(NULL, private_size);
+	if (!dev) 
+		return NULL;
+
+	pri = dev->priv;
+	dpri = (struct mcast_data *) pri->user;
+	*dpri = mcast_priv[index];
+	memcpy(dev->dev_addr, dpri->hwaddr, ETH_ALEN);
+	printk("mcast backend ");
+	if(dpri->hw_setup)
+		printk("ethernet address=%x:%x:%x:%x:%x:%x ",
+		       dpri->hwaddr[0], dpri->hwaddr[1], dpri->hwaddr[2], 
+		       dpri->hwaddr[3], dpri->hwaddr[4], dpri->hwaddr[5]);
+		
+	printk("multicast adddress: %s:%u, TTL:%u ",
+	       dpri->addr, dpri->port, dpri->ttl);
+
+	printk("\n");
+	return(dev);
+}
+
+static unsigned short mcast_protocol(struct sk_buff *skb)
+{
+	return eth_type_trans(skb, skb->dev);
+}
+
+static int mcast_set_mac(struct sockaddr *addr, void *data)
+{
+	struct mcast_data *pri = data;
+	struct net_device *dev = pri->dev;
+	struct sockaddr *hwaddr = addr;
+
+	memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
+	return mcast_user_set_mac(pri, hwaddr->sa_data, ETH_ALEN);
+}
+
+static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_recvfrom(fd, (*skb)->mac.raw, 
+			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int mcast_write(int fd, struct sk_buff **skb,
+			struct uml_net_private *lp)
+{
+	return mcast_user_write(fd, (*skb)->data, (*skb)->len, 
+				 (struct mcast_data *) &lp->user);
+}
+
+static struct net_kern_info mcast_kern_info = {
+	init:			mcast_init,
+	protocol:		mcast_protocol,
+	set_mac:		mcast_set_mac,
+	read:			mcast_read,
+	write:			mcast_write,
+};
+
+static int mcast_count = 0;
+
+void mcast_setup(char *str, struct uml_net *dev)
+{
+	int err, n = mcast_count;
+	int num = 0;
+	char *p1, *p2;
+
+	dev->user = &mcast_user_info;
+	dev->kern = &mcast_kern_info;
+	dev->private_size = sizeof(struct mcast_data);
+	dev->transport_index = mcast_count++;
+
+
+	/* somewhat more sophisticated parser, needed for in_aton */
+
+	p1 = str;
+	if (*str == ',')
+		p1++;
+	while (p1 && *p1) {
+		if ((p2 = strchr(p1, ',')))
+			*p2++ = '\0';
+		if (strlen(p1) > 0) {
+			switch (num) {
+			case 0:
+				/* First argument: Ethernet address */
+				err = setup_etheraddr(p1, 
+						      mcast_priv[n].hwaddr);
+				if (!err) 
+					mcast_priv[n].hw_setup = 1;
+				break;
+			case 1:
+				/* Second argument: Multicast group */
+				mcast_priv[n].addr = p1;
+				break;
+			case 2:
+				/* Third argument: Port number */
+				mcast_priv[n].port = 
+					htons(simple_strtoul(p1, NULL, 10));
+				break;
+			case 3:
+				/* Fourth argument: TTL */
+				mcast_priv[n].ttl = 
+						simple_strtoul(p1, NULL, 10);
+				break;
+			}
+		}
+		p1 = p2;
+		num++;
+	}
+
+	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n",
+		mcast_priv[n].addr, mcast_priv[n].port,
+		mcast_priv[n].ttl);
+
+	return;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mcast_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_kern.h
--- linux/arch/um/drivers/mcast_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_MCAST_KERN_H
+#define __UM_MCAST_KERN_H
+
+#include "net_kern.h"
+
+extern void mcast_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru linux/arch/um/drivers/mcast_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_user.c
--- linux/arch/um/drivers/mcast_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mcast_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,193 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <linux/inet.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include "net_user.h"
+#include "mcast.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "user.h"
+
+#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+static struct sockaddr_in *new_addr(char *addr, unsigned short port)
+{
+	struct sockaddr_in *sin;
+
+	sin = um_kmalloc(sizeof(struct sockaddr_in));
+	if(sin == NULL){
+		printk("new_addr: allocation of sockaddr_in failed\n");
+		return(NULL);
+	}
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = in_aton(addr);
+	sin->sin_port = port;
+	return(sin);
+}
+
+static void mcast_user_init(void *data, void *dev)
+{
+	struct mcast_data *pri = data;
+
+	pri->mcast_addr = new_addr(pri->addr, pri->port);
+	pri->dev = dev;
+}
+
+static int mcast_open(void *data)
+{
+	struct mcast_data *pri = data;
+	struct sockaddr_in *sin = pri->mcast_addr;
+	struct ip_mreq mreq;
+	char addr[sizeof("255.255.255.255\0")];
+	int fd, yes = 1;
+
+
+	if(!pri->hw_setup){
+		pri->hwaddr[0] = 0xfe;
+		pri->hwaddr[1] = 0xfd;
+		pri->hwaddr[2] = 0x0;
+		pri->hwaddr[3] = 0x0;
+		pri->hwaddr[4] = 0x0;
+		pri->hwaddr[5] = 0x0;
+		dev_ip_addr(pri->dev, addr, &pri->hwaddr[2]);
+		set_ether_mac(pri->dev, pri->hwaddr);
+	}
+
+	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
+		fd = -EINVAL;
+		goto out;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+		printk("mcast_open : data socket failed, errno = %d\n", 
+		       errno);
+		fd = -ENOMEM;
+		goto out;
+	}
+
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+		printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* set ttl according to config */
+	if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
+		       sizeof(pri->ttl)) < 0) {
+		printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* set LOOP, so data does get fed back to local sockets */
+	if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+		printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* bind socket to mcast address */
+	if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
+		printk("mcast_open : data bind failed, errno = %d\n", errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}		
+	
+	/* subscribe to the multicast group */
+	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
+	mreq.imr_interface.s_addr = 0;
+	if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, 
+		       &mreq, sizeof(mreq)) < 0) {
+		printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
+			errno);
+		printk("There appears not to be a multicast-capable network "
+		       "interface on the host.\n");
+		printk("eth0 should be configured in order to use the "
+		       "multicast transport.\n");
+		close(fd);
+		fd = -EINVAL;
+	}
+
+ out:
+	return(fd);
+}
+
+static void mcast_close(int fd, void *data)
+{
+	struct ip_mreq mreq;
+	struct mcast_data *pri = data;
+	struct sockaddr_in *sin = pri->mcast_addr;
+
+	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
+	mreq.imr_interface.s_addr = 0;
+	if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
+		       &mreq, sizeof(mreq)) < 0) {
+		printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
+			errno);
+	}
+
+	close(fd);
+}
+
+int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
+{
+	struct sockaddr_in *data_addr = pri->mcast_addr;
+
+	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+}
+
+static int mcast_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+int mcast_user_set_mac(struct mcast_data *pri, unsigned char *hwaddr,
+			 int len)
+{
+	memcpy(pri->hwaddr, hwaddr, len);
+	return 0;
+}
+
+struct net_user_info mcast_user_info = {
+	init:		mcast_user_init,
+	open:		mcast_open,
+	close:	 	mcast_close,
+	set_mtu:	mcast_set_mtu,
+	add_address:	NULL,
+	delete_address: NULL,
+	max_packet:	MAX_PACKET - ETH_HEADER_OTHER
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mconsole_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/mconsole_kern.c
--- linux/arch/um/drivers/mconsole_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mconsole_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/slab.h"
+#include "linux/init.h"
+#include "linux/notifier.h"
+#include "linux/reboot.h"
+#include "linux/utsname.h"
+#include "linux/ctype.h"
+#include "linux/interrupt.h"
+#include "linux/sysrq.h"
+#include "asm/irq.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mconsole.h"
+#include "mconsole_kern.h"
+#include "irq_user.h"
+#include "init.h"
+
+static int do_unlink_socket(struct notifier_block *notifier, 
+			    unsigned long what, void *data)
+{
+	return(mconsole_unlink_socket());
+}
+
+
+static struct notifier_block reboot_notifier = {
+	notifier_call:		do_unlink_socket,
+	priority:		0,
+};
+
+LIST_HEAD(mc_requests);
+
+void mc_task_proc(void *unused)
+{
+	struct mconsole_entry *req;
+	unsigned long flags;
+	int done;
+
+	do {
+		save_flags(flags);
+		req = list_entry(mc_requests.next, struct mconsole_entry, 
+				 list);
+		list_del(&req->list);
+		done = list_empty(&mc_requests);
+		restore_flags(flags);
+		req->request.cmd->handler(&req->request);
+		kfree(req);
+	} while(!done);
+}
+
+struct tq_struct mconsole_task = {
+	routine:	mc_task_proc,
+	data: 		NULL
+};
+
+void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int fd;
+	struct mconsole_entry *new;
+	struct mc_request req;
+
+	fd = (int) dev_id;
+	while (mconsole_get_request(fd, &req)){
+		if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
+		else {
+			new = kmalloc(sizeof(req), GFP_ATOMIC);
+			if(new == NULL)
+				mconsole_reply(&req, "Out of memory", 1, 0);
+			else {
+				new->request = req;
+				list_add(&new->list, &mc_requests);
+			}
+		}
+	}
+	if(!list_empty(&mc_requests)) schedule_task(&mconsole_task);
+	reactivate_fd(fd, MCONSOLE_IRQ);
+}
+
+void mconsole_version(struct mc_request *req)
+{
+	char version[256];
+
+	sprintf(version, "%s %s %s %s %s", system_utsname.sysname, 
+		system_utsname.nodename, system_utsname.release, 
+		system_utsname.version, system_utsname.machine);
+	mconsole_reply(req, version, 0, 0);
+}
+
+#define UML_MCONSOLE_HELPTEXT \
+"Commands:
+    version - Get kernel version
+    help - Print this message
+    halt - Halt UML
+    reboot - Reboot UML
+    config <dev>=<config> - Add a new device to UML; 
+	same syntax as command line
+    remove <dev> - Remove a device from the client
+    sysrq <letter> - Performs the SysRq action controlled by the letter
+    cad - invoke the Ctl-Alt-Del handler
+"
+
+void mconsole_help(struct mc_request *req)
+{
+	mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
+}
+
+void mconsole_halt(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	machine_halt();
+}
+
+void mconsole_reboot(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	machine_restart(NULL);
+}
+
+extern void ctrl_alt_del(void);
+
+void mconsole_cad(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	ctrl_alt_del();
+}
+
+LIST_HEAD(mconsole_devices);
+
+void mconsole_register_dev(struct mc_device *new)
+{
+	list_add(&new->list, &mconsole_devices);
+}
+
+static struct mc_device *mconsole_find_dev(char *name)
+{
+	struct list_head *ele;
+	struct mc_device *dev;
+
+	list_for_each(ele, &mconsole_devices){
+		dev = list_entry(ele, struct mc_device, list);
+		if(!strncmp(name, dev->name, strlen(dev->name)))
+			return(dev);
+	}
+	return(NULL);
+}
+
+void mconsole_config(struct mc_request *req)
+{
+	struct mc_device *dev;
+	char *ptr = req->request.data;
+	int err;
+
+	ptr += strlen("config");
+	while(isspace(*ptr)) ptr++;
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "Bad configuration option", 1, 0);
+		return;
+	}
+	err = (*dev->config)(&ptr[strlen(dev->name)]);
+	mconsole_reply(req, "", err, 0);
+}
+
+void mconsole_remove(struct mc_request *req)
+{
+	struct mc_device *dev;	
+	char *ptr = req->request.data;
+	int err;
+
+	ptr += strlen("remove");
+	while(isspace(*ptr)) ptr++;
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "Bad remove option", 1, 0);
+		return;
+	}
+	err = (*dev->remove)(&ptr[strlen(dev->name)]);
+	mconsole_reply(req, "", err, 0);
+}
+
+#ifdef CONFIG_MAGIC_SYSRQ
+void mconsole_sysrq(struct mc_request *req)
+{
+	char *ptr = req->request.data;
+
+	ptr += strlen("sysrq");
+	while(isspace(*ptr)) ptr++;
+
+	handle_sysrq(*ptr, &current->thread.regs, NULL, NULL);
+	mconsole_reply(req, "", 0, 0);
+}
+#else
+void mconsole_sysrq(struct mc_request *req)
+{
+	mconsole_reply(req, "Sysrq not compiled in", 1, 0);
+}
+#endif
+
+static char *notify_socket = NULL;
+
+int mconsole_init(void)
+{
+	int err;
+	int sock;
+
+	sock = mconsole_create_listening_socket();
+	if (sock < 0) {
+		printk("Failed to initialize management console\n");
+		return 1;
+	}
+
+	register_reboot_notifier(&reboot_notifier);
+
+	err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
+			     SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
+			     "mconsole", (void *)sock);
+	if (err) {
+		printk("Failed to get IRQ for management console\n");
+		return 1;
+	}
+
+	if(notify_socket != NULL){
+		notify_socket = uml_strdup(notify_socket);
+		if(notify_socket != NULL)
+			mconsole_open_for_business(notify_socket);
+		else printk(KERN_ERR "mconsole_setup failed to strdup "
+			    "string\n");
+	}
+
+	printk("mconsole initialized on %s\n", mconsole_socket_name);
+	return 0;
+}
+
+__initcall(mconsole_init);
+
+#define NOTIFY "=notify:"
+
+static int mconsole_setup(char *str)
+{
+	if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
+		str += strlen(NOTIFY);
+		notify_socket = str;
+	}
+	else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
+	return(1);
+}
+
+__setup("mconsole", mconsole_setup);
+
+__uml_help(mconsole_setup,
+"mconsole=notify:<socket>\n"
+"    Requests that the mconsole driver send a message to the named Unix\n"
+"    socket containing the name of the mconsole socket.  This also serves\n"
+"    to notify outside processes when UML has booted far enough to respond\n"
+"    to mconsole requests.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mconsole_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/mconsole_user.c
--- linux/arch/um/drivers/mconsole_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mconsole_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include "user.h"
+#include "mconsole.h"
+#include "umid.h"
+
+static struct mconsole_command commands[] = {
+	{ "version", mconsole_version, 1 },
+	{ "halt", mconsole_halt, 0 },
+	{ "reboot", mconsole_reboot, 0 },
+	{ "config", mconsole_config, 0 },
+	{ "remove", mconsole_remove, 0 },
+	{ "sysrq", mconsole_sysrq, 1 },
+	{ "help", mconsole_help, 1 },
+	{ "cad", mconsole_cad, 1 },
+};
+
+char mconsole_socket_name[256];
+
+int mconsole_reply_v0(struct mc_request *req, char *reply)
+{
+        struct iovec iov;
+        struct msghdr msg;
+
+        iov.iov_base = reply;
+        iov.iov_len = strlen(reply);
+
+        msg.msg_name = &(req->origin);
+        msg.msg_namelen = req->originlen;
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_control = NULL;
+        msg.msg_controllen = 0;
+        msg.msg_flags = 0;
+
+        return sendmsg(req->originating_fd, &msg, 0);
+}
+
+static struct mconsole_command *mconsole_parse(struct mc_request *req)
+{
+	struct mconsole_command *cmd;
+	int i;
+
+	for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
+		cmd = &commands[i];
+		if(!strncmp(req->request.data, cmd->command, 
+			    strlen(cmd->command))){
+			return(cmd);
+		}
+	}
+	return(NULL);
+}
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+
+#define STRINGX(x) #x
+#define STRING(x) STRINGX(x)
+
+int mconsole_get_request(int fd, struct mc_request *req)
+{
+	int len;
+
+	req->originlen = sizeof(req->origin);
+	req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
+			    (struct sockaddr *) req->origin, &req->originlen);
+	if (req->len < 0)
+		return 0;
+
+	req->originating_fd = fd;
+
+	if(req->request.magic != MCONSOLE_MAGIC){
+		/* Unversioned request */
+		len = MIN(sizeof(req->request.data) - 1, 
+			  strlen((char *) &req->request));
+		memmove(req->request.data, &req->request, len);
+		req->request.data[len] = '\0';
+
+		req->request.magic = MCONSOLE_MAGIC;
+		req->request.version = 0;
+		req->request.len = len;
+
+		mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
+				  "not supported by this driver");
+		return(0);
+	}
+
+	if(req->request.len >= MCONSOLE_MAX_DATA){
+		mconsole_reply(req, "Request too large", 1, 0);
+		return(0);
+	}
+	if(req->request.version != MCONSOLE_VERSION){
+		mconsole_reply(req, "This driver only supports version " 
+                               STRING(MCONSOLE_VERSION) " clients", 1, 0);
+	}
+	
+	req->request.data[req->request.len] = '\0';
+	req->cmd = mconsole_parse(req);
+	if(req->cmd == NULL){
+		mconsole_reply(req, "Unknown command", 1, 0);
+		return(0);
+	}
+
+	return(1);
+}
+
+int mconsole_reply(struct mc_request *req, char *str, int err, int more)
+{
+	struct mconsole_reply reply;
+	int total, len, n;
+
+	total = strlen(str);
+	do {
+		reply.err = err;
+
+		/* err can only be true on the first packet */
+		err = 0;
+
+		len = MIN(total, MCONSOLE_MAX_DATA - 1);
+
+		if(len == total) reply.more = more;
+		else reply.more = 1;
+
+		memcpy(reply.data, str, len);
+		reply.data[len] = '\0';
+		total -= len;
+		reply.len = len + 1;
+
+		len = sizeof(reply) + reply.len - sizeof(reply.data);
+
+		n = sendto(req->originating_fd, &reply, len, 0,
+			   (struct sockaddr *) req->origin, req->originlen);
+
+		if(n < 0) return(-errno);
+	} while(total > 0);
+	return(0);
+}
+
+int mconsole_unlink_socket(void)
+{
+	unlink(mconsole_socket_name);
+	return 0;
+}
+
+int mconsole_create_listening_socket(void)
+{
+	struct sockaddr_un addr;
+	char file[256];
+	int sock, err, yes = 1;
+
+	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		printk("create_listening_socket - socket failed, errno = %d\n",
+		       errno);
+		return(-1);
+	}
+
+	addr.sun_family = AF_UNIX;
+
+	if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
+
+	strcpy(mconsole_socket_name, file);
+	strcpy(addr.sun_path, file);
+
+	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0) {
+		if (errno != EADDRINUSE) {
+			printk("create_listening_socket - bind failed, "
+			       "errno = %d\n", errno);
+			return(-1);
+		}
+	}
+
+	setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &yes, sizeof(yes));
+
+	return sock;
+}
+
+void mconsole_open_for_business(char *name)
+{
+	struct sockaddr_un addr;
+	int sock, n;
+
+	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if(sock < 0){
+		printk("mconsole_open_for_business - socket failed, "
+		       "errno = %d\n", errno);
+		return;
+	}
+
+	addr.sun_family = AF_UNIX;
+	strcpy(addr.sun_path, name);
+	n = sendto(sock, mconsole_socket_name, strlen(mconsole_socket_name), 
+		   0, (struct sockaddr *) &addr, sizeof(addr));
+	if(n < 0)
+		printk("mconsole_open_for_business - sendto failed, "
+		       "errno = %d\n", errno);
+	close(sock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/mmapper_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/mmapper_kern.c
--- linux/arch/um/drivers/mmapper_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/mmapper_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,146 @@
+/*
+ * arch/um/drivers/mmapper_kern.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ */
+#include <linux/kdev_t.h>
+#include <linux/time.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h> 
+#include <linux/slab.h>
+#include <linux/init.h> 
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/smplock.h>
+#include <asm/pgtable.h>
+#include "mem_user.h"
+#include "user_util.h"
+ 
+static unsigned long mmapper_size;
+static char *p_buf = NULL;
+static char *v_buf = NULL;
+
+static ssize_t
+mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	if(*ppos > mmapper_size)
+		return -EINVAL;
+
+	if(count + *ppos > mmapper_size)
+		count = count + *ppos - mmapper_size;
+
+	if(count < 0)
+		return -EINVAL;
+ 
+	copy_to_user(buf,&v_buf[*ppos],count);
+	
+	return count;
+}
+
+static ssize_t
+mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	if(*ppos > mmapper_size)
+		return -EINVAL;
+
+	if(count + *ppos > mmapper_size)
+		count = count + *ppos - mmapper_size;
+
+	if(count < 0)
+		return -EINVAL;
+
+	copy_from_user(&v_buf[*ppos],buf,count);
+	
+	return count;
+}
+
+static int 
+mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	 unsigned long arg)
+{
+	return(-ENOIOCTLCMD);
+}
+
+static int 
+mmapper_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	int ret = -EINVAL;
+	int size;
+
+	lock_kernel();
+	if (vma->vm_pgoff != 0)
+		goto out;
+	
+	size = vma->vm_end - vma->vm_start;
+
+	/* XXX A comment above remap_page_range says it should only be
+	 * called when the mm semaphore is held
+	 */
+	if (remap_page_range(vma->vm_start, (unsigned long) p_buf,
+			     size, vma->vm_page_prot))
+		goto out;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static int
+mmapper_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int 
+mmapper_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations mmapper_fops = {
+	owner:		THIS_MODULE,
+	read:		mmapper_read,
+	write:		mmapper_write,
+	ioctl:		mmapper_ioctl,
+	mmap:		mmapper_mmap,
+	open:		mmapper_open,
+	release:	mmapper_release,
+};
+
+static int __init mmapper_init(void)
+{
+	printk(KERN_INFO "Mapper v0.1\n");
+
+	p_buf = (char *) find_iomem("mmapper", &mmapper_size);
+
+	v_buf = p_buf;
+
+	devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, 
+			30, 0, S_IFCHR | S_IRUGO | S_IWUGO, 
+			&mmapper_fops, NULL); 
+	devfs_mk_symlink(NULL, "mmapper", DEVFS_FL_DEFAULT, "mmapper0",
+			 NULL, NULL);
+	return(0);
+}
+
+static void mmapper_exit(void)
+{
+}
+
+module_init(mmapper_init);
+module_exit(mmapper_exit);
+
+MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
+MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/net_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/net_kern.c
--- linux/arch/um/drivers/net_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/net_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/netdevice.h"
+#include "linux/skbuff.h"
+#include "linux/socket.h"
+#include "linux/spinlock.h"
+#include "linux/module.h"
+#include "linux/init.h"
+#include "linux/etherdevice.h"
+#include "linux/list.h"
+#include "linux/inetdevice.h"
+#include "linux/ctype.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "slip.h"
+#include "slip_kern.h"
+#include "etap.h"
+#include "etap_kern.h"
+#include "tuntap.h"
+#include "tuntap_kern.h"
+#include "daemon.h"
+#include "daemon_kern.h"
+#include "mcast.h"
+#include "mcast_kern.h"
+#include "mconsole_kern.h"
+#include "init.h"
+#include "irq_user.h"
+
+LIST_HEAD(opened);
+
+struct uml_net devices[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] = 
+	{
+		dev:		NULL,
+		user:		NULL,
+		kern:		NULL,
+		private_size:	0,
+	}
+};
+
+static int eth_setup_common(char *str, int *index_out)
+{
+	char *end;
+	int n;
+
+	n = simple_strtoul(str, &end, 0);
+	if(end == str){
+		printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
+		return(1);
+	}
+	if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){
+		printk(KERN_ERR "eth_setup: device %d out of range\n", n);
+		return(1);
+	}
+	str = end;
+	if(*str != '='){
+		printk(KERN_ERR 
+		       "eth_setup: expected '=' after device number\n");
+		return(1);
+	}
+	str++;
+	if(devices[n].dev != NULL){
+		printk(KERN_ERR "eth_setup: Device %d already configured\n",
+		       n);
+		return(1);
+	}
+	if(index_out) *index_out = n;
+#ifdef CONFIG_UML_NET_ETHERTAP
+	if(!strncmp(str, "ethertap", strlen("ethertap"))){
+		ethertap_setup(&str[strlen("ethertap")], &devices[n]);
+		return(0);
+	}
+#endif
+#ifdef CONFIG_UML_NET_TUNTAP
+	if(!strncmp(str, "tuntap", strlen("tuntap"))){
+		tuntap_setup(&str[strlen("tuntap")], &devices[n]);
+		return(0);
+	}
+#endif
+#ifdef CONFIG_UML_NET_DAEMON
+	if(!strncmp(str, "daemon", strlen("daemon"))){
+		daemon_setup(&str[strlen("daemon")], &devices[n]);
+		return(0);
+	}
+#endif
+#ifdef CONFIG_UML_NET_SLIP
+	if(!strncmp(str, "slip", strlen("slip"))){
+		slip_setup(&str[strlen("slip")], &devices[n]);
+		return(0);
+	}
+#endif
+#ifdef CONFIG_UML_NET_MCAST
+	if(!strncmp(str, "mcast", strlen("mcast"))){
+		mcast_setup(&str[strlen("mcast")], &devices[n]);
+		return(0);
+	}
+#endif
+	printk(KERN_ERR "Unknown transport in eth_setup : %s\n", str);
+	return(1);
+}
+
+static int eth_setup(char *str)
+{
+	eth_setup_common(str, NULL);
+	return(1);
+}
+
+#ifdef CONFIG_UML_NET_ETHERTAP
+#define UML_NET_ETHERTAP_HELP	\
+"    eth[0-9]+=ethertap,<device>,<ethernet address>,<tap ip address>\n" \
+"    eth0=ethertap,tap0,,192.168.0.1\n\n"
+#else
+#define UML_NET_ETHERTAP_HELP
+#endif
+#ifdef CONFIG_UML_NET_TUNTAP
+#define UML_NET_TUNTAP_HELP \
+"    eth[0-9]+=tuntap,,<ethernet address>,<ip address>\n" \
+"    eth0=tuntap,,fe:fd:0:0:0:1,192.168.0.1\n\n"
+#else
+#define UML_NET_TUNTAP_HELP
+#endif
+#ifdef CONFIG_UML_NET_DAEMON
+#define UML_NET_DAEMON_HELP \
+"    eth[0-9]+=daemon,<ethernet address>,<type>,<control socket>,<data socket>\n" \
+"    eth0=daemon,unix,/tmp/uml.ctl,/tmp/uml.data\n\n"
+#else
+#define UML_NET_DAEMON_HELP
+#endif
+#ifdef CONFIG_UML_NET_SLIP
+#define UML_NET_SLIP_HELP \
+"    eth[0-9]+=slip,<slip ip>\n" \
+"    eth0=slip,192.168.0.1\n\n"
+#else
+#define UML_NET_SLIP_HELP
+#endif
+#ifdef CONFIG_UML_NET_MCAST
+#define UML_NET_MCAST_HELP \
+"    eth[0-9]+=mcast,<ethernet address>,<address>,<port>,<ttl>\n" \
+"    eth0=mcast,,224.2.3.4:5555,3\n\n"
+#else
+#define UML_NET_MCAST_HELP
+#endif
+
+__setup("eth", eth_setup);
+__uml_help(eth_setup,
+"eth[0-9]+=<transport>,<options>\n"
+"    Configure a network device.  Formats and examples follow (one \n"
+"    for each configured transport).\n\n"
+UML_NET_ETHERTAP_HELP
+UML_NET_TUNTAP_HELP
+UML_NET_DAEMON_HELP
+UML_NET_SLIP_HELP
+UML_NET_MCAST_HELP
+);
+int ndev = 0;
+
+static int uml_net_rx(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	int pkt_len;
+	struct sk_buff *skb;
+
+	/* If we can't allocate memory, try again next round. */
+	if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
+		lp->stats.rx_dropped++;
+		reactivate_fd(lp->fd, UM_ETH_IRQ);
+		return 0;
+	}
+
+	skb->dev = dev;
+	skb_put(skb, dev->mtu);
+	skb->mac.raw = skb->data;
+	pkt_len = (*lp->read)(lp->fd, &skb, lp);
+
+	reactivate_fd(lp->fd, UM_ETH_IRQ);
+	if (pkt_len > 0) {
+		skb_trim(skb, pkt_len);
+		skb->protocol = (*lp->protocol)(skb);
+		netif_rx(skb);
+
+		lp->stats.rx_bytes += skb->len;
+		lp->stats.rx_packets++;
+		return pkt_len;
+	}
+
+	kfree_skb(skb);
+	return pkt_len;
+}
+
+void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct uml_net_private *lp = dev->priv;
+	int err;
+
+	if (netif_running(dev)) {
+		spin_lock(&lp->lock);
+		while((err = uml_net_rx(dev)) > 0) ;
+		if(err < 0) {
+			printk(KERN_ERR 
+			       "Device '%s' read returned %d, shutting it "
+			       "down\n", dev->name, err);
+			dev->flags &= ~IFF_UP;
+			dev_close(dev);
+		}
+		spin_unlock(&lp->lock);
+	}
+}
+
+static int uml_net_open(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	int err;
+
+	spin_lock(&lp->lock);
+
+	if(lp->fd >= 0){
+		err = -ENXIO;
+		goto out;
+	}
+
+	lp->fd = (*lp->open)(&lp->user);
+	if(lp->fd < 0){
+		err = lp->fd;
+		goto out;
+	}
+
+	err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
+			     SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
+	if(err != 0){
+		printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
+		(*lp->close)(lp->fd, &lp->user);
+		lp->fd = -1;
+		err = -ENETUNREACH;
+	}
+
+	lp->tl.data = (unsigned long) &lp->user;
+	netif_start_queue(dev);
+
+	list_add(&lp->list, &opened);
+	MOD_INC_USE_COUNT;
+ out:
+	spin_unlock(&lp->lock);
+	return(err);
+}
+
+static int uml_net_close(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	
+	netif_stop_queue(dev);
+	spin_lock(&lp->lock);
+
+	free_irq(dev->irq, dev);
+	(*lp->close)(lp->fd, &lp->user);
+	lp->fd = -1;
+	list_del(&lp->list);
+	
+	MOD_DEC_USE_COUNT;
+	spin_unlock(&lp->lock);
+	return 0;
+}
+
+static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	unsigned long flags;
+	int len;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	len = (*lp->write)(lp->fd, &skb, lp);
+
+	if(len == skb->len) {
+		lp->stats.tx_packets++;
+		lp->stats.tx_bytes += skb->len;
+		dev->trans_start = jiffies;
+		netif_start_queue(dev);
+
+		/* this is normally done in the interrupt when tx finishes */
+		netif_wake_queue(dev);
+	} 
+	else if(len == 0){
+		netif_start_queue(dev);
+		lp->stats.tx_dropped++;
+	}
+	else {
+		netif_start_queue(dev);
+		printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
+	}
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	return &lp->stats;
+}
+
+static void uml_net_set_multicast_list(struct net_device *dev)
+{
+	if (dev->flags & IFF_PROMISC) return;
+	else if (dev->mc_count)	dev->flags |= IFF_ALLMULTI;
+	else dev->flags &= ~IFF_ALLMULTI;
+}
+
+static void uml_net_tx_timeout(struct net_device *dev)
+{
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+static int uml_net_set_mac(struct net_device *dev, void *addr)
+{
+	struct uml_net_private *lp = dev->priv;
+	struct sockaddr *hwaddr = addr;
+	int err;
+
+	spin_lock(&lp->lock);
+
+	err = (*lp->set_mac)(hwaddr, &lp->user);
+
+	spin_unlock(&lp->lock);
+
+	return err;
+}
+
+static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct uml_net_private *lp = dev->priv;
+	int err = 0;
+
+	spin_lock(&lp->lock);
+
+	new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
+	if(new_mtu < 0){
+		err = new_mtu;
+		goto out;
+	}
+
+	dev->mtu = new_mtu;
+
+ out:
+	spin_unlock(&lp->lock);
+	return err;
+}
+
+static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return(-EINVAL);
+}
+
+void uml_net_user_timer_expire(unsigned long _conn)
+{
+#ifdef undef
+	struct connection *conn = (struct connection *)_conn;
+
+	dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
+	do_connect(conn);
+#endif
+}
+
+static int eth_configure(struct uml_net *device, int n)
+{
+	struct net_device *dev;
+	struct uml_net_private *lp;
+
+	device->private_size += sizeof(struct uml_net_private) + 
+		sizeof(((struct uml_net_private *) 0)->user);
+	printk(KERN_INFO "Netdevice %d : ", n);
+	dev = (*device->kern->init)(device->private_size,
+				    device->transport_index);
+	device->dev = dev;
+
+	if (dev == NULL){
+		printk(KERN_ERR "eth_configure: Out of memory on device %d\n",
+		       n);
+		return(1);
+	}
+
+	dev->mtu = device->user->max_packet;
+	dev->open = uml_net_open;
+	dev->hard_start_xmit = uml_net_start_xmit;
+	dev->stop = uml_net_close;
+	dev->get_stats = uml_net_get_stats;
+	dev->set_multicast_list = uml_net_set_multicast_list;
+	dev->tx_timeout = uml_net_tx_timeout;
+	dev->set_mac_address = uml_net_set_mac;
+	dev->change_mtu = uml_net_change_mtu;
+	dev->do_ioctl = uml_net_ioctl;
+	dev->watchdog_timeo = (HZ >> 1);
+	dev->irq = UM_ETH_IRQ;
+
+	lp = dev->priv;
+	spin_lock_init(&lp->lock);
+	init_timer(&lp->tl);
+	lp->tl.function = uml_net_user_timer_expire;
+	lp->list = ((struct list_head) LIST_HEAD_INIT(lp->list));
+	memset(&lp->stats, 0, sizeof(lp->stats));
+	lp->fd = -1;
+	lp->protocol = device->kern->protocol;
+	lp->set_mac = device->kern->set_mac;
+	lp->open = device->user->open;
+	lp->close = device->user->close;
+	lp->read = device->kern->read;
+	lp->write = device->kern->write;
+	lp->add_address = device->user->add_address;
+	lp->delete_address = device->user->delete_address;
+	lp->set_mtu = device->user->set_mtu;
+		
+	if(device->user->init) 
+		(*device->user->init)(&lp->user, dev);
+	return(0);
+}
+
+int __init uml_net_probe(void)
+{
+	int i;
+
+	for(i = 0; i < sizeof(devices)/sizeof(devices[0]); i++){
+		if(devices[i].user == NULL) continue;
+		eth_configure(&devices[i], i);
+	}
+	return(0);
+}
+
+static int net_config(char *str)
+{
+	int err, n;
+
+	str = uml_strdup(str);
+	if(str == NULL){
+		printk(KERN_ERR "net_config failed to strdup string\n");
+		return(1);
+	}
+	err = eth_setup_common(str, &n);
+	if(err){
+		kfree(str);
+		return(err);
+	}
+	err = eth_configure(&devices[n], n);
+	return(err);
+}
+
+static int net_remove(char *str)
+{
+	struct net_device *dev;
+	struct uml_net_private *lp;
+	int n;
+
+	if(!isdigit(*str)) return(-1);
+	n = *str - '0';
+	if(devices[n].dev == NULL) return(0);
+	dev = devices[n].dev;
+	lp = dev->priv;
+	if(lp->fd > 0) return(-1);
+	unregister_netdev(dev);
+	devices[n].dev = NULL;
+	return(0);
+}
+
+static struct mc_device net_mc = {
+	name:		"eth",
+	config:		net_config,
+	remove:		net_remove,
+};
+
+static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
+			      void *ptr)
+{
+	struct in_ifaddr *ifa = ptr;
+	u32 addr = ifa->ifa_address;
+	u32 netmask = ifa->ifa_mask;
+	struct net_device *dev = ifa->ifa_dev->dev;
+	struct uml_net_private *lp;
+	void (*proc)(unsigned char *, unsigned char *, void *);
+	unsigned char addr_buf[4], netmask_buf[4];
+
+	if(dev->open != uml_net_open) return(NOTIFY_DONE);
+
+	lp = dev->priv;
+
+	proc = NULL;
+	switch (event){
+	case NETDEV_UP:
+		proc = lp->add_address;
+		break;
+	case NETDEV_DOWN:
+		proc = lp->delete_address;
+		break;
+	}
+	if(proc != NULL){
+		addr_buf[0] = addr & 0xff;
+		addr_buf[1] = (addr >> 8) & 0xff;
+		addr_buf[2] = (addr >> 16) & 0xff;
+		addr_buf[3] = addr >> 24;
+		netmask_buf[0] = netmask & 0xff;
+		netmask_buf[1] = (netmask >> 8) & 0xff;
+		netmask_buf[2] = (netmask >> 16) & 0xff;
+		netmask_buf[3] = netmask >> 24;
+		(*proc)(addr_buf, netmask_buf, &lp->user);
+	}
+	return(NOTIFY_DONE);
+}
+
+struct notifier_block uml_inetaddr_notifier = {
+	notifier_call:		uml_inetaddr_event,
+};
+
+static int uml_net_init(void)
+{
+	mconsole_register_dev(&net_mc);
+	register_inetaddr_notifier(&uml_inetaddr_notifier);
+	return(0);
+}
+
+__initcall(uml_net_init);
+
+static void close_devices(void)
+{
+	struct list_head *ele;
+	struct uml_net_private *lp;	
+
+	list_for_each(ele, &opened){
+		lp = list_entry(ele, struct uml_net_private, list);
+		(*lp->close)(lp->fd, &lp->user);
+	}
+}
+
+__uml_exitcall(close_devices);
+
+int setup_etheraddr(char *str, unsigned char *addr)
+{
+	char *end;
+	int i;
+
+	for(i=0;i<6;i++){
+		addr[i] = simple_strtoul(str, &end, 16);
+		if((end == str) ||
+		   ((*end != ':') && (*end != ',') && (*end != '\0'))){
+			printk(KERN_ERR 
+			       "setup_etheraddr: failed to parse '%s' "
+			       "as an ethernet address\n", str);
+			return(-1);
+		}
+		str = end + 1;
+	}
+	if(addr[0] & 1){
+		printk(KERN_ERR 
+		       "Attempt to assign a broadcast ethernet address to a "
+		       "device disallowed\n");
+		return(-1);
+	}
+	return(0);
+}
+
+void dev_ip_addr(void *d, char *buf, char *bin_buf)
+{
+	struct net_device *dev = d;
+	struct in_device *ip = dev->ip_ptr;
+	struct in_ifaddr *in;
+	u32 addr;
+
+	if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
+		printk(KERN_WARNING "dev_ip_addr - device not assigned an "
+		       "IP address\n");
+		return;
+	}
+	addr = in->ifa_address;
+	sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, 
+		(addr >> 16) & 0xff, addr >> 24);
+	if(bin_buf){
+		bin_buf[0] = addr & 0xff;
+		bin_buf[1] = (addr >> 8) & 0xff;
+		bin_buf[2] = (addr >> 16) & 0xff;
+		bin_buf[3] = addr >> 24;
+	}
+}
+
+void set_ether_mac(void *d, unsigned char *addr)
+{
+	struct net_device *dev = d;
+
+	memcpy(dev->dev_addr, addr, ETH_ALEN);	
+}
+
+struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
+{
+	if((skb != NULL) && (skb_tailroom(skb) < extra)){
+	  	struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
+		dev_kfree_skb(skb);
+		skb = skb2;
+	}
+	if(skb != NULL) skb_put(skb, extra);
+	return(skb);
+}
+
+void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, 
+					void *), 
+		    void *arg)
+{
+	struct net_device *dev = d;
+	struct in_device *ip = dev->ip_ptr;
+	struct in_ifaddr *in;
+	unsigned char address[4], netmask[4];
+
+	if(ip == NULL) return;
+	in = ip->ifa_list;
+	while(in != NULL){
+		address[0] = in->ifa_address & 0xff;
+		address[1] = (in->ifa_address >> 8) & 0xff;
+		address[2] = (in->ifa_address >> 16) & 0xff;
+		address[3] = in->ifa_address >> 24;
+		netmask[0] = in->ifa_mask & 0xff;
+		netmask[1] = (in->ifa_mask >> 8) & 0xff;
+		netmask[2] = (in->ifa_mask >> 16) & 0xff;
+		netmask[3] = in->ifa_mask >> 24;
+		(*cb)(address, netmask, arg);
+		in = in->ifa_next;
+	}
+}
+
+void *get_output_buffer(int *len_out)
+{
+	void *ret;
+
+	ret = (void *) __get_free_pages(GFP_KERNEL, 0);
+	if(ret) *len_out = PAGE_SIZE;
+	else *len_out = 0;
+	return(ret);
+}
+
+void free_output_buffer(void *buffer)
+{
+	free_pages((unsigned long) buffer, 0);
+}
+
+void tap_setup_common(char *str, char *type, char **dev_name, char *hw_addr, 
+		      int *hw_setup, char **gate_addr)
+{
+	int err;
+
+	if(*str != ','){
+		printk(KERN_ERR 
+		       "ethertap_setup: expected ',' after '%s'\n", type);
+		return;
+	}
+	str++;
+	if(*str != ',') *dev_name = str;
+	str = strchr(str, ',');
+	if(str == NULL) return;
+	*str++ = '\0';
+	if(*str != ','){
+		err = setup_etheraddr(str, hw_addr);
+		if(!err) *hw_setup = 1;
+	}
+	str = strchr(str, ',');
+	if(str == NULL) return;
+	*str++ = '\0';
+	if(*str != '\0') *gate_addr = str;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/net_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/net_kern.h
--- linux/arch/um/drivers/net_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/net_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,66 @@
+#ifndef __UM_NET_KERN_H
+#define __UM_NET_KERN_H
+
+#include "linux/netdevice.h"
+#include "linux/skbuff.h"
+#include "linux/socket.h"
+#include "linux/list.h"
+
+#define MAX_UML_NETDEV (16)
+
+struct uml_net {
+	struct net_device *dev;
+	struct net_user_info *user;
+	struct net_kern_info *kern;
+	int private_size;
+	int transport_index;
+};
+
+struct uml_net_private {
+	spinlock_t lock;
+	
+	struct timer_list tl;
+	struct list_head list;
+	struct net_device_stats stats;
+	int fd;
+	unsigned short (*protocol)(struct sk_buff *);
+	int (*set_mac)(struct sockaddr *hwaddr, void *);
+	int (*open)(void *);
+	void (*close)(int, void *);
+	int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
+	int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
+	
+	void (*add_address)(unsigned char *, unsigned char *, void *);
+	void (*delete_address)(unsigned char *, unsigned char *, void *);
+	int (*set_mtu)(int mtu, void *);
+	int user[1];
+};
+
+struct net_kern_info {
+	struct net_device *(*init)(int, int);
+	unsigned short (*protocol)(struct sk_buff *);
+	int (*set_mac)(struct sockaddr *hwaddr, void *);
+	int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
+	int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
+};
+
+extern struct net_device *ether_init(int);
+extern unsigned short ether_protocol(struct sk_buff *);
+extern int ether_set_mac(struct sockaddr *hwaddr, void *);
+extern int setup_etheraddr(char *str, unsigned char *addr);
+extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
+extern void tap_setup_common(char *str, char *type, char **dev_name, 
+			     char *hw_addr, int *hw_setup, char **gate_addr);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/net_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/net_user.c
--- linux/arch/um/drivers/net_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/net_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,232 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "net_user.h"
+
+int tap_open_common(void *dev, int hw_setup, char *gate_addr)
+{
+	int tap_addr[4];
+
+	if(gate_addr == NULL) return(0);
+	if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
+		  &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
+		printk("Invalid tap IP address - '%s'\n", 
+		       gate_addr);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+void tap_check_mac(int *setup, char *mac, char *gate_addr, char *eth_addr,
+		   void *dev)
+{
+	int tap_addr[4];
+
+	if(*setup) return;
+	if((gate_addr != NULL) && 
+	   (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
+		   &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
+	   (eth_addr[0] == tap_addr[0]) && 
+	   (eth_addr[1] == tap_addr[1]) && 
+	   (eth_addr[2] == tap_addr[2]) && 
+	   (eth_addr[3] == tap_addr[3])){
+		printk("The tap IP address and the UML eth IP address"
+		       " must be different\n");
+	}
+	memcpy(&mac[2], eth_addr, 4);
+	set_ether_mac(dev, mac);
+	*setup = 1;
+}
+
+void read_output(int fd, char *output, int len)
+{
+	int remain, n, actual;
+	char c;
+
+	if(output == NULL){
+		output = &c;
+		len = sizeof(c);
+	}
+		
+	*output = '\0';
+	if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){
+		printk("read_output - read of length failed, errno = %d\n",
+		       errno);
+		return;
+	}
+
+	while(remain != 0){
+		n = (remain < len) ? remain : len;
+		actual = read(fd, output, n);
+		if(actual != n){
+			printk("read_output - read of data failed, "
+			       "errno = %d\n", errno);
+			return;
+		}
+		remain -= actual;
+	}
+	return;
+}
+
+int net_read(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = read(fd,  buf,  len)) < 0) && (errno == EINTR)) ;
+
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);
+}
+
+int net_recvfrom(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = recvfrom(fd,  buf,  len, 0, NULL, NULL)) < 0) && 
+	      (errno == EINTR)) ;
+
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);
+}
+
+int net_write(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+int net_send(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
+{
+	int n;
+
+	while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
+			   sock_len)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+struct change_data {
+	char *dev;
+	char *what;
+	char *address;
+	char *netmask;
+	int output_len;
+	char *output;
+};
+
+static void change_tramp(void *arg)
+{
+	int pid, fds[2];
+	struct change_data *data = arg;
+	char version[sizeof("nnnnn\0")];
+	char *argv[] = { "uml_net", version, data->what, data->dev, 
+			 data->address, data->netmask, NULL };
+
+	sprintf(version, "%d", UML_NET_VERSION);
+	if(pipe(fds) < 0){
+		printk("change_tramp - pipe failed, errno = %d\n",
+		       errno);
+		return;
+	}
+	if((pid = fork()) == 0){
+		dup2(fds[1], 1);
+		close(fds[0]);
+		execvp(argv[0], argv);
+		printk("Exec of '%s' failed - errno = %d\n", argv[0], errno);
+		exit(1);		
+	}
+	close(fds[1]);
+	read_output(fds[0], data->output, data->output_len);
+	waitpid(pid, NULL, 0);
+}
+
+static void change(char *dev, char *what, unsigned char *addr,
+		   unsigned char *netmask)
+{
+	char addr_buf[sizeof("255.255.255.255\0")];
+	char netmask_buf[sizeof("255.255.255.255\0")];
+	struct change_data data;
+
+	data.dev = dev;
+	data.what = what;
+	sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
+	sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 
+		netmask[2], netmask[3]);
+	data.address = addr_buf;
+	data.netmask = netmask_buf;
+	data.output_len = page_size();
+	data.output = um_kmalloc(data.output_len);
+	if(data.output == NULL)
+		printk("change : failed to allocate output buffer\n");
+	tracing_cb(change_tramp, &data);
+	if(data.output != NULL){
+		printk("%s", data.output);
+		kfree(data.output);
+	}
+}
+
+void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
+{
+	change(arg, "add", addr, netmask);
+}
+
+void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
+{
+	change(arg, "del", addr, netmask);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/net_user.h linux-2.4.19-pre5-mjc/arch/um/drivers/net_user.h
--- linux/arch/um/drivers/net_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/net_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,57 @@
+#ifndef __UM_NET_USER_H__
+#define __UM_NET_USER_H__
+
+#define ETH_ADDR_LEN (6)
+#define ETH_HEADER_ETHERTAP (16)
+#define ETH_HEADER_OTHER (14)
+#define ETH_MAX_PACKET (1500)
+
+#define UML_NET_VERSION (4)
+
+struct net_user_info {
+	void (*init)(void *, void *);
+	int (*open)(void *);
+	void (*close)(int, void *);
+	int (*set_mtu)(int mtu, void *);
+	void (*add_address)(unsigned char *, unsigned char *, void *);
+	void (*delete_address)(unsigned char *, unsigned char *, void *);
+	int max_packet;
+};
+
+extern void ether_user_init(void *data, void *dev);
+extern void dev_ip_addr(void *d, char *buf, char *bin_buf);
+extern void set_ether_mac(void *d, unsigned char *addr);
+extern void iter_addresses(void *d, void (*cb)(unsigned char *, 
+					       unsigned char *, void *), 
+			   void *arg);
+
+extern void *get_output_buffer(int *len_out);
+extern void free_output_buffer(void *buffer);
+
+extern int tap_open_common(void *dev, int hw_setup, char *gate_addr);
+extern void tap_check_mac(int *setup, char *mac, char *gate_addr, 
+			  char *eth_addr, void *dev);
+
+extern void read_output(int fd, char *output_out, int len);
+
+extern int net_read(int fd, void *buf, int len);
+extern int net_recvfrom(int fd, void *buf, int len);
+extern int net_write(int fd, void *buf, int len);
+extern int net_send(int fd, void *buf, int len);
+extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
+
+extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
+extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/null.c linux-2.4.19-pre5-mjc/arch/um/drivers/null.c
--- linux/arch/um/drivers/null.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/null.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,52 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include "chan_user.h"
+
+static int null_chan;
+
+void *null_init(char *str, int device, struct chan_opts *opts)
+{
+	return(&null_chan);
+}
+
+int null_open(int input, int output, int primary, void *d)
+{
+	return(open("/dev/null", O_RDWR));
+}
+
+int null_read(int fd, void *unused)
+{
+	return(-ENODEV);
+}
+
+void null_free(void *data)
+{
+}
+
+struct chan_ops null_ops = {
+	init:		null_init,
+	open:		null_open,
+	close:		generic_close,
+	read:		null_read,
+	write:		generic_write,
+	console_write:	generic_console_write,
+	window_size:	generic_window_size,
+	free:		null_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/port.c linux-2.4.19-pre5-mjc/arch/um/drivers/port.c
--- linux/arch/um/drivers/port.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/port.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,218 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "chan_user.h"
+#include "port.h"
+
+struct port_chan {
+	int fd;
+	int raw;
+	int socket[2];
+	struct termios tt;
+	void *kernel_data;
+};
+
+void *port_init(char *str, int device, struct chan_opts *opts)
+{
+	struct port_chan *data;
+	void *kern_data;
+	char *end;
+	int port;
+
+	if(*str != ':'){
+		printk("port_init : channel type 'port' must specify a "
+		       "port number\n");
+		return(NULL);
+	}
+	str++;
+	port = strtoul(str, &end, 0);
+	if(*end != '\0'){
+		printk("port_init : couldn't parse port '%s'\n", str);
+		return(NULL);
+	}
+
+	if((kern_data = port_data(port)) == NULL) return(NULL);
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct port_chan) { fd : 		-1,
+				      raw : 		opts->raw,
+				      socket : 		{ -1, -1 },
+				      kernel_data :	kern_data });
+	
+	return(data);
+}
+
+int port_open(int input, int output, int primary, void *d)
+{
+	struct port_chan *data = d;
+	int fd;
+
+	fd = port_wait(data->kernel_data, data->socket);
+	if((fd >= 0) && data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	data->fd = fd;
+	return(fd);
+}
+
+void port_close(int fd, void *d)
+{
+	struct port_chan *data = d;
+
+	close(data->fd);
+	shutdown(data->socket[0], SHUT_RDWR);
+	shutdown(data->socket[1], SHUT_RDWR);
+}
+
+int port_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct port_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+void port_free(void *d)
+{
+	struct port_chan *data = d;
+
+	port_kern_free(data->kernel_data);
+	kfree(data);
+}
+
+struct chan_ops port_ops = {
+	init:		port_init,
+	open:		port_open,
+	close:		port_close,
+	read:	        generic_read,
+	write:		generic_write,
+	console_write:	port_console_write,
+	window_size:	generic_window_size,
+	free:		port_free,
+	winch:		1,
+};
+
+int port_listen_fd(int port)
+{
+	struct sockaddr_in addr;
+	int fd;
+
+	fd = socket(PF_INET, SOCK_STREAM, 0);
+	if(fd == -1) return(-errno);
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) 
+		return(-errno);
+  
+	if(listen(fd, 1) < 0) return(-errno);
+
+	return(fd);
+}
+
+struct port_connect_data {
+	int sock_fd;
+	int pipe_fds[2];
+	int err;
+};
+
+void port_connect_tramp(void *d)
+{
+	struct port_connect_data *data = d;
+
+	data->err = 0;
+	if(fork() == 0){
+		dup2(data->sock_fd, 0);
+		dup2(data->sock_fd, 1);
+		dup2(data->sock_fd, 2);
+		close(data->sock_fd);
+		dup2(data->pipe_fds[1], 3);
+		close(data->pipe_fds[1]);
+		execlp("/usr/sbin/in.telnetd", "in.telnetd", "-L", 
+		       "/usr/lib/uml/port-helper", NULL);
+		shutdown(3, SHUT_RDWR);
+		shutdown(data->pipe_fds[0], SHUT_RDWR);
+		data->err = errno;
+		exit(1);
+	}
+}
+
+static int rcv_fd(int fd, struct port_connect_data *data)
+{
+	int new, n;
+	char buf[CMSG_SPACE(sizeof(new))];
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = NULL;
+	msg.msg_iovlen = 0;
+	msg.msg_control = buf;
+	msg.msg_controllen = sizeof(buf);
+	msg.msg_flags = 0;
+
+	n = recvmsg(fd, &msg, 0);
+	if(n < 0){
+		printk("rcv_fd : recvmsg failed - errno = %d\n", errno);
+		return(-1);
+	}
+  
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if(cmsg == NULL){
+		printk("rcv_fd didn't receive anything, error = %d\n", 
+		       data->err);
+		return(-1);
+	}
+	if((cmsg->cmsg_level != SOL_SOCKET) || 
+	   (cmsg->cmsg_type != SCM_RIGHTS)){
+		printk("rcv_fd didn't receive a descriptor\n");
+		return(-1);
+	}
+
+	new = ((int *) CMSG_DATA(cmsg))[0];
+	return(new);
+}
+
+int port_connection(int fd, int *socket)
+{
+	int new;
+	struct port_connect_data data;
+
+	if((new = accept(fd, NULL, 0)) < 0) return(-errno);
+
+	if(socketpair(PF_UNIX, SOCK_DGRAM, 0, socket) < 0) return(-errno);
+
+	data = ((struct port_connect_data)
+		{ sock_fd : 		new,
+		  pipe_fds :		{ socket[0], socket[1] } });
+
+	tracing_cb(port_connect_tramp, &data);
+	return(rcv_fd(socket[0], &data));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/port.h linux-2.4.19-pre5-mjc/arch/um/drivers/port.h
--- linux/arch/um/drivers/port.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/port.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PORT_H__
+#define __PORT_H__
+
+extern void *port_data(int port);
+extern int port_wait(void *data, int *socket_out);
+extern void port_kern_close(void *d);
+extern int port_connection(int fd, int *socket_out);
+extern int port_listen_fd(int port);
+extern void port_read(int fd, void *data);
+extern void port_kern_free(void *d);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/port_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/port_kern.c
--- linux/arch/um/drivers/port_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/port_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,154 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/list.h"
+#include "linux/slab.h"
+#include "linux/irq.h"
+#include "linux/spinlock.h"
+#include "linux/errno.h"
+#include "asm/semaphore.h"
+#include "asm/errno.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "port.h"
+
+struct port_list {
+	struct list_head list;
+	struct semaphore sem;
+	int port;
+	int fd;
+	spinlock_t lock;
+	struct list_head connections;
+};
+
+struct port_dev {
+	struct port_list *port;
+	int fd;
+};
+
+struct connection {
+	struct list_head list;
+	int fd;
+	int socket[2];
+};
+
+struct list_head ports = LIST_HEAD_INIT(ports);
+
+static void port_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct port_list *port = data;
+	struct connection *conn;
+	int fd, socket[2];
+
+	reactivate_fd(port->fd, ACCEPT_IRQ);
+	fd = port_connection(port->fd, socket);
+	if(fd < 0){
+		printk("port_connection returned %d\n", -fd);
+		return;
+	}
+	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
+	if(conn == NULL){
+		printk("port_interrupt : failed to allocate connection\n");
+		close(fd);
+		return;
+	}
+	*conn = ((struct connection) 
+		{ list :	LIST_HEAD_INIT(conn->list),
+		  fd :		fd,
+		  socket : 	{ socket[0], socket[1] } });
+	list_add(&conn->list, &port->connections);
+	up(&port->sem);
+} 
+
+void *port_data(int port_num)
+{
+	struct list_head *ele;
+	struct port_list *port;
+	struct port_dev *dev;
+	int fd;
+
+	list_for_each(ele, &ports){
+		port = list_entry(ele, struct port_list, list);
+		if(port->port == port_num) goto found;
+	}
+	port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
+	if(port == NULL){
+		printk(KERN_ERR "Allocation of port list failed\n");
+		return(NULL);
+	}
+
+	fd = port_listen_fd(port_num);
+	if(fd < 0){
+		printk(KERN_ERR "binding to port %d failed, errno = %d\n",
+		       port_num, -fd);
+		return(NULL);
+	}
+	if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, 
+			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
+			  port)){
+		printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
+		return(NULL);
+	}
+
+	*port = ((struct port_list) 
+		{ list : 	LIST_HEAD_INIT(port->list),
+		  sem :		__SEMAPHORE_INITIALIZER(port->sem, 0),
+		  lock :	SPIN_LOCK_UNLOCKED,
+		  port : 	port_num,
+		  fd : 		fd,
+		  connections :	LIST_HEAD_INIT(port->connections) });
+	list_add(&port->list, &ports);
+
+ found:
+	dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
+	if(dev == NULL){
+		printk(KERN_ERR "Allocation of port device entry failed\n");
+		return(NULL);
+	}
+
+	*dev = ((struct port_dev) 
+		{ port : 	port,
+		  fd :		-1 });
+	return(dev);
+}
+
+int port_wait(void *data, int *socket_out)
+{
+	struct port_dev *dev = data;
+	struct connection *conn;
+
+	if(down_interruptible(&dev->port->sem)) return(-ERESTARTSYS);
+	spin_lock(&dev->port->lock);
+	conn = list_entry(dev->port->connections.next, struct connection, 
+			  list);
+	list_del(&conn->list);
+	spin_unlock(&dev->port->lock);
+
+	dev->fd = conn->fd;
+	socket_out[0] = conn->socket[0];
+	socket_out[1] = conn->socket[1];
+	kfree(conn);
+
+	return(dev->fd);
+}
+
+void port_kern_free(void *d)
+{
+	struct port_dev *dev = d;
+
+	kfree(dev);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/pty.c linux-2.4.19-pre5-mjc/arch/um/drivers/pty.c
--- linux/arch/um/drivers/pty.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/pty.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "chan_user.h"
+#include "user.h"
+#include "user_util.h"
+
+struct pty_chan {
+	void (*announce)(char *dev_name, int dev);
+	int dev;
+	int raw;
+	struct termios tt;
+};
+
+void *pty_chan_init(char *str, int device, struct chan_opts *opts)
+{
+	struct pty_chan *data;
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct pty_chan) { announce : 	opts->announce, 
+				     dev : 		device,
+				     raw : 		opts->raw });
+	return(data);
+}
+
+int pts_open(int input, int output, int primary, void *d)
+{
+	struct pty_chan *data = d;
+	int fd;
+
+	if((fd = get_pty()) < 0){
+		printk("open_pts : Failed to open pts\n");
+		return(-errno);
+	}
+	if(data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	if(data->announce) (*data->announce)(ptsname(fd), data->dev);
+	return(fd);
+}
+
+int pty_open(int input, int output, int primary, void *d)
+{
+	struct pty_chan *data = d;
+	int fd;
+	char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
+
+	fd = getmaster(dev);
+	if(fd < 0) return(-errno);
+	if(data->raw) raw(fd, 0);
+	if(data->announce) (*data->announce)(dev, data->dev);
+	return(fd);
+}
+
+int pty_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct pty_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops pty_ops = {
+	init:		pty_chan_init,
+	open:		pty_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	pty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+struct chan_ops pts_ops = {
+	init:		pty_chan_init,
+	open:		pts_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	pty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/slip.h linux-2.4.19-pre5-mjc/arch/um/drivers/slip.h
--- linux/arch/um/drivers/slip.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/slip.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,34 @@
+#ifndef __UM_SLIP_H
+#define __UM_SLIP_H
+
+#define BUF_SIZE 1500
+
+struct slip_data {
+	void *dev;
+	char name[sizeof("slnnnnn\0")];
+	char *addr;
+	char *gate_addr;
+	int slave;
+	char buf[2 * BUF_SIZE];
+	int pos;
+	int esc;
+};
+
+extern struct net_user_info slip_user_info;
+
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
+extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/slip_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/slip_kern.c
--- linux/arch/um/drivers/slip_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/slip_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,106 @@
+#include "linux/kernel.h"
+#include "linux/stddef.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/if_arp.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "kern.h"
+#include "slip.h"
+#include "slip_kern.h"
+
+struct slip_data slip_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		addr:		NULL,
+		gate_addr:	NULL,
+		slave:		-1,
+		buf: 		{ 0 },
+		pos:		0,
+		esc:		0,
+	}
+};
+
+struct net_device umn_dev;
+
+struct net_device *slip_init(int private_size, int index)
+{
+	struct uml_net_private *private;
+	struct slip_data *spri;
+
+	private = kmalloc(private_size, GFP_KERNEL);
+	if(private == NULL) return(NULL);
+	umn_dev.priv = private;
+	spri = (struct slip_data *) private->user;
+	*spri = slip_priv[index];
+	strncpy(umn_dev.name, "umn", IFNAMSIZ);
+	umn_dev.init = NULL;
+	umn_dev.hard_header_len = 0;
+	umn_dev.addr_len = 4;
+	umn_dev.type = ARPHRD_ETHER;
+	umn_dev.tx_queue_len = 256;
+	umn_dev.flags = IFF_NOARP;
+	if(register_netdev(&umn_dev))
+		printk(KERN_ERR "Couldn't initialize umn\n");
+	printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
+	
+	return(&umn_dev);
+}
+
+static int slip_set_mac(struct sockaddr *hwaddr, void *data)
+{
+	return(0);
+}
+
+static unsigned short slip_protocol(struct sk_buff *skbuff)
+{
+	return(htons(ETH_P_IP));
+}
+
+static int slip_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
+			      (struct slip_data *) &lp->user));
+}
+
+static int slip_write(int fd, struct sk_buff **skb,
+		      struct uml_net_private *lp)
+{
+	return(slip_user_write(fd, (*skb)->data, (*skb)->len, 
+			       (struct slip_data *) &lp->user));
+}
+
+struct net_kern_info slip_kern_info = {
+	init:			slip_init,
+	protocol:		slip_protocol,
+	set_mac:		slip_set_mac,
+	read:			slip_read,
+	write:			slip_write,
+};
+
+static int slip_count = 0;
+
+void slip_setup(char *str, struct uml_net *dev)
+{
+	int n = slip_count;
+
+	dev->user = &slip_user_info;
+	dev->kern = &slip_kern_info;
+	dev->private_size = sizeof(struct slip_data);
+	dev->transport_index = slip_count++;
+	if(*str != ',') return;
+	str++;
+	if(str[0] != '\0') slip_priv[n].gate_addr = str;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/slip_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/slip_kern.h
--- linux/arch/um/drivers/slip_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/slip_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_SLIP_KERN_H
+#define __UM_SLIP_KERN_H
+
+#include "net_kern.h"
+
+extern void slip_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru linux/arch/um/drivers/slip_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/slip_user.c
--- linux/arch/um/drivers/slip_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/slip_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,329 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <sys/termios.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "net_user.h"
+#include "slip.h"
+
+void slip_user_init(void *data, void *dev)
+{
+	struct slip_data *pri = data;
+
+	pri->dev = dev;
+}
+
+static int set_up_tty(int fd)
+{
+	int i;
+	struct termios tios;
+
+	if (tcgetattr(fd, &tios) < 0) {
+		printk("could not get initial terminal attributes\n");
+		return(-1);
+	}
+
+	tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
+	tios.c_iflag = IGNBRK | IGNPAR;
+	tios.c_oflag = 0;
+	tios.c_lflag = 0;
+	for (i = 0; i < NCCS; i++)
+		tios.c_cc[i] = 0;
+	tios.c_cc[VMIN] = 1;
+	tios.c_cc[VTIME] = 0;
+
+	cfsetospeed(&tios, B38400);
+	cfsetispeed(&tios, B38400);
+
+	if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+		printk("failed to set terminal attributes\n");
+		return(-1);
+	}
+	return(0);
+}
+
+struct slip_tramp_data {
+	int fd;
+	char **args;
+	int err;
+	int output_len;
+	char *output;
+};
+
+void slip_tramp(void *arg)
+{
+	struct slip_tramp_data *data = arg;
+	char **argv = data->args;
+	int status, pid, fds[2];
+
+	data->err = 0;
+	data->output = NULL;
+	if(pipe(fds) != 0){
+		perror("slip_tramp : pipe failed");
+		data->err = EINVAL;
+		return;
+	}
+	if((pid = fork()) == 0){
+		if(data->fd != -1) dup2(data->fd, 0);
+		dup2(fds[1], 1);
+		close(fds[0]);
+		execvp(argv[0], argv);
+		exit(errno);
+	}
+	else if(pid < 0) data->err = errno;
+	else {
+		close(fds[1]);
+		read_output(fds[0], data->output, data->output_len);
+		if(waitpid(pid, &status, 0) < 0) data->err = errno;
+		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+			printk("'%s' didn't exit with status 0\n", argv[0]);
+			data->err = EINVAL;
+		}
+	}
+}
+
+static int slip_open(void *data)
+{
+	struct slip_data *pri = data;
+	struct slip_tramp_data slip_data;
+	char version_buf[sizeof("nnnnn\0")];
+	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+	char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 
+			 NULL };
+	int sfd, mfd, disc, sencap;
+
+	if((mfd = get_pty()) < 0){
+		printk("umn : Failed to open pty\n");
+		return(-1);
+	}
+	if((sfd = open(ptsname(mfd), O_RDWR)) < 0){
+		printk("Couldn't open tty for slip line\n");
+		return(-1);
+	}
+	if(set_up_tty(sfd)) return(-1);
+	pri->slave = sfd;
+	pri->pos = 0;
+	pri->esc = 0;
+	if(pri->gate_addr != NULL){
+		sprintf(version_buf, "%d", UML_NET_VERSION);
+		slip_data.fd = sfd;
+		strcpy(gate_buf, pri->gate_addr);
+		slip_data.args = argv;
+		slip_data.output_len = page_size();
+		slip_data.output = um_kmalloc(slip_data.output_len);
+		if(slip_data.output == NULL)
+			printk("slip_open : failed to allocate output "
+			       "buffer\n");
+		tracing_cb(slip_tramp, &slip_data);
+		if(slip_data.output != NULL){
+			printk("%s", slip_data.output);
+			kfree(slip_data.output);
+		}
+		if(slip_data.err != 0){
+			printk("slip_tramp failed - errno = %d\n", 
+			       slip_data.err);
+			return(-slip_data.err);
+		}
+		if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){
+			printk("SIOCGIFNAME failed, errno = %d\n", errno);
+			return(-errno);
+		}
+		iter_addresses(pri->dev, open_addr, pri->name);
+	}
+	else {
+		disc = N_SLIP;
+		if(ioctl(sfd, TIOCSETD, &disc) < 0){
+			printk("Failed to set slip line discipline - "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+		sencap = 0;
+		if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
+			printk("Failed to sett slip encapsulation - "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+	}
+	return(mfd);
+}
+
+static void slip_close(int fd, void *data)
+{
+	struct slip_data *pri = data;
+	struct slip_tramp_data slip_data;
+	char version_buf[sizeof("nnnnn\0")];
+	char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 
+			 NULL };
+
+	if(pri->gate_addr != NULL)
+		iter_addresses(pri->dev, close_addr, pri->name);
+
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+	slip_data.fd = -1;
+	slip_data.args = argv;
+	tracing_cb(slip_tramp, &slip_data);
+	if(slip_data.output != NULL){
+		printk("%s", slip_data.output);
+		kfree(slip_data.output);
+	}
+	if(slip_data.err != 0)
+		printk("slip_tramp failed - errno = %d\n", slip_data.err);
+	close(fd);
+	close(pri->slave);
+	pri->slave = -1;
+}
+
+/* SLIP protocol characters. */
+#define END             0300		/* indicates end of frame	*/
+#define ESC             0333		/* indicates byte stuffing	*/
+#define ESC_END         0334		/* ESC ESC_END means END 'data'	*/
+#define ESC_ESC         0335		/* ESC ESC_ESC means ESC 'data'	*/
+
+static int slip_unesc(struct slip_data *sl, unsigned char c)
+{
+	int ret;
+
+	switch(c){
+	case END:
+		sl->esc = 0;
+		ret = sl->pos;
+		sl->pos = 0;
+		return(ret);
+	case ESC:
+		sl->esc = 1;
+		return(0);
+	case ESC_ESC:
+		if(sl->esc){
+			sl->esc = 0;
+			c = ESC;
+		}
+		break;
+	case ESC_END:
+		if(sl->esc){
+			sl->esc = 0;
+			c = END;
+		}
+		break;
+	}
+	sl->buf[sl->pos++] = c;
+	return(0);
+}
+
+int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
+{
+	int i, n, size, start;
+
+	n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos);
+	if(n <= 0) return(n);
+
+	start = pri->pos;
+	for(i = 0; i < n; i++){
+		size = slip_unesc(pri, pri->buf[start + i]);
+		if(size){
+			memcpy(buf, pri->buf, size);
+			return(size);
+		}
+	}
+	return(0);
+}
+
+static int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+	unsigned char *ptr = d;
+	unsigned char c;
+
+	/*
+	 * Send an initial END character to flush out any
+	 * data that may have accumulated in the receiver
+	 * due to line noise.
+	 */
+
+	*ptr++ = END;
+
+	/*
+	 * For each byte in the packet, send the appropriate
+	 * character sequence, according to the SLIP protocol.
+	 */
+
+	while (len-- > 0) {
+		switch(c = *s++) {
+		case END:
+			*ptr++ = ESC;
+			*ptr++ = ESC_END;
+			break;
+		case ESC:
+			*ptr++ = ESC;
+			*ptr++ = ESC_ESC;
+			break;
+		default:
+			*ptr++ = c;
+			break;
+		}
+	}
+	*ptr++ = END;
+	return (ptr - d);
+}
+
+int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
+{
+	int actual, n;
+
+	actual = slip_esc(buf, pri->buf, len);
+	n = net_write(fd, pri->buf, actual);
+	if(n < 0) return(n);
+	else return(len);
+}
+
+static int slip_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
+			  void *data)
+{
+	struct slip_data *pri = data;
+
+	if(pri->slave == -1) return;
+	open_addr(addr, netmask, pri->name);
+}
+
+static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct slip_data *pri = data;
+
+	if(pri->slave == -1) return;
+	close_addr(addr, netmask, pri->name);
+}
+
+struct net_user_info slip_user_info = {
+	init:		slip_user_init,
+	open:		slip_open,
+	close:	 	slip_close,
+	set_mtu:	slip_set_mtu,
+	add_address:	slip_add_addr,
+	delete_address: slip_del_addr,
+	max_packet:	BUF_SIZE
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ssl.c linux-2.4.19-pre5-mjc/arch/um/drivers/ssl.c
--- linux/arch/um/drivers/ssl.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ssl.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,267 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/fs.h"
+#include "linux/tty.h"
+#include "linux/tty_driver.h"
+#include "linux/major.h"
+#include "linux/mm.h"
+#include "linux/init.h"
+#include "linux/devfs_fs_kernel.h"
+#include "asm/termbits.h"
+#include "asm/irq.h"
+#include "line.h"
+#include "ssl.h"
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "init.h"
+#include "irq_user.h"
+#include "2_5compat.h"
+
+static int ssl_version = 1;
+
+static struct tty_driver ssl_driver;
+
+static int ssl_refcount = 0;
+
+#define NR_PORTS 64
+
+static struct tty_struct *ssl_table[NR_PORTS];
+static struct termios *ssl_termios[NR_PORTS];
+static struct termios *ssl_termios_locked[NR_PORTS];
+
+void ssl_announce(char *dev_name, int dev)
+{
+	printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
+	       dev_name);
+}
+
+static struct chan_opts opts = {
+	announce: 	ssl_announce,
+	xterm_title:	"Serial Line #%d",
+	raw:		1,
+};
+
+static struct line serial_lines[NR_PORTS] = 
+	{ [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, SSL_WRITE_IRQ) };
+
+static int setup_ssl_irq(int fd, int input, int output, void *data)
+{
+	int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
+
+	if(input) err = um_request_irq(SSL_IRQ, fd, IRQ_READ, line_interrupt, 
+				       flags, "ssl", data);
+	if(err) return(err);
+	if(output) err = um_request_irq(SSL_WRITE_IRQ, fd, IRQ_WRITE, 
+					line_write_interrupt, flags, "ssl", 
+					data);
+	return(err);
+}
+
+int ssl_open(struct tty_struct *tty, struct file *filp)
+{
+	int line;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		return -ENODEV;
+	return(line_open(serial_lines, line, tty, setup_ssl_irq, &opts));
+}
+
+static void ssl_close(struct tty_struct *tty, struct file * filp)
+{
+	line_close(serial_lines, minor(tty->device) - tty->driver.minor_start,
+		   SSL_IRQ);
+}
+
+static int ssl_write(struct tty_struct * tty, int from_user,
+		     const unsigned char *buf, int count)
+{
+	int line, ret;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		panic("Bad tty in ssl_write");
+	ret = line_write(&serial_lines[line], buf, count);
+	return(ret);
+}
+
+static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	int line;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		panic("Bad tty in ssl_put_char");
+	line_write(&serial_lines[line], &ch, sizeof(ch));
+}
+
+static void ssl_flush_chars(struct tty_struct *tty)
+{
+	return;
+}
+
+static int ssl_chars_in_buffer(struct tty_struct *tty)
+{
+	return(0);
+}
+
+static void ssl_flush_buffer(struct tty_struct *tty)
+{
+	return;
+}
+
+static int ssl_ioctl(struct tty_struct *tty, struct file * file,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret;
+
+	ret = 0;
+	switch(cmd){
+	case TCGETS:
+	case TCSETS:
+	case TCFLSH:
+	case TCSETSF:
+	case TCSETSW:
+	case TCGETA:
+	case TIOCMGET:
+		ret = -ENOIOCTLCMD;
+		break;
+	default:
+		printk(KERN_ERR 
+		       "Unimplemented ioctl in ssl_ioctl : 0x%x\n", cmd);
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	return(ret);
+}
+
+static void ssl_throttle(struct tty_struct * tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_throttle\n");
+}
+
+static void ssl_unthrottle(struct tty_struct * tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
+}
+
+static void ssl_set_termios(struct tty_struct *tty, 
+			    struct termios *old_termios)
+{
+}
+
+static void ssl_stop(struct tty_struct *tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_stop\n");
+}
+
+static void ssl_start(struct tty_struct *tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_start\n");
+}
+
+void ssl_hangup(struct tty_struct *tty)
+{
+}
+
+int ssl_init(void)
+{
+	int i, err;
+
+	printk(KERN_INFO "Initializing software serial port version %d\n", 
+	       ssl_version);
+  
+	/* Initialize the tty_driver structure */
+	
+	memset(&ssl_driver, 0, sizeof(struct tty_driver));
+	ssl_driver.magic = TTY_DRIVER_MAGIC;
+	ssl_driver.name = "tts/%d";
+	ssl_driver.major = TTYAUX_MAJOR;
+	ssl_driver.minor_start = 64;
+	ssl_driver.num = NR_PORTS;
+	ssl_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	ssl_driver.subtype = 0;
+	ssl_driver.init_termios = tty_std_termios;
+	ssl_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	ssl_driver.flags = TTY_DRIVER_REAL_RAW;
+	ssl_driver.refcount = &ssl_refcount;
+	ssl_driver.table = ssl_table;
+	ssl_driver.termios = ssl_termios;
+	ssl_driver.termios_locked = ssl_termios_locked;
+
+	ssl_driver.open = ssl_open;
+	ssl_driver.close = ssl_close;
+	ssl_driver.write = ssl_write;
+	ssl_driver.put_char = ssl_put_char;
+	ssl_driver.flush_chars = ssl_flush_chars;
+	ssl_driver.write_room = line_write_room;
+	ssl_driver.chars_in_buffer = ssl_chars_in_buffer;
+	ssl_driver.flush_buffer = ssl_flush_buffer;
+	ssl_driver.ioctl = ssl_ioctl;
+	ssl_driver.throttle = ssl_throttle;
+	ssl_driver.unthrottle = ssl_unthrottle;
+	ssl_driver.set_termios = ssl_set_termios;
+	ssl_driver.stop = ssl_stop;
+	ssl_driver.start = ssl_start;
+	ssl_driver.hangup = ssl_hangup;
+	if (tty_register_driver(&ssl_driver))
+		panic("Couldn't register ssl driver\n");
+
+	err = devfs_mk_symlink(NULL, "serial", 0, "tts", NULL, NULL);
+	if(err) printk("Symlink creation from /dev/serial to /dev/tts "
+		       "returned %d\n", err);
+
+	for(i = 0; i < sizeof(serial_lines)/sizeof(serial_lines[0]); i++){
+		if(!serial_lines[i].valid) 
+			tty_unregister_devfs(&ssl_driver, 
+					     ssl_driver.minor_start + i);
+	}
+
+	for(i = 0; i < sizeof(serial_lines)/sizeof(serial_lines[0]); i++){
+		INIT_LIST_HEAD(&serial_lines[i].chan_list);
+		sema_init(&serial_lines[i].sem, 1);
+	}
+
+	return(0);
+}
+
+__initcall(ssl_init);
+
+static int ssl_chan_setup(char *str)
+{
+	line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
+		   str);
+	return(1);
+}
+
+__setup("ssl", ssl_chan_setup);
+__channel_help(ssl_chan_setup, "ssl");
+
+static void ssl_exit(void)
+{
+	int i;
+
+	for(i=0;i<sizeof(serial_lines)/sizeof(serial_lines[0]);i++){
+		close_chan(&serial_lines[i].chan_list);
+	}
+}
+
+__uml_exitcall(ssl_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ssl.h linux-2.4.19-pre5-mjc/arch/um/drivers/ssl.h
--- linux/arch/um/drivers/ssl.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ssl.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SSL_H__
+#define __SSL_H__
+
+extern int ssl_read(int fd, int line);
+extern void ssl_receive_char(int line, char ch);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/stdio_console.c linux-2.4.19-pre5-mjc/arch/um/drivers/stdio_console.c
--- linux/arch/um/drivers/stdio_console.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/stdio_console.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,259 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/posix_types.h"
+#include "linux/tty.h"
+#include "linux/tty_flip.h"
+#include "linux/types.h"
+#include "linux/major.h"
+#include "linux/kdev_t.h"
+#include "linux/console.h"
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "linux/list.h"
+#include "linux/init.h"
+#include "linux/interrupt.h"
+#include "linux/devfs_fs_kernel.h"
+#include "asm/current.h"
+#include "asm/softirq.h"
+#include "asm/hardirq.h"
+#include "stdio_console.h"
+#include "line.h"
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+#include "init.h"
+#include "2_5compat.h"
+
+#define MAX_TTYS (8)
+
+static struct tty_driver console_driver;
+static struct tty_struct *console_table[MAX_TTYS];
+static struct termios *console_termios[MAX_TTYS];
+static struct termios *console_termios_locked[MAX_TTYS];
+static int console_refcount;
+
+static struct chan_ops init_console_ops = {
+	init : 		NULL,
+	open : 		NULL,
+	close :		NULL,
+	read : 		NULL,
+	write :		NULL,
+	console_write :	generic_write,
+	window_size :	NULL,
+	free : 		NULL,
+	winch:		0,
+};
+
+static struct chan init_console_chan = {
+	list : 		{ },
+	primary :	1,
+	input :		0,
+	output :	1,
+	opened :	1,
+	fd :		1,
+	pri :		INIT_STATIC,
+	ops :		&init_console_ops,
+	data :		NULL
+};
+
+void stdio_announce(char *dev_name, int dev)
+{
+	printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
+	       dev_name);
+}
+
+static struct chan_opts opts = {
+	announce: 	stdio_announce,
+	xterm_title:	"Virtual Console #%d",
+	raw:		1,
+};
+
+struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, 
+					CONSOLE_WRITE_IRQ),
+			      [ 1 ... MAX_TTYS - 1 ] = 
+			      LINE_INIT(CONFIG_CON_CHAN, CONSOLE_WRITE_IRQ) };
+
+static int setup_console_irq(int fd, int input, int output, void *data)
+{
+	int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
+
+	if(input) err = um_request_irq(CONSOLE_IRQ, fd, IRQ_READ, 
+				       line_interrupt, flags, "console", data);
+	if(err) return(err);
+	if(output) err = um_request_irq(CONSOLE_WRITE_IRQ, fd, IRQ_WRITE, 
+					line_write_interrupt, flags, 
+					"console-write", data);
+	return(err);
+}
+
+static int open_console(int line, struct tty_struct *tty)
+{
+	return(line_open(vts, line, tty, setup_console_irq, &opts));
+}
+
+static int con_open(struct tty_struct * tty, struct file * filp)
+{
+	int line, ret;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	ret = open_console(line, tty);
+	chan_window_size(&vts[line].chan_list, &tty->winsize.ws_row, 
+			 &tty->winsize.ws_col);	
+	return(ret);
+}
+
+static void con_close(struct tty_struct * tty, struct file * filp)
+{
+	line_close(vts, minor(tty->device) - tty->driver.minor_start, 
+		   CONSOLE_IRQ);
+}
+
+static int con_write(struct tty_struct * tty, int from_user, 
+		     const unsigned char *buf, int count)
+{
+	int line, ret;
+
+	if(in_interrupt() && tty->stopped) return 0;
+	while(tty->stopped) schedule();
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	ret = line_write(&vts[line], buf, count);
+	return(ret);
+}
+
+static void set_termios(struct tty_struct *tty, struct termios * old)
+{
+}
+
+static int chars_in_buffer(struct tty_struct *tty)
+{
+	return(0);
+}
+
+int stdio_init(void)
+{
+	int i, err;
+
+	printk(KERN_INFO "Initializing stdio console driver\n");
+	memset(&console_driver, 0, sizeof(struct tty_driver));
+	console_driver.magic = TTY_DRIVER_MAGIC;
+	console_driver.driver_name = "stdio console";
+	console_driver.name = "vc/%d";
+	console_driver.major = TTY_MAJOR;
+	console_driver.minor_start = 0;
+	console_driver.num = MAX_TTYS;
+	console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
+	console_driver.subtype = SYSTEM_TYPE_CONSOLE;
+	console_driver.init_termios = tty_std_termios;
+	console_driver.flags = TTY_DRIVER_REAL_RAW;
+	console_driver.refcount = &console_refcount;
+	console_driver.table = console_table;
+	console_driver.termios = console_termios;
+	console_driver.termios_locked = console_termios_locked;
+
+	console_driver.open = con_open;
+	console_driver.close = con_close;
+	console_driver.write = con_write;
+	console_driver.put_char = NULL;
+	console_driver.flush_chars = NULL;
+	console_driver.write_room = line_write_room;
+	console_driver.chars_in_buffer = chars_in_buffer;
+	console_driver.flush_buffer = NULL;
+	console_driver.ioctl = NULL;
+	console_driver.throttle = NULL;
+	console_driver.unthrottle = NULL;
+	console_driver.send_xchar = NULL;
+	console_driver.set_termios = set_termios;
+	console_driver.stop = NULL;
+	console_driver.start = NULL;
+	console_driver.hangup = NULL;
+	console_driver.break_ctl = NULL;
+	console_driver.wait_until_sent = NULL;
+	console_driver.read_proc = NULL;
+	if (tty_register_driver(&console_driver))
+		panic("Couldn't register console driver\n");
+
+	err = devfs_mk_symlink(NULL, "ttys", 0, "vc", NULL, NULL);
+	if(err) printk("Symlink creation from /dev/ttys to /dev/vc "
+		       "returned %d\n", err);
+
+	for(i = 0; i < sizeof(vts)/sizeof(vts[0]); i++){
+		if(!vts[i].valid) 
+			tty_unregister_devfs(&console_driver, 
+					     console_driver.minor_start + i);
+	}
+
+	for(i = 0; i < sizeof(vts)/sizeof(vts[0]); i++){
+		INIT_LIST_HEAD(&vts[i].chan_list);
+		sema_init(&vts[i].sem, 1);
+	}
+	
+	open_console(0, NULL);
+	return(0);
+}
+
+__initcall(stdio_init);
+
+static void console_write(struct console *console, const char *string, 
+			  unsigned len)
+{
+	console_write_chan(&vts[console->index].chan_list, string, len);
+}
+
+static kdev_t console_device(struct console *c)
+{
+	return mk_kdev(TTY_MAJOR, c->index);
+}
+
+static int console_setup(struct console *co, char *options)
+{
+	return(0);
+}
+
+static struct console stdiocons = INIT_CONSOLE("tty", console_write, 
+					       console_device, console_setup,
+					       CON_PRINTBUFFER);
+
+void stdio_console_init(void)
+{
+	INIT_LIST_HEAD(&vts[0].chan_list);
+	list_add(&init_console_chan.list, &vts[0].chan_list);
+	register_console(&stdiocons);
+}
+
+static int console_chan_setup(char *str)
+{
+	line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
+	return(1);
+}
+
+__setup("con", console_chan_setup);
+__channel_help(console_chan_setup, "con");
+
+static void console_exit(void)
+{
+	int i;
+
+	line_close(vts, 0, CONSOLE_IRQ);
+	for(i=0;i<sizeof(vts)/sizeof(vts[0]);i++){
+		close_chan(&vts[i].chan_list);
+	}
+}
+
+__uml_exitcall(console_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/stdio_console.h linux-2.4.19-pre5-mjc/arch/um/drivers/stdio_console.h
--- linux/arch/um/drivers/stdio_console.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/stdio_console.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,21 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STDIO_CONSOLE_H
+#define __STDIO_CONSOLE_H
+
+extern void save_console_flags(void);
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/tty.c linux-2.4.19-pre5-mjc/arch/um/drivers/tty.c
--- linux/arch/um/drivers/tty.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/tty.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,85 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include "chan_user.h"
+#include "user_util.h"
+#include "user.h"
+
+struct tty_chan {
+	char *dev;
+	int raw;
+	struct termios tt;
+};
+
+void *tty_chan_init(char *str, int device, struct chan_opts *opts)
+{
+	struct tty_chan *data;
+
+	if(*str != ':'){
+		printk("tty_init : channel type 'tty' must specify "
+		       "a device\n");
+		return(NULL);
+	}
+	str++;
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct tty_chan) { dev :	str,
+				     raw :	opts->raw });
+				     
+	return(data);
+}
+
+int tty_open(int input, int output, int primary, void *d)
+{
+	struct tty_chan *data = d;
+	int fd, mode;
+
+	if(input && output) mode = O_RDWR;
+	else if(input) mode = O_RDONLY;
+	else mode = O_WRONLY;
+
+	fd = open(data->dev, mode);
+	if(fd < 0) return(-errno);
+	if(data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	return(fd);
+}
+
+int tty_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct tty_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops tty_ops = {
+	init:		tty_chan_init,
+	open:		tty_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	tty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/tuntap.h linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap.h
--- linux/arch/um/drivers/tuntap.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TUNTAP_H
+#define __UM_TUNTAP_H
+
+#include "net_user.h"
+
+struct tuntap_data {
+	char *dev_name;
+	int fixed_config;
+	char *gate_addr;
+	int fd;
+	void *dev;
+	unsigned char hw_addr[ETH_ADDR_LEN];
+	int hw_setup;
+};
+
+extern struct net_user_info tuntap_user_info;
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/tuntap_kern.c linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_kern.c
--- linux/arch/um/drivers/tuntap_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,123 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/skbuff.h"
+#include "asm/errno.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "tuntap.h"
+
+struct tuntap_setup {
+	char *dev_name;
+	unsigned char hw_addr[ETH_ALEN];
+	int hw_setup;
+	char *gate_addr;
+};
+
+struct tuntap_setup tuntap_priv[MAX_UML_NETDEV] = { 
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		dev_name:	NULL,
+		hw_addr:	{ 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
+		hw_setup:	0,
+		gate_addr:	NULL,
+	}
+};
+
+struct net_device *tuntap_init(int private_size, int index)
+{
+	struct net_device *dev;
+	struct uml_net_private *pri;
+	struct tuntap_data *tpri;
+
+	dev = init_etherdev(NULL, private_size);
+	if(dev == NULL) return(NULL);
+	pri = dev->priv;
+	tpri = (struct tuntap_data *) pri->user;
+	tpri->dev_name = tuntap_priv[index].dev_name;
+	tpri->fixed_config = (tpri->dev_name != NULL);
+	tpri->gate_addr = tuntap_priv[index].gate_addr;
+	memcpy(dev->dev_addr, tuntap_priv[index].hw_addr, ETH_ALEN);
+	memcpy(tpri->hw_addr, tuntap_priv[index].hw_addr, 
+	       sizeof(tpri->hw_addr));
+	printk("TUN/TAP backend - ");
+	if(tpri->gate_addr != NULL) 
+		printk("IP = %s", tpri->gate_addr);
+	tpri->hw_setup = tuntap_priv[index].hw_setup;
+	if(tpri->hw_setup)
+		printk(" ether = %x:%x:%x:%x:%x:%x",
+		       tpri->hw_addr[0], tpri->hw_addr[1], tpri->hw_addr[2],
+		       tpri->hw_addr[3], tpri->hw_addr[4], tpri->hw_addr[5]);
+	printk("\n");
+	tpri->fd = -1;
+	return(dev);
+}
+
+static unsigned short tuntap_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int tuntap_set_mac(struct sockaddr *addr, void *data)
+{
+	struct tuntap_data *pri = data;
+	struct sockaddr *hwaddr = addr;
+
+	memcpy(pri->hw_addr, hwaddr->sa_data, ETH_ALEN);
+
+	return 0;
+}
+
+static int tuntap_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_read(fd, (*skb)->mac.raw, 
+			(*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int tuntap_write(int fd, struct sk_buff **skb, 
+			struct uml_net_private *lp)
+{
+	return(net_write(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info tuntap_kern_info = {
+	init:			tuntap_init,
+	protocol:		tuntap_protocol,
+	set_mac:		tuntap_set_mac,
+	read:			tuntap_read,
+	write: 			tuntap_write,
+};
+
+static int tuntap_count = 0;
+
+void tuntap_setup(char *str, struct uml_net *dev)
+{
+	struct tuntap_setup *pri;
+
+	dev->user = &tuntap_user_info;
+	dev->kern = &tuntap_kern_info;
+	dev->private_size = sizeof(struct tuntap_data);
+	pri = &tuntap_priv[tuntap_count];
+	dev->transport_index = tuntap_count++;
+	tap_setup_common(str, "tuntap", &pri->dev_name, pri->hw_addr,  
+			 &pri->hw_setup, &pri->gate_addr);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/tuntap_kern.h linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_kern.h
--- linux/arch/um/drivers/tuntap_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TUNTAP_KERN_H
+#define __UM_TUNTAP_KERN_H
+
+#include "net_kern.h"
+
+extern void tuntap_setup(char *arg, struct uml_net *dev);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/tuntap_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_user.c
--- linux/arch/um/drivers/tuntap_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/tuntap_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,225 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include "net_user.h"
+#include "tuntap.h"
+#include "kern_util.h"
+#include "user.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void tuntap_user_init(void *data, void *dev)
+{
+	struct tuntap_data *pri = data;
+
+	pri->dev = dev;
+}
+
+struct tuntap_open_data {
+	char *name;
+	char *gate;
+	int data_fd;
+	int remote;
+	int me;
+	int err;
+	char *buffer;
+	int len;
+	int used;
+};
+
+static void tuntap_open_tramp(void *arg)
+{
+	struct tuntap_open_data *data = arg;
+	char version_buf[sizeof("nnnnn\0")];
+	char *args[] = { "uml_net", version_buf, "tuntap", "up", data->gate,
+			 NULL };
+	char buf[CMSG_SPACE(sizeof(data->data_fd))];
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct iovec iov;
+	int pid, n;
+
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+	data->err = 0;
+	if((pid = fork()) == 0){
+		dup2(data->remote, 1);
+		close(data->me);
+		execvp(args[0], args);
+		printk("Exec of '%s' failed - errno = %d\n", args[0], errno);
+		exit(1);		
+	}	
+	else if(pid < 0) data->err = errno;
+	close(data->remote);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	if(data->buffer != NULL){
+		iov = ((struct iovec) { data->buffer, data->len });
+		msg.msg_iov = &iov;
+		msg.msg_iovlen = 1;
+	}
+	else {
+		msg.msg_iov = NULL;
+		msg.msg_iovlen = 0;
+	}
+	msg.msg_control = buf;
+	msg.msg_controllen = sizeof(buf);
+	msg.msg_flags = 0;
+	n = recvmsg(data->me, &msg, 0);
+	data->used = n;
+	if(n < 0){
+		printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
+		       errno);
+		data->err = errno;
+		return;
+	}
+	waitpid(pid, NULL, 0);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if(cmsg == NULL){
+		printk("tuntap_open_tramp : didn't receive a message\n");
+		data->err = EINVAL;
+		return;
+	}
+	if((cmsg->cmsg_level != SOL_SOCKET) || 
+	   (cmsg->cmsg_type != SCM_RIGHTS)){
+		printk("tuntap_open_tramp : didn't receive a descriptor\n");
+		data->err = EINVAL;
+		return;
+	}
+	data->data_fd = ((int *) CMSG_DATA(cmsg))[0];
+}
+
+static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct tuntap_data *pri = data;
+
+	tap_check_mac(&pri->hw_setup, pri->hw_addr, pri->gate_addr, addr, 
+		      pri->dev);
+	if((pri->fd == -1) || pri->fixed_config) return;
+	open_addr(addr, netmask, pri->dev_name);
+}
+
+static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct tuntap_data *pri = data;
+
+	if((pri->fd == -1) || pri->fixed_config) return;
+	close_addr(addr, netmask, pri->dev_name);
+}
+
+static int tuntap_open(void *data)
+{
+	struct ifreq ifr;
+	struct tuntap_data *pri = data;
+	struct tuntap_open_data tap_data;
+	char *output;
+	int err, fds[2];
+
+	err = tap_open_common(pri->dev, pri->hw_setup, pri->gate_addr);
+	if(err) return(err);
+
+	if(pri->fixed_config){
+		if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){
+			printk("Failed to open /dev/net/tun, errno = %d\n",
+			       errno);
+			return(-errno);
+		}
+		memset(&ifr, 0, sizeof(ifr));
+		ifr.ifr_flags = IFF_TAP;
+		strncpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name) - 1);
+		if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
+			printk("TUNSETIFF failed, errno = %d", errno);
+			close(pri->fd);
+			return(-errno);
+		}
+	}
+	else {
+		if(socketpair(PF_UNIX, SOCK_DGRAM, 0, fds) < 0){
+			printk("data socketpair failed - errno = %d\n", errno);
+			return(-errno);
+		}
+
+		tap_data.me = fds[0];
+		tap_data.remote = fds[1];
+		tap_data.data_fd = -1;
+		tap_data.gate = pri->gate_addr;
+		tap_data.buffer = get_output_buffer(&tap_data.len);
+		if(tap_data.buffer != NULL) tap_data.len--;
+		tap_data.used = 0;
+
+		tracing_cb(tuntap_open_tramp, &tap_data);
+		output = tap_data.buffer;
+		if(tap_data.err == 0){
+			pri->dev_name = uml_strdup(tap_data.buffer);
+			output += IFNAMSIZ;
+			printk(output);
+			free_output_buffer(tap_data.buffer);
+		}
+		else {
+			printk(output);
+			free_output_buffer(tap_data.buffer);
+			printk("tuntap_open_tramp failed - errno = %d\n", 
+			       tap_data.err);
+			return(-tap_data.err);
+		}
+		close(fds[0]);
+		pri->fd = tap_data.data_fd;
+		iter_addresses(pri->dev, open_addr, pri->dev_name);
+	}
+
+	return(pri->fd);
+}
+
+static void tuntap_close(int fd, void *data)
+{
+	struct tuntap_data *pri = data;
+
+	if(!pri->fixed_config) 
+		iter_addresses(pri->dev, close_addr, pri->dev_name);
+	close(fd);
+	pri->fd = -1;
+}
+
+static int tuntap_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+struct net_user_info tuntap_user_info = {
+	init:		tuntap_user_init,
+	open:		tuntap_open,
+	close:	 	tuntap_close,
+	set_mtu:	tuntap_set_mtu,
+	add_address:	tuntap_add_addr,
+	delete_address: tuntap_del_addr,
+	max_packet:	MAX_PACKET
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ubd.c linux-2.4.19-pre5-mjc/arch/um/drivers/ubd.c
--- linux/arch/um/drivers/ubd.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ubd.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,834 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#define MAJOR_NR UBD_MAJOR
+#include "linux/config.h"
+#include "linux/blk.h"
+#include "linux/blkdev.h"
+#include "linux/hdreg.h"
+#include "linux/init.h"
+#include "linux/devfs_fs_kernel.h"
+#include "linux/cdrom.h"
+#include "linux/proc_fs.h"
+#include "linux/ctype.h"
+#include "linux/capability.h"
+#include "linux/mm.h"
+#include "linux/vmalloc.h"
+#include "linux/blkpg.h"
+#include "asm/segment.h"
+#include "asm/uaccess.h"
+#include "asm/irq.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mconsole_kern.h"
+#include "init.h"
+#include "irq_user.h"
+#include "ubd_user.h"
+#include "2_5compat.h"
+
+extern __s64 file_size(char *file);
+
+static int ubd_open(struct inode * inode, struct file * filp);
+static int ubd_release(struct inode * inode, struct file * file);
+static int ubd_ioctl(struct inode * inode, struct file * file,
+		     unsigned int cmd, unsigned long arg);
+
+#define MAX_DEV (8)
+
+static int blk_sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = BLOCK_SIZE };
+
+static int hardsect_sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = 512 };
+
+static int sizes[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = 0 };
+
+static struct block_device_operations ubd_blops = {
+        open:		ubd_open,
+        release:	ubd_release,
+        ioctl:		ubd_ioctl,
+};
+
+static struct hd_struct	ubd_part[MAX_DEV] = 
+{ [ 0 ... MAX_DEV - 1 ] = { 0, 0, 0 } };
+
+static request_queue_t *ubd_queue;
+
+static int fake_major = 0;
+
+static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part,
+						 sizes, MAX_DEV, &ubd_blops);
+
+static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part,
+						  sizes, MAX_DEV, &ubd_blops);
+
+#ifdef CONFIG_BLK_DEV_UBD_SYNC
+#define OPEN_FLAGS O_RDWR | O_SYNC
+#else
+#define OPEN_FLAGS O_RDWR
+#endif
+
+static int global_openflags = OPEN_FLAGS;
+
+struct cow {
+	char *file;
+	int fd;
+	unsigned long *bitmap;
+	unsigned long bitmap_len;
+	int bitmap_offset;
+        int data_offset;
+};
+
+struct ubd {
+	char *file;
+	int is_dir;
+	int count;
+	int fd;
+	__u64 size;
+	int boot_openflags;
+	int openflags;
+	devfs_handle_t real;
+	devfs_handle_t fake;
+	struct cow cow;
+};
+
+#define DEFAULT_COW { \
+	file:			NULL, \
+        fd:			-1, \
+        bitmap:			NULL, \
+	bitmap_offset:		0, \
+        data_offset:		0, \
+}
+
+#define DEFAULT_UBD { \
+	file: 			NULL, \
+	is_dir:			0, \
+	count:			0, \
+	fd:			-1, \
+	size:			-1, \
+	boot_openflags:		OPEN_FLAGS, \
+	openflags:		OPEN_FLAGS, \
+	real:			NULL, \
+	fake:			NULL, \
+        cow:			DEFAULT_COW, \
+}
+
+struct ubd ubd_dev[MAX_DEV] = { 
+{ 
+	file: 			"root_fs",
+	is_dir:			0, 
+	count:			0, 
+	fd:			-1, 
+	size:			0, 
+	boot_openflags:		OPEN_FLAGS, 
+	openflags:		OPEN_FLAGS,
+	real:			NULL,
+	fake:			NULL,
+	cow:			DEFAULT_COW,
+}, 
+[ 1 ... MAX_DEV - 1 ] = DEFAULT_UBD
+};
+
+static struct hd_driveid ubd_id = {
+        cyls:		0,
+	heads:		128,
+	sectors:	32,
+};
+
+static int fake_ide = 0;
+static struct proc_dir_entry *proc_ide_root = NULL;
+static struct proc_dir_entry *proc_ide = NULL;
+
+static void make_proc_ide(void)
+{
+	proc_ide_root = proc_mkdir("ide", 0);
+	proc_ide = proc_mkdir("ide0", proc_ide_root);
+}
+
+static int proc_ide_read_media(char *page, char **start, off_t off, int count,
+			       int *eof, void *data)
+{
+	int len;
+
+	strcpy(page, "disk\n");
+	len = strlen("disk\n");
+	len -= off;
+	if (len < count){
+		*eof = 1;
+		if (len <= 0) return 0;
+	}
+	else len = count;
+	*start = page + off;
+	return len;
+	
+}
+
+static void make_ide_entries(char *dev_name)
+{
+	struct proc_dir_entry *dir, *ent;
+	char name[64];
+
+	if(!fake_ide) return;
+	if(proc_ide_root == NULL) make_proc_ide();
+	dir = proc_mkdir(dev_name, proc_ide);
+	ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
+	if(!ent) return;
+	ent->nlink = 1;
+	ent->data = NULL;
+	ent->read_proc = proc_ide_read_media;
+	ent->write_proc = NULL;
+	sprintf(name,"ide0/%s", dev_name);
+	proc_symlink(dev_name, proc_ide_root, name);
+}
+
+static int fake_ide_setup(char *str)
+{
+	fake_ide = 1;
+	return(1);
+}
+
+__setup("fake_ide", fake_ide_setup);
+
+__uml_help(fake_ide_setup,
+"fake_ide\n"
+"    Create ide0 entries that map onto ubd devices.\n\n"
+);
+
+static int ubd_setup_common(char *str, int *index_out)
+{
+	char *backing_file;
+	int n, sync, perm = O_RDWR;
+
+	if(index_out) *index_out = -1;
+	n = *str++;
+	if(n == '='){
+		char *end;
+		int major;
+
+		if(!strcmp(str, "sync")){
+			global_openflags |= O_SYNC;
+			return(0);
+		}
+		major = simple_strtoul(str, &end, 0);
+		if(*end != '\0'){
+			printk(KERN_ERR 
+			       "ubd_setup : didn't parse major number\n");
+			return(1);
+		}
+		fake_gendisk.major = major;
+		fake_major = major;
+		printk(KERN_INFO "Setting extra ubd major number to %d\n",
+		       major);
+		return(0);
+	}
+	if(n < '0'){
+		printk(KERN_ERR "ubd_setup : index out of range\n");
+		return(1);
+	}
+	n -= '0';
+	if(n >= MAX_DEV){
+		printk(KERN_ERR "ubd_setup : index out of range\n");
+		return(1);
+	}
+	if(index_out) *index_out = n;
+	sync = ubd_dev[n].boot_openflags & O_SYNC;
+	if (*str == 'r') {
+		perm = O_RDONLY;
+		str++;
+	}
+	if (*str == 's') {
+		sync = O_SYNC;
+		str++;
+	}
+	if(*str++ != '='){
+		printk(KERN_ERR "ubd_setup : Expected '='\n");
+		return(1);
+	}
+	backing_file = strchr(str, ',');
+	if(backing_file){
+		*backing_file = '\0';
+		backing_file++;
+	}
+	ubd_dev[n].file = str;
+	ubd_dev[n].cow.file = backing_file;
+	ubd_dev[n].boot_openflags = global_openflags | perm | sync;
+	return(0);
+}
+
+static int ubd_setup(char *str)
+{
+	ubd_setup_common(str, NULL);
+	return(1);
+}
+
+__setup("ubd", ubd_setup);
+__uml_help(ubd_setup,
+"ubd<n>=<filename>\n"
+"    This is used to associate a device with a file in the underlying\n"
+"    filesystem. Usually, there is a filesystem in the file, but \n"
+"    that's not required. Swap devices containing swap files can be\n"
+"    specified like this. Also, a file which doesn't contain a\n"
+"    filesystem can have its contents read in the virtual \n"
+"    machine by running dd on the device. n must be in the range\n"
+"    0 to 7. Appending an 'r' to the number will cause that device\n"
+"    to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
+"    an 's' (has to be _after_ 'r', if there is one) will cause data\n"
+"    to be written to disk on the host immediately.\n\n"
+);
+
+static int fakehd(char *str)
+{
+	printk(KERN_INFO 
+	       "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
+	ubd_gendisk.major_name = "hd";
+	return(1);
+}
+
+__setup("fakehd", fakehd);
+__uml_help(fakehd,
+"fakehd\n"
+"    Change the ubd device name to \"hd\".\n\n"
+);
+
+static void do_ubd_request(request_queue_t * q);
+
+int thread_fd = -1;
+
+int intr_count = 0;
+
+static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
+
+static void ubd_finish(int error)
+{
+	int nsect;
+
+	if(error){
+		end_request(0);
+		return;
+	}
+	nsect = CURRENT->current_nr_sectors;
+	CURRENT->sector += nsect;
+	CURRENT->buffer += nsect << 9;
+	CURRENT->errors = 0;
+	CURRENT->nr_sectors -= nsect;
+	CURRENT->current_nr_sectors = 0;
+	end_request(1);
+}
+
+static void ubd_handler(void)
+{
+	struct io_thread_req req;
+	int n;
+
+	DEVICE_INTR = NULL;
+	intr_count++;
+	n = read_ubd_fs(thread_fd, &req, sizeof(req));
+	if(n != sizeof(req)){
+		printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
+		       "errno = %d\n", getpid(), -n);
+		spin_lock(&REQUEST_LOCK);
+		end_request(0);
+		spin_unlock(&REQUEST_LOCK);
+		return;
+	}
+        
+        if((req.offset != ((__u64) (CURRENT->sector)) << 9) ||
+	   (req.length != (CURRENT->current_nr_sectors) << 9))
+		panic("I/O op mismatch");
+	
+	spin_lock(&REQUEST_LOCK);
+	ubd_finish(req.error);
+	reactivate_fd(thread_fd, UBD_IRQ);	
+	do_ubd_request(ubd_queue);
+	spin_unlock(&REQUEST_LOCK);
+}
+
+static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
+{
+	ubd_handler();
+}
+
+static int io_pid = -1;
+
+void kill_io_thread(void)
+{
+	if(io_pid != -1) kill(io_pid, SIGKILL);
+}
+
+__uml_exitcall(kill_io_thread);
+
+int sync = 0;
+
+devfs_handle_t ubd_dir_handle;
+devfs_handle_t ubd_fake_dir_handle;
+
+static int ubd_add(int n)
+{
+	char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
+
+	if(ubd_dev[n].file == NULL) return(-1);
+	sprintf(name, "%d", n);
+	ubd_dev[n].real = devfs_register(ubd_dir_handle, name, 
+					 DEVFS_FL_DEFAULT, MAJOR_NR, n,
+					 S_IFBLK | S_IRUSR | S_IWUSR | 
+					 S_IRGRP |S_IWGRP,
+					 &ubd_blops, NULL);
+	if(fake_major != 0){
+		ubd_dev[n].fake = devfs_register(ubd_fake_dir_handle, name, 
+						 DEVFS_FL_DEFAULT, fake_major,
+						 n, S_IFBLK | S_IRUSR | 
+						 S_IWUSR | S_IRGRP | S_IWGRP,
+						 &ubd_blops, NULL);
+	}
+	if(!strcmp(ubd_gendisk.major_name, "ubd")){
+		sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n);
+	}
+	else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
+		     n + 'a');
+	make_ide_entries(dev_name);
+	return(0);
+}
+
+static int ubd_config(char *str)
+{
+	int n, err;
+
+	str = uml_strdup(str);
+	if(str == NULL){
+		printk(KERN_ERR "ubd_config failed to strdup string\n");
+		return(1);
+	}
+	err = ubd_setup_common(str, &n);
+	if(err){
+		kfree(str);
+		return(-1);
+	}
+	if(n != -1) ubd_add(n);
+	return(0);
+}
+
+static int ubd_remove(char *str)
+{
+	int n;
+
+	if(!isdigit(*str)) return(-1);
+	n = *str - '0';
+	if(ubd_dev[n].file == NULL) return(0);
+	if(ubd_dev[n].count > 0) return(-1);
+	if(ubd_dev[n].real != NULL) devfs_unregister(ubd_dev[n].real);
+	if(ubd_dev[n].fake != NULL) devfs_unregister(ubd_dev[n].fake);
+	ubd_dev[n] = ((struct ubd) DEFAULT_UBD);
+	return(0);
+}
+
+static struct mc_device ubd_mc = {
+	name:		"ubd",
+	config:		ubd_config,
+	remove:		ubd_remove,
+};
+
+int ubd_mc_init(void)
+{
+	mconsole_register_dev(&ubd_mc);
+	return(0);
+}
+
+__initcall(ubd_mc_init);
+
+static request_queue_t *ubd_get_queue(kdev_t device)
+{
+	return(ubd_queue);
+}
+
+int ubd_init(void)
+{
+	unsigned long stack;
+        int i, err;
+
+	ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL);
+	if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) {
+		printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR);
+		return -1;
+	}
+	ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
+	INIT_QUEUE(ubd_queue, DEVICE_REQUEST, &ubd_lock);
+	INIT_ELV(ubd_queue, &ubd_queue->elevator);
+	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
+	blksize_size[MAJOR_NR] = blk_sizes;
+	blk_size[MAJOR_NR] = sizes;
+	INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
+        add_gendisk(&ubd_gendisk);
+	if (fake_major != 0){
+		char name[sizeof("ubd_nnn\0")];
+
+		snprintf(name, sizeof(name), "ubd_%d", fake_major);
+		ubd_fake_dir_handle = devfs_mk_dir(NULL, name, NULL);
+		if(devfs_register_blkdev(fake_major, "ubd", &ubd_blops)) {
+			printk(KERN_ERR "ubd: unable to get major %d\n",
+			       fake_major);
+			return -1;
+		}
+		blk_dev[fake_major].queue = ubd_get_queue;
+		read_ahead[fake_major] = 8;	/* 8 sector (4kB) read-ahead */
+		blksize_size[fake_major] = blk_sizes;
+		INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
+                add_gendisk(&fake_gendisk);
+	}
+	for(i=0;i<MAX_DEV;i++) ubd_add(i);
+	if(sync){
+		printk(KERN_INFO "ubd : Synchronous mode\n");
+		return(0);
+	}
+	stack = alloc_stack();
+	io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
+				 &thread_fd);
+	if(io_pid < 0){
+		printk(KERN_ERR 
+		       "ubd : Failed to start I/O thread (errno = %d) - "
+		       "falling back to synchronous I/O\n", -io_pid);
+		return(0);
+	}
+	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
+			     SA_INTERRUPT, "ubd", ubd_dev);
+	if(err != 0) printk(KERN_ERR 
+			    "um_request_irq failed - errno = %d\n", -err);
+	return(err);
+}
+
+__initcall(ubd_init);
+
+static void ubd_close(struct ubd *dev)
+{
+	close_fd(dev->fd);
+	if(dev->cow.file != NULL) {
+		close_fd(dev->cow.fd);
+		vfree(dev->cow.bitmap);
+		dev->cow.bitmap = NULL;
+	}
+}
+
+static int ubd_open_dev(struct ubd *dev)
+{
+	int err, flags, n, create_cow, *create_ptr;
+
+	create_cow = 0;
+	create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
+	dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
+				&dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
+				&dev->cow.data_offset, create_ptr);
+
+	if((dev->fd == -ENOENT) && create_cow){
+		n = dev - ubd_dev;
+		dev->fd = create_cow_file(dev->file, dev->cow.file, 1 << 9,
+					  &dev->cow.bitmap_offset, 
+					  &dev->cow.bitmap_len,
+					  &dev->cow.data_offset);
+		if(dev->fd >= 0){
+			printk(KERN_INFO "Creating \"%s\" as COW file for "
+			       "\"%s\"\n", dev->file, dev->cow.file);
+		}
+	}
+
+	if(dev->fd < 0) return(dev->fd);
+
+	if(dev->cow.file != NULL){
+		err = -ENOMEM;
+		dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
+		if(dev->cow.bitmap == NULL) goto error;
+		flush_tlb_kernel_vm();
+
+		err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
+				      dev->cow.bitmap_offset, 
+				      dev->cow.bitmap_len);
+		if(err) goto error;
+
+		flags = O_RDONLY;
+		err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, 
+				    NULL, NULL);
+		if(err < 0) goto error;
+		dev->cow.fd = err;
+	}
+	return(0);
+ error:
+	close_fd(dev->fd);
+	return(err);
+}
+
+static int ubd_open(struct inode * inode, struct file * filp)
+{
+	char *file;
+	int n;
+
+	n = minor(inode->i_rdev);
+	if(n > MAX_DEV)
+		return -ENODEV;
+	if(ubd_is_dir(ubd_dev[n].file)){
+		ubd_dev[n].is_dir = 1;
+		return(0);
+	}
+	if(ubd_dev[n].count == 0){
+		ubd_dev[n].openflags = ubd_dev[n].boot_openflags;
+		/* XXX This error is wrong when errno isn't stored in
+		 * ubd_dev[n].fd
+		 */
+		if(ubd_open_dev(&ubd_dev[n]) < 0){
+			printk(KERN_ERR "ubd%d: Can't open \"%s\": "
+			       "errno = %d\n", n, ubd_dev[n].file, 
+			       -ubd_dev[n].fd);
+		}
+		if(ubd_dev[n].fd < 0)
+			return -ENODEV;
+		file = ubd_dev[n].cow.file ? ubd_dev[n].cow.file : 
+			ubd_dev[n].file;
+		ubd_dev[n].size = file_size(file);
+		if(ubd_dev[n].size < 0) return(ubd_dev[n].size);
+		ubd_part[n].start_sect = 0;
+		ubd_part[n].nr_sects = ubd_dev[n].size / blk_sizes[n];
+		sizes[n] = ubd_dev[n].size / BLOCK_SIZE;
+	}
+	ubd_dev[n].count++;
+	if ((filp->f_mode & FMODE_WRITE) && 
+	    ((ubd_dev[n].openflags & ~O_SYNC) == O_RDONLY)){
+	        if(--ubd_dev[n].count == 0) ubd_close(&ubd_dev[n]);
+	        return -EROFS;
+	}
+	return(0);
+}
+
+static int ubd_release(struct inode * inode, struct file * file)
+{
+        int n;
+
+	n =  minor(inode->i_rdev);
+	if(n > MAX_DEV)
+		return -ENODEV;
+	if(--ubd_dev[n].count == 0){
+		ubd_close(&ubd_dev[n]);
+		sizes[n] = 0;
+		ubd_part[n].nr_sects = 0;
+	}
+	return(0);
+}
+
+int cow_read = 0;
+int cow_write = 0;
+
+void cowify_req(struct io_thread_req *req, struct ubd *dev)
+{
+        int i, update_bitmap, sector = req->offset >> 9;
+
+	if(req->length > (sizeof(req->sector_mask) * 8) << 9)
+		panic("Operation too long");
+	if(req->op == UBD_READ) {
+		for(i = 0; i < req->length >> 9; i++){
+			if(ubd_test_bit(sector + i, (unsigned char *) 
+					dev->cow.bitmap)){
+				ubd_set_bit(i, (unsigned char *) 
+					    &req->sector_mask);
+				cow_read++;
+			}
+                }
+        } 
+        else {
+		update_bitmap = 0;
+		for(i = 0; i < req->length >> 9; i++){
+			cow_write++;
+			ubd_set_bit(i, (unsigned char *) 
+				    &req->sector_mask);
+			if(!ubd_test_bit(sector + i, (unsigned char *) 
+					 dev->cow.bitmap))
+				update_bitmap = 1;
+			ubd_set_bit(sector + i, (unsigned char *) 
+				    dev->cow.bitmap);
+		}
+		if(update_bitmap){
+			req->cow_offset = sector / (sizeof(unsigned long) * 8);
+			req->bitmap_words[0] = 
+				dev->cow.bitmap[req->cow_offset];
+			req->bitmap_words[1] = 
+				dev->cow.bitmap[req->cow_offset + 1];
+			req->cow_offset *= sizeof(unsigned long);
+			req->cow_offset += dev->cow.bitmap_offset;
+		}
+	}
+}
+
+static int prepare_request(struct request *req, struct io_thread_req *io_req)
+{
+	struct ubd *dev;
+	__u64 block;
+	int nsect;
+
+	if(req->rq_status == RQ_INACTIVE) return(1);
+
+	dev = &ubd_dev[minor(req->rq_dev)];
+	if(dev->is_dir){
+		strcpy(req->buffer, "HOSTFS:");
+		strcat(req->buffer, dev->file);
+		end_request(1);
+		return(1);
+	}
+	if(IS_WRITE(req) && ((dev->openflags & O_ACCMODE) == O_RDONLY)){
+		printk("Write attempted on readonly ubd device %d\n", 
+		       minor(req->rq_dev));
+		end_request(0);
+		return(1);
+	}
+
+        block = req->sector;
+        nsect = req->current_nr_sectors;
+
+	io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE;
+	io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
+	io_req->fds[1] = dev->fd;
+	io_req->offsets[0] = 0;
+	io_req->offsets[1] = dev->cow.data_offset;
+	io_req->offset = ((__u64) block) << 9;
+	io_req->length = nsect << 9;
+	io_req->buffer = req->buffer;
+	io_req->sectorsize = 1 << 9;
+	io_req->sector_mask = 0;
+	io_req->cow_offset = -1;
+	io_req->error = 0;
+
+        if(dev->cow.file != NULL) cowify_req(io_req, dev);
+	return(0);
+}
+
+static void do_ubd_request(request_queue_t *q)
+{
+	struct io_thread_req io_req;
+	struct request *req;
+	int err, n;
+
+	if(thread_fd == -1){
+		while(!list_empty(&q->queue_head)){
+			req = blkdev_entry_next_request(&q->queue_head);
+			err = prepare_request(req, &io_req);
+			if(!err){
+				do_io(&io_req);
+				ubd_finish(io_req.error);
+			}
+		}
+	}
+	else {
+		if(DEVICE_INTR || list_empty(&q->queue_head)) return;
+		req = blkdev_entry_next_request(&q->queue_head);
+		err = prepare_request(req, &io_req);
+		if(!err){
+			SET_INTR(ubd_handler);
+			n = write_ubd_fs(thread_fd, (char *) &io_req, 
+					 sizeof(io_req));
+			if(n != sizeof(io_req))
+				printk("write to io thread failed, "
+				       "errno = %d\n", -n);
+		}
+	}
+}
+
+static int ubd_ioctl(struct inode * inode, struct file * file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+	int dev, err;
+
+        if(!inode) return -EINVAL;
+	dev = minor(inode->i_rdev);
+	if (dev > MAX_DEV)
+		return -EINVAL;
+	switch (cmd) {
+	        struct hd_geometry g;
+		struct cdrom_volctrl volume;
+	case HDIO_GETGEO:
+		if (!loc)  return -EINVAL;
+		g.heads = 128;
+		g.sectors = 32;
+		g.cylinders = ubd_dev[dev].size / (128 * 32);
+		g.start = 2;
+		return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+	case BLKRASET:
+		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+		if(arg > 0xff) return -EINVAL;
+		read_ahead[major(inode->i_rdev)] = arg;
+		return 0;
+	case BLKRAGET:
+		if (!arg)  return -EINVAL;
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if (err)
+			return err;
+		return 0;
+	case BLKGETSIZE:   /* Return device size */
+		if (!arg)  return -EINVAL;
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if (err)
+			return err;
+		put_user(ubd_dev[dev].size >> 9, (long *) arg);
+		return 0;
+	case BLKFLSBUF:
+		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+		return 0;
+
+	case BLKRRPART: /* Re-read partition tables */
+		return 0; /* revalidate_hddisk(inode->i_rdev, 1); */
+
+	case HDIO_SET_UNMASKINTR:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		if ((arg > 1) || (minor(inode->i_rdev) & 0x3F))
+			return -EINVAL;
+		return 0;
+
+	case HDIO_GET_UNMASKINTR:
+		if (!arg)  return -EINVAL;
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if (err)
+			return err;
+		return 0;
+
+	case HDIO_GET_MULTCOUNT:
+		if (!arg)  return -EINVAL;
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if (err)
+			return err;
+		return 0;
+
+	case HDIO_SET_MULTCOUNT:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		if (minor(inode->i_rdev) & 0x3F) return -EINVAL;
+		return 0;
+
+	case HDIO_GET_IDENTITY:
+		ubd_id.cyls = ubd_dev[dev].size / (128 * 32);
+		if (copy_to_user((char *) arg, (char *) &ubd_id, 
+				 sizeof(ubd_id)))
+			return -EFAULT;
+		return 0;
+		
+	case CDROMVOLREAD:
+		if(copy_from_user(&volume, (char *) arg, sizeof(volume)))
+			return -EFAULT;
+		volume.channel0 = 255;
+		volume.channel1 = 255;
+		volume.channel2 = 255;
+		volume.channel3 = 255;
+		if(copy_to_user((char *) arg, &volume, sizeof(volume)))
+			return -EFAULT;		
+		return 0;
+
+	default:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/ubd_user.c linux-2.4.19-pre5-mjc/arch/um/drivers/ubd_user.c
--- linux/arch/um/drivers/ubd_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/ubd_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,566 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ubd_user.h"
+
+#include <endian.h>
+#include <byteswap.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x)  bswap_64(x)
+# define htonll(x)  bswap_64(x)
+#else
+#error "__BYTE_ORDER not defined"
+#endif
+
+extern __s64 file_size(char *file);
+
+#define PATH_LEN_V1 256
+
+struct cow_header_v1 {
+	int magic;
+	int version;
+	char backing_file[PATH_LEN_V1];
+	time_t mtime;
+	__u64 size;
+	int sectorsize;
+};
+
+#define PATH_LEN_V2 MAXPATHLEN
+
+struct cow_header_v2 {
+	unsigned long magic;
+	unsigned long version;
+	char backing_file[PATH_LEN_V2];
+	time_t mtime;
+	__u64 size;
+	int sectorsize;
+};
+
+union cow_header {
+	struct cow_header_v1 v1;
+	struct cow_header_v2 v2;
+};
+
+#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+#define COW_VERSION 2
+
+static void sizes(__u64 size, int sectorsize, int bitmap_offset, 
+		  unsigned long *bitmap_len_out, int *data_offset_out)
+{
+	*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+
+	*data_offset_out = bitmap_offset + *bitmap_len_out;
+	*data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
+	*data_offset_out *= sectorsize;
+}
+
+static int read_cow_header(int fd, int *magic_out, char **backing_file_out, 
+			   time_t *mtime_out, __u64 *size_out, 
+			   int *sectorsize_out, int *bitmap_offset_out)
+{
+	union cow_header *header;
+	char *file;
+	int err, n;
+	unsigned long version, magic;
+
+	header = um_kmalloc(sizeof(*header));
+	if(header == NULL){
+		printk("read_cow_header - Failed to allocate header\n");
+		return(-ENOMEM);
+	}
+	err = -EINVAL;
+	n = read(fd, header, sizeof(*header));
+	if(n < offsetof(typeof(header->v1), backing_file)){
+		printk("read_cow_header - short header\n");
+		goto out;
+	}
+
+	magic = header->v1.magic;
+	if(magic == COW_MAGIC) {
+		version = header->v1.version;
+	}
+	else if(magic == ntohl(COW_MAGIC)){
+		version = ntohl(header->v1.version);
+	}
+	else goto out;
+
+	*magic_out = COW_MAGIC;
+
+	if(version == 1){
+		if(n < sizeof(header->v1)){
+			printk("read_cow_header - failed to read V1 header\n");
+			goto out;
+		}
+		*mtime_out = header->v1.mtime;
+		*size_out = header->v1.size;
+		*sectorsize_out = header->v1.sectorsize;
+		*bitmap_offset_out = sizeof(header->v1);
+		file = header->v1.backing_file;
+	}
+	else if(version == 2){
+		if(n < sizeof(header->v2)){
+			printk("read_cow_header - failed to read V2 header\n");
+			goto out;
+		}
+		*mtime_out = ntohl(header->v2.mtime);
+		*size_out = ntohll(header->v2.size);
+		*sectorsize_out = ntohl(header->v2.sectorsize);
+		*bitmap_offset_out = sizeof(header->v2);
+		file = header->v2.backing_file;
+	}
+	else {
+		printk("read_cow_header - invalid COW version\n");
+		goto out;
+	}
+	err = -ENOMEM;
+	*backing_file_out = uml_strdup(file);
+	if(*backing_file_out == NULL){
+		printk("read_cow_header - failed to allocate backing file\n");
+		goto out;
+	}
+	err = 0;
+ out:
+	kfree(header);
+	return(err);
+}
+
+int open_ubd_file(char *file, int *openflags, char **backing_file_out, 
+		  int *bitmap_offset_out, unsigned long *bitmap_len_out, 
+		  int *data_offset_out, int *create_cow_out)
+{
+	struct stat64 buf;
+	time_t mtime;
+	__u64 size;
+	__s64 actual;
+	char *backing_file;
+        int fd, err, sectorsize, magic, mode = 0644;
+
+        if((fd = open64(file, *openflags, mode)) < 0){
+		if((errno == ENOENT) && (create_cow_out != NULL))
+			*create_cow_out = 1;
+                if(((*openflags & O_ACCMODE) != O_RDWR) || 
+                   ((errno != EROFS) && (errno != EACCES))) return(-errno);
+		*openflags &= ~O_ACCMODE;
+                *openflags |= O_RDONLY;
+                if((fd = open64(file, *openflags, mode)) < 0) return(-errno);
+        }
+	if(backing_file_out == NULL) return(fd);
+
+	err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, 
+			      &sectorsize, bitmap_offset_out);
+	if(err && (*backing_file_out != NULL)){
+		printk("Failed to read COW header from COW file \"%s\", "
+		       "errno = %d\n", file, err);
+		goto error;
+	}
+	if(err) return(fd);
+	
+	if((*backing_file_out != NULL) &&
+	   strcmp(*backing_file_out, backing_file)){
+		printk("Backing file mismatch - \"%s\" requested,\n"
+		       "\"%s\" specified in COW header of \"%s\"\n",
+		       *backing_file_out, backing_file, file);
+		printk("Using \"%s\"\n", backing_file);
+	}
+
+	if(backing_file_out == NULL) return(fd);
+	
+	*backing_file_out = backing_file;
+
+  	err = stat64(*backing_file_out, &buf);
+  	if(err){
+		printk("Failed to stat backing file \"%s\", errno = %d\n",
+		       *backing_file_out, errno);
+		err = -errno;
+		goto error;
+	}
+
+	actual = file_size(*backing_file_out);
+	if(actual < 0){
+		err = actual;
+		printk("Failed to get size of backing file \"%s\", "
+		       "errno = %d\n", *backing_file_out, -err);
+		goto error;
+	}
+
+  	err = -EINVAL;
+  	if(actual != size){
+		printk("Size mismatch (%ld vs %ld) of COW header vs backing "
+		       "file\n", buf.st_size, size);
+		goto error;
+	}
+	if(buf.st_mtime != mtime){
+		printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
+		       "file\n", buf.st_mtime, mtime);
+		goto error;
+	}
+
+	sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
+	      data_offset_out);
+
+        return(fd);
+ error:
+	close(fd);
+	return(err);
+}
+
+int read_cow_bitmap(int fd, void *buf, int offset, int len)
+{
+	int err;
+
+	err = lseek64(fd, offset, SEEK_SET);
+	if(err != offset) return(-errno);
+	err = read(fd, buf, len);
+	if(err < 0) return(-errno);
+	return(0);
+}
+
+static int absolutize(char *to, int size, char *from)
+{
+	char save_cwd[256], *slash;
+	int remaining;
+
+	if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+		printk("absolutize : unable to get cwd - errno = %d\n", errno);
+		return(-1);
+	}
+	slash = strrchr(from, '/');
+	if(slash != NULL){
+		*slash = '\0';
+		if(chdir(from)){
+			*slash = '/';
+			printk("absolutize : Can't cd to '%s' - errno = %d\n",
+			       from, errno);
+			return(-1);
+		}
+		*slash = '/';
+		if(getcwd(to, size) == NULL){
+			printk("absolutize : unable to get cwd of '%s' - "
+			       "errno = %d\n", from, errno);
+			return(-1);
+		}
+		remaining = size - strlen(to);
+		if(strlen(slash) + 1 > remaining){
+			printk("absolutize : unable to fit '%s' into %d "
+			       "chars\n", from, size);
+			return(-1);
+		}
+		strcat(to, slash);
+	}
+	else {
+		if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+			printk("absolutize : unable to fit '%s' into %d "
+			       "chars\n", from, size);
+			return(-1);
+		}
+		strcpy(to, save_cwd);
+		strcat(to, "/");
+		strcat(to, from);
+	}
+	chdir(save_cwd);
+	return(0);
+}
+
+int create_cow_file(char *cow_file, char *backing_file, int sectorsize, 
+		    int *bitmap_offset_out, unsigned long *bitmap_len_out, 
+		    int *data_offset_out)
+{
+        struct cow_header_v2 *header;
+	struct stat64 buf;
+	__u64 blocks;
+	long zero;
+	int err, fd, i, flags;
+	__s64 size;
+
+	err = -ENOMEM;
+	header = um_kmalloc(sizeof(*header));
+	if(header == NULL){
+		printk("Failed to allocate COW V2 header\n");
+		goto out_free;
+	}
+	header->magic = htonl(COW_MAGIC);
+	header->version = htonl(COW_VERSION);
+
+	err = -EINVAL;
+	if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+		printk("Backing file name \"%s\" is too long - names are "
+		       "limited to %d characters\n", backing_file, 
+		       sizeof(header->backing_file) - 1);
+		goto out_free;
+	}
+
+	if(absolutize(header->backing_file, sizeof(header->backing_file), 
+		      backing_file))
+		goto out_free;
+
+	err = stat64(header->backing_file, &buf);
+	if(err < 0){
+		printk("Stat of backing file '%s' failed, errno = %d\n",
+		       header->backing_file, errno);
+		err = -errno;
+		goto out_free;
+	}
+
+	header->mtime = htonl(buf.st_mtime);
+	header->size = htonll(buf.st_size);
+	header->sectorsize = htonl(sectorsize);
+
+	size = file_size(header->backing_file);
+	if(size < 0){
+		printk("Couldn't get size of backing file '%s', errno = %d\n",
+		       -size);
+		err = size;
+		goto out_free;
+	}
+
+	flags = O_RDWR | O_CREAT;
+	fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
+	if(fd < 0){
+		err = fd;
+		printk("Open of COW file '%s' failed, errno = %d\n", -err);
+		goto out_free;
+	}
+
+	err = write(fd, header, sizeof(*header));
+	
+	if(err != sizeof(*header)){
+		printk("Write of header to new COW file '%s' failed, "
+		       "errno = %d\n", cow_file, errno);
+		goto out_close;
+	}
+
+	blocks = (size + sectorsize - 1) / sectorsize;
+	blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
+	zero = 0;
+	for(i = 0; i < blocks; i++){
+		err = write(fd, &zero, sizeof(zero));
+		if(err != sizeof(zero)){
+			printk("Write of bitmap to new COW file '%s' failed, "
+			       "errno = %d\n", cow_file, errno);
+			goto out_close;
+		}
+	}
+
+	sizes(size, sectorsize, sizeof(struct cow_header_v2), 
+	      bitmap_len_out, data_offset_out);
+	*bitmap_offset_out = sizeof(struct cow_header_v2);
+
+	kfree(header);
+	return(fd);
+
+ out_close:
+	close(fd);
+ out_free:
+	kfree(header);
+	return(err);
+}
+
+int read_ubd_fs(int fd, void *buffer, int len)
+{
+	int n;
+
+	n = read(fd, buffer, len);
+	if(n < 0) return(-errno);
+	else return(n);
+}
+
+int write_ubd_fs(int fd, char *buffer, int len)
+{
+	int n;
+
+	n = write(fd, buffer, len);
+	if(n < 0) return(-errno);
+	else return(n);
+}
+
+int ubd_is_dir(char *file)
+{
+	struct stat64 buf;
+
+	if(stat64(file, &buf) < 0) return(0);
+	return(S_ISDIR(buf.st_mode));
+}
+
+void do_io(struct io_thread_req *req)
+{
+	char *buf;
+	unsigned long len;
+	int n, nsectors, start, end, bit;
+	__u64 off;
+
+	nsectors = req->length / req->sectorsize;
+	start = 0;
+	do {
+		bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
+		end = start;
+		while((end < nsectors) && 
+		      (ubd_test_bit(end, (unsigned char *) 
+				    &req->sector_mask) == bit))
+			end++;
+
+		if(end != nsectors)
+			printk("end != nsectors\n");
+		off = req->offset + req->offsets[bit];
+		len = (end - start) * req->sectorsize;
+		buf = &req->buffer[start * req->sectorsize];
+
+		if(lseek64(req->fds[bit], off, SEEK_SET) != off){
+			printk("do_io - lseek failed : errno = %d\n", errno);
+			req->error = 1;
+			return;
+		}
+		if(req->op == UBD_READ){
+			n = 0;
+			do {
+				buf = &buf[n];
+				len -= n;
+				n = read(req->fds[bit], buf, len);
+				if (n < 0) {
+					printk("do_io - read returned %d : "
+					       "errno = %d fd = %d\n", n,
+					       errno, req->fds[bit]);
+					req->error = 1;
+					return;
+				}
+			} while((n < len) && (n != 0));
+			if (n < len) memset(&buf[n], 0, len - n);
+		}
+		else {
+			n = write(req->fds[bit], buf, len);
+			if(n != len){
+				printk("do_io - write returned %d : "
+				       "errno = %d fd = %d\n", n, 
+				       errno, req->fds[bit]);
+				req->error = 1;
+				return;
+			}
+		}
+
+		start = end;
+	} while(start < nsectors);
+
+	if(req->cow_offset != -1){
+		if(lseek64(req->fds[1], req->cow_offset, SEEK_SET) != 
+		   req->cow_offset){
+			printk("do_io - bitmap lseek failed : errno = %d\n",
+			       errno);
+			req->error = 1;
+			return;
+		}
+		n = write(req->fds[1], &req->bitmap_words, 
+			  sizeof(req->bitmap_words));
+		if(n != sizeof(req->bitmap_words)){
+			printk("do_io - bitmap update returned %d : "
+			       "errno = %d fd = %d\n", n, errno, req->fds[1]);
+			req->error = 1;
+			return;
+		}
+	}
+	req->error = 0;
+	return;
+}
+
+int kernel_fd = -1;
+
+int io_count = 0;
+
+int io_thread(void *arg)
+{
+	struct io_thread_req req;
+	int n;
+
+	signal(SIGWINCH, SIG_IGN);
+	while(1){
+		n = read(kernel_fd, &req, sizeof(req));
+		if(n < 0) printk("io_thread - read returned %d, errno = %d\n",
+				 n, errno);
+		else if(n < sizeof(req)){
+			printk("io_thread - short read : length = %d\n", n);
+			continue;
+		}
+		io_count++;
+		do_io(&req);
+		n = write(kernel_fd, &req, sizeof(req));
+		if(n != sizeof(req))
+			printk("io_thread - write failed, errno = %d\n",
+			       errno);
+	}
+}
+
+int start_io_thread(unsigned long sp, int *fd_out)
+{
+	int pid, fds[2];
+
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0){
+		printk("start_io_thread - socketpair failed, errno = %d\n",
+		       errno);
+		return(-1);
+	}
+	kernel_fd = fds[0];
+	*fd_out = fds[1];
+
+	pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
+		    NULL);
+	if(pid < 0){
+		printk("start_io_thread - clone failed : errno = %d\n", errno);
+		return(-errno);
+	}
+	return(pid);
+}
+
+#ifdef notdef
+int start_io_thread(unsigned long sp, int *fd_out)
+{
+	int pid;
+
+	if((kernel_fd = get_pty()) < 0) return(-1);
+	raw(kernel_fd, 0);
+	if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){
+		printk("Couldn't open tty for IO\n");
+		return(-1);
+	}
+
+	pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
+		    NULL);
+	if(pid < 0){
+		printk("start_io_thread - clone failed : errno = %d\n", errno);
+		return(-errno);
+	}
+	return(pid);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/drivers/xterm.c linux-2.4.19-pre5-mjc/arch/um/drivers/xterm.c
--- linux/arch/um/drivers/xterm.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/drivers/xterm.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,144 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <sched.h>
+#include "kern_util.h"
+#include "user_util.h"
+#include "chan_user.h"
+#include "user.h"
+
+struct xterm_chan {
+	int pid;
+	int fd;
+	char *title;
+	int device;
+	int raw;
+	struct termios tt;
+};
+
+void *xterm_init(char *str, int device, struct chan_opts *opts)
+{
+	struct xterm_chan *data;
+
+	if((data = malloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct xterm_chan) { pid :		-1, 
+				       device :		device, 
+				       title :		opts->xterm_title,
+				       raw : 		opts->raw });
+	return(data);
+}
+
+struct xterm_info {
+	char tty[2];
+	int fd;
+	int slave;
+	int console_num;
+	int *pid_out;
+	char *title;
+	int winch;
+};
+
+static void xterm_tramp(void *arg)
+{
+	struct xterm_info *info;
+	int pid;
+	char title[256], flag[sizeof("Sxxnn\0")], c;
+
+	info = arg;
+	sprintf(flag, "-S%c%c%d", info->tty[0], info->tty[1], info->fd);
+	sprintf(title, info->title, info->console_num);
+	if((pid = fork()) != 0) *info->pid_out = pid;
+	else {
+		execlp("xterm", "xterm", flag, "-T", title, NULL);
+		printk("execlp of xterm failed - errno = %d\n", errno);
+		close(info->fd);
+		exit(1);
+	}
+	close(info->fd);
+	while((read(info->slave, &c, sizeof(c)) == sizeof(c)) && (c != '\n')) ;
+}
+
+int xterm_open(int input, int output, int primary, void *d)
+{
+	struct xterm_chan *data = d;
+	struct xterm_info info;
+	int master, slave;
+	char dev[] = "/dev/ptyXX";
+
+	master = getmaster(dev);
+	if(master == -1){
+		printk("No unused host ptys found\n");
+		return(-ENODEV);
+	}
+	dev[strlen("/dev/")] = 't';
+	slave = open(dev, O_RDWR);
+	if(slave == -1) return(-errno);
+	tcgetattr(slave, &data->tt);
+	raw(slave, 0);
+	info.tty[0] = dev[strlen("/dev/pty")];
+	info.tty[1] = dev[strlen("/dev/ptyX")];
+	info.fd = master;
+	info.slave = slave;
+	info.console_num = data->device;
+	info.pid_out = &data->pid;
+	info.title = data->title;
+	tracing_cb(xterm_tramp, &info);
+	tcsetattr(slave, TCSADRAIN, &data->tt);
+	if(data->raw) raw(slave, 0);
+	data->fd = slave;
+
+	return(slave);
+}
+
+void xterm_close(int fd, void *d)
+{
+	struct xterm_chan *data = d;
+	
+	if(data->pid != -1) kill(data->pid, SIGKILL);
+	close(fd);
+}
+
+void xterm_free(void *d)
+{
+	free(d);
+}
+
+int xterm_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct xterm_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops xterm_ops = {
+	init:		xterm_init,
+	open:		xterm_open,
+	close:		xterm_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	xterm_console_write,
+	window_size:	generic_window_size,
+	free:		xterm_free,
+	winch:		1,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/fs/Makefile linux-2.4.19-pre5-mjc/arch/um/fs/Makefile
--- linux/arch/um/fs/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/fs/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,16 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+O_TARGET := fs.o
+
+subdir-$(CONFIG_HOSTFS) = hostfs
+
+MOD_SUB_DIRS := $(subdir-m)
+SUB_DIRS := $(subdir-y)
+
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+obj-m += $(join $(subdir-m),$(subdir-m:%=/%.o))
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/fs/hostfs/Makefile linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/Makefile
--- linux/arch/um/fs/hostfs/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,31 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
+# to __st_ino.  It stayed in the same place, so as long as the correct name
+# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
+
+STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
+				echo __)st_ino
+
+USER_CFLAGS := $(USER_CFLAGS) -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
+
+O_TARGET :=
+obj-y = 
+obj-m =
+
+CFLAGS_hostfs_kern.o := $(CFLAGS)
+CFLAGS_hostfs_user.o := $(USER_CFLAGS)
+
+ifneq ($(CONFIG_HOSTFS), n)
+  O_TARGET := hostfs.o
+endif
+
+obj-y += hostfs_kern.o hostfs_user.o
+obj-m += $(O_TARGET)
+
+override CFLAGS =  
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/fs/hostfs/hostfs.h linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs.h
--- linux/arch/um/fs/hostfs/hostfs.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,74 @@
+#ifndef __UM_FS_HOSTFS
+#define __UM_FS_HOSTFS
+
+#define HOSTFS_FILE 1 
+#define HOSTFS_DIR 2 
+#define HOSTFS_SYMLINK 3 
+#define HOSTFS_CHARDEV 4
+#define HOSTFS_BLOCDEV 5
+#define HOSTFS_FIFO 6
+#define HOSTFS_SOCK 7
+
+/* These are exactly the same definitions as in fs.h, but the names are 
+ *  changed so that this file can be included in both kernel and user files.
+ */
+
+#define HOSTFS_ATTR_MODE	1
+#define HOSTFS_ATTR_UID 	2
+#define HOSTFS_ATTR_GID 	4
+#define HOSTFS_ATTR_SIZE	8
+#define HOSTFS_ATTR_ATIME	16
+#define HOSTFS_ATTR_MTIME	32
+#define HOSTFS_ATTR_CTIME	64
+#define HOSTFS_ATTR_ATIME_SET	128
+#define HOSTFS_ATTR_MTIME_SET	256
+#define HOSTFS_ATTR_FORCE	512	/* Not a change, but a change it */
+#define HOSTFS_ATTR_ATTR_FLAG	1024
+
+struct hostfs_iattr {
+	unsigned int	ia_valid;
+	mode_t		ia_mode;
+	uid_t		ia_uid;
+	gid_t		ia_gid;
+	loff_t		ia_size;
+	time_t		ia_atime;
+	time_t		ia_mtime;
+	time_t		ia_ctime;
+	unsigned int	ia_attr_flags;
+};
+
+extern int stat_file(const char *path, int *dev_out, unsigned long long *inode_out,
+		     int *mode_out, int *nlink_out, int *uid_out, 
+		     int *gid_out, unsigned long long *size_out, 
+		     unsigned long *atime_out, unsigned long *mtime_out, 
+		     unsigned long *ctime_out, int *blksize_out, 
+		     unsigned long long *blocks_out);
+extern int access_file(char *path, int r, int w, int x);
+extern int open_file(char *path, int r, int w);
+extern int file_type(const char *path, int *rdev);
+extern void *open_dir(char *path, int *err_out);
+extern char *read_dir(void *stream, unsigned long long *pos, 
+		      unsigned long long *ino_out, int *len_out);
+extern void close_file(void *stream);
+extern void close_dir(void *stream);
+extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
+extern int write_file(int fd, unsigned long long *offset, const char *buf,
+		      int len);
+extern int lseek_file(int fd, long long offset, int whence);
+extern int file_create(char *name, int ur, int uw, int ux, int gr, 
+		       int gw, int gx, int or, int ow, int ox);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs);
+extern int make_symlink(const char *from, const char *to);
+extern int unlink_file(const char *file);
+extern int do_mkdir(const char *file, int mode);
+extern int do_rmdir(const char *file);
+extern int do_mknod(const char *file, int mode, int dev);
+extern int link_file(const char *from, const char *to);
+extern int do_readlink(char *file, char *buf, int size);
+extern int rename_file(char *from, char *to);
+extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
+		     long long *bfree_out, long long *bavail_out, long long *files_out, 
+		     long long *ffree_out, void *fsid_out, int fsid_size, 
+		     long *namelen_out, long *spare_out);
+
+#endif
diff -Nru linux/arch/um/fs/hostfs/hostfs_kern.c linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs_kern.c
--- linux/arch/um/fs/hostfs/hostfs_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,761 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <asm/uaccess.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "user_util.h"
+#include "2_5compat.h"
+
+#define file_hostfs_i(file) (&(file)->f_dentry->d_inode->u.hostfs_i)
+
+int hostfs_d_delete(struct dentry *dentry)
+{
+	return(1);
+}
+
+struct dentry_operations hostfs_dentry_ops = {
+	d_delete:		hostfs_d_delete,
+};
+
+static char *root_ino = "/";
+
+#define HOSTFS_SUPER_MAGIC 0x00c0ffee
+
+static struct inode_operations hostfs_iops;
+static struct address_space_operations hostfs_link_aops;
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+	struct dentry *parent;
+	char *root, *name;
+	int len;
+
+	len = 0;
+	parent = dentry;
+	while(parent->d_parent != parent){
+		len += parent->d_name.len + 1;
+		parent = parent->d_parent;
+	}
+	
+	root = parent->d_inode->u.hostfs_i.host_filename;
+	len += strlen(root);
+	name = kmalloc(len + extra + 1, GFP_KERNEL);
+	if(name == NULL) return(NULL);
+
+	name[len] = '\0';
+	parent = dentry;
+	while(parent->d_parent != parent){
+		len -= parent->d_name.len + 1;
+		name[len] = '/';
+		strncpy(&name[len + 1], parent->d_name.name, 
+			parent->d_name.len);
+		parent = parent->d_parent;
+	}
+	strncpy(name, root, strlen(root));
+	return(name);
+}
+
+static char *inode_name(struct inode *ino, int extra)
+{
+	struct dentry *dentry;
+
+	dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
+	return(dentry_name(dentry, extra));
+}
+
+static int read_name(struct inode *ino, char *name)
+{
+	/* The non-int inode fields are copied into ints by stat_file and
+	 * then copied into the inode because passing the actual pointers
+	 * in and having them treated as int * breaks on big-endian machines
+	 */
+	int err;
+	int i_dev, i_mode, i_nlink, i_blksize;
+	unsigned long long i_size;
+	unsigned long long i_ino;
+	unsigned long long i_blocks;
+	err = stat_file(name, &i_dev, &i_ino, &i_mode, &i_nlink, 
+			&ino->i_uid, &ino->i_gid, &i_size, &ino->i_atime, 
+			&ino->i_mtime, &ino->i_ctime, &i_blksize, &i_blocks);
+	if(err) return(err);
+	ino->i_ino = i_ino;
+	ino->i_dev = i_dev;
+	ino->i_mode = i_mode;
+	ino->i_nlink = i_nlink;
+	ino->i_size = i_size;
+	ino->i_blksize = i_blksize;
+	ino->i_blocks = i_blocks;
+	if(kdev_same(ino->i_sb->s_dev, ROOT_DEV) && (ino->i_uid == getuid()))
+		ino->i_uid = 0;
+	return(0);
+}
+
+static int read_inode(struct inode *ino)
+{
+	char *name;
+	int err;
+
+	name = inode_name(ino, 0);
+	if(name == NULL) return(-ENOMEM);
+	err = read_name(ino, name);
+	kfree(name);
+	return(err);
+}
+
+void hostfs_delete_inode(struct inode *ino)
+{
+	if(ino->u.hostfs_i.host_filename) kfree(ino->u.hostfs_i.host_filename);
+	ino->u.hostfs_i.host_filename = NULL;
+	if(ino->u.hostfs_i.fd != -1) close_file(&ino->u.hostfs_i.fd);
+	ino->u.hostfs_i.mode = 0;
+	clear_inode(ino);
+}
+
+int hostfs_statfs(struct super_block *sb, struct statfs *sf)
+{
+	/* do_statfs uses struct statfs64 internally, but the linux kernel
+	 * struct statfs still has 32-bit versions for most of these fields,
+	 * so we convert them here
+	 */
+	int err;
+	long long f_blocks;
+	long long f_bfree;
+	long long f_bavail;
+	long long f_files;
+	long long f_ffree;
+
+	err = do_statfs(sb->s_root->d_inode->u.hostfs_i.host_filename,
+			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
+			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), 
+			&sf->f_namelen, sf->f_spare);
+	if(err) return(err);
+	sf->f_blocks = f_blocks;
+	sf->f_bfree = f_bfree;
+	sf->f_bavail = f_bavail;
+	sf->f_files = f_files;
+	sf->f_ffree = f_ffree;
+	sf->f_type = HOSTFS_SUPER_MAGIC;
+	return(0);
+}
+
+static struct super_operations hostfs_sbops = { 
+	put_inode:	force_delete,
+	delete_inode:	hostfs_delete_inode,
+	statfs:		hostfs_statfs,
+};
+
+int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+	void *dir;
+	char *name;
+	unsigned long long next, ino;
+	int error, len;
+
+	name = dentry_name(file->f_dentry, 0);
+	if(name == NULL) return(-ENOMEM);
+	dir = open_dir(name, &error);
+	kfree(name);
+	if(dir == NULL) return(-error);
+	next = file->f_pos;
+	while((name = read_dir(dir, &next, &ino, &len)) != NULL){
+		error = (*filldir)(ent, name, len, file->f_pos, 
+				   ino, DT_UNKNOWN);
+		if(error) break;
+		file->f_pos = next;
+	}
+	close_dir(dir);
+	return(0);
+}
+
+int hostfs_file_open(struct inode *ino, struct file *file)
+{
+	char *name;
+	int mode = 0, r = 0, w = 0, fd;
+
+	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
+	if((mode & ino->u.hostfs_i.mode) == mode) return(0);
+
+	if(ino->u.hostfs_i.fd != -1){
+		close_file(&ino->u.hostfs_i.fd);
+		ino->u.hostfs_i.fd = -1;
+	}
+	ino->u.hostfs_i.mode |= mode;
+	if(ino->u.hostfs_i.mode & FMODE_READ) r = 1;
+	if(ino->u.hostfs_i.mode & FMODE_WRITE) w = 1;
+	if(w) r = 1;
+	name = dentry_name(file->f_dentry, 0);
+	if(name == NULL) return(-ENOMEM);
+	fd = open_file(name, r, w);
+	kfree(name);
+	if(fd < 0) return(fd);
+	file_hostfs_i(file)->fd = fd;
+	return(0);
+}
+
+int hostfs_dir_open(struct inode *ino, struct file *file)
+{
+	return(0);	
+}
+
+int hostfs_dir_release(struct inode *ino, struct file *file)
+{
+	return(0);
+}
+
+int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	return(0);
+}
+
+static struct file_operations hostfs_file_fops = {
+	owner:		NULL,
+	read:		generic_file_read,
+	write:		generic_file_write,
+	mmap:		generic_file_mmap,
+	open:		hostfs_file_open,
+	release:	NULL,
+	fsync:		hostfs_fsync,
+};
+
+static struct file_operations hostfs_dir_fops = {
+	owner:		NULL,
+	readdir:	hostfs_readdir,
+	open:		hostfs_dir_open,
+	release:	hostfs_dir_release,
+	fsync:		hostfs_fsync,
+};
+
+int hostfs_writepage(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+	struct inode *inode = mapping->host;
+	char *buffer;
+	unsigned long long base;
+	int count = PAGE_CACHE_SIZE;
+	int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	int err;
+
+	if (page->index >= end_index)
+		count = inode->i_size & (PAGE_CACHE_SIZE-1);
+
+	buffer = kmap(page);
+	base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
+
+	err = write_file(inode->u.hostfs_i.fd, &base, buffer, count);
+	if(err != count){
+		ClearPageUptodate(page);
+		goto out;
+	}
+
+	if (base > inode->i_size)
+		inode->i_size = base;
+
+	if (PageError(page))
+		ClearPageError(page);	
+	err = 0;
+
+ out:	
+	kunmap(page);
+
+	UnlockPage(page);
+	return err; 
+}
+
+int hostfs_readpage(struct file *file, struct page *page)
+{
+	char *buffer;
+	long long start;
+	int err = 0;
+
+	start = (long long) page->index << PAGE_CACHE_SHIFT;
+	buffer = kmap(page);
+	err = read_file(file_hostfs_i(file)->fd, &start, buffer,
+			PAGE_CACHE_SIZE);
+	if(err < 0) goto out;
+
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	if (PageError(page)) ClearPageError(page);
+	err = 0;
+ out:
+	kunmap(page);
+	UnlockPage(page);
+	return(err);
+}
+
+int hostfs_prepare_write(struct file *file, struct page *page, 
+			 unsigned int from, unsigned int to)
+{
+	char *buffer;
+	long long start, tmp;
+	int err;
+
+	start = (long long) page->index << PAGE_CACHE_SHIFT;
+	buffer = kmap(page);
+	if(from != 0){
+		tmp = start;
+		err = read_file(file_hostfs_i(file)->fd, &tmp, buffer,
+				from);
+		if(err < 0) goto out;
+	}
+	if(to != PAGE_CACHE_SIZE){
+		start += to;
+		err = read_file(file_hostfs_i(file)->fd, &start, buffer + to,
+				PAGE_CACHE_SIZE - to);
+		if(err < 0) goto out;		
+	}
+	err = 0;
+ out:
+	kunmap(page);
+	return(err);
+}
+
+int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
+		 unsigned to)
+{
+	struct address_space *mapping = page->mapping;
+	struct inode *inode = mapping->host;
+	char *buffer;
+	long long start;
+	int err = 0;
+
+	start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
+	buffer = kmap(page);
+	err = write_file(file_hostfs_i(file)->fd, &start, buffer + from, 
+			 to - from);
+	if(err > 0) err = 0;
+	if(!err && (start > inode->i_size))
+		inode->i_size = start;
+
+	kunmap(page);
+	return(err);
+}
+
+static struct address_space_operations hostfs_aops = {
+	writepage: 	hostfs_writepage,
+	readpage:	hostfs_readpage,
+	prepare_write:	hostfs_prepare_write,
+	commit_write:	hostfs_commit_write
+};
+
+static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
+			       int *error)
+{
+	struct inode *inode;
+	char *name;
+	int type, err = 0, rdev;
+
+	inode = get_empty_inode();
+	if(inode == NULL) return(NULL);
+	inode->u.hostfs_i.host_filename = NULL;
+	inode->u.hostfs_i.fd = -1;
+	inode->u.hostfs_i.mode = 0;
+	if(error) *error = 0;
+	insert_inode_hash(inode);
+	if(dentry){
+		name = dentry_name(dentry, 0);
+		if(name == NULL){
+			err = -ENOMEM;
+			goto out;
+		}
+		type = file_type(name, &rdev);
+		kfree(name);
+	}
+	else type = HOSTFS_DIR;
+	inode->i_sb = sb;
+
+	if(type == HOSTFS_SYMLINK)
+		inode->i_op = &page_symlink_inode_operations;
+	else inode->i_op = &hostfs_iops;
+
+	if(type == HOSTFS_DIR) inode->i_fop = &hostfs_dir_fops;
+	else inode->i_fop = &hostfs_file_fops;
+
+	if(type == HOSTFS_SYMLINK) inode->i_mapping->a_ops = &hostfs_link_aops;
+	else inode->i_mapping->a_ops = &hostfs_aops;
+
+	switch (type) {
+	case HOSTFS_CHARDEV:
+		init_special_inode(inode, S_IFCHR, rdev);
+		break;
+	case HOSTFS_BLOCDEV:
+		init_special_inode(inode, S_IFBLK, rdev);
+		break;
+	case HOSTFS_FIFO:
+		init_special_inode(inode, S_IFIFO, 0);
+		break;
+	case HOSTFS_SOCK:
+		init_special_inode(inode, S_IFSOCK, 0);
+		break;
+	}
+	
+	return(inode);
+ out:
+	iput(inode);
+	if(error) *error = err;
+	return(NULL);
+}
+
+int hostfs_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct inode *inode;
+	char *name;
+	int error;
+
+	inode = get_inode(dir->i_sb, dentry, &error);
+	if(error) return(error);
+	name = dentry_name(dentry, 0);
+	if(name == NULL){
+		iput(inode);
+		return(-ENOMEM);
+	}
+	error = file_create(name, 
+			    mode | S_IRUSR, mode | S_IWUSR, mode | S_IXUSR, 
+			    mode | S_IRGRP, mode | S_IWGRP, mode | S_IXGRP, 
+			    mode | S_IROTH, mode | S_IWOTH, mode | S_IXOTH);
+	if(!error) error = read_name(inode, name);
+	kfree(name);
+	if(error){
+		iput(inode);
+		return(error);
+	}
+	d_instantiate(dentry, inode);
+	return(0);
+}
+ 
+struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry)
+{
+	struct inode *inode;
+	char *name;
+	int error;
+
+	inode = get_inode(ino->i_sb, dentry, &error);
+	if(error != 0) return(ERR_PTR(error));
+	name = dentry_name(dentry, 0);
+	if(name == NULL) return(ERR_PTR(-ENOMEM));
+	error = read_name(inode, name);
+	kfree(name);
+	if(error){
+		iput(inode);
+		if(error == -ENOENT) inode = NULL;
+		else return(ERR_PTR(error));
+	}
+	d_add(dentry, inode);
+	dentry->d_op = &hostfs_dentry_ops;
+	return(NULL);
+}
+
+static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
+{
+        char *file;
+	int len;
+
+	file = inode_name(ino, dentry->d_name.len + 1);
+	if(file == NULL) return(NULL);
+        strcat(file, "/");
+	len = strlen(file);
+        strncat(file, dentry->d_name.name, dentry->d_name.len);
+	file[len + dentry->d_name.len] = '\0';
+        return(file);
+}
+
+int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
+{
+        char *from_name, *to_name;
+        int err;
+
+        if((from_name = inode_dentry_name(ino, from)) == NULL) 
+                return(-ENOMEM);
+        to_name = dentry_name(to, 0);
+	if(to_name == NULL){
+		kfree(from_name);
+		return(-ENOMEM);
+	}
+        err = link_file(to_name, from_name);
+        kfree(from_name);
+        kfree(to_name);
+        return(err);
+}
+
+int hostfs_unlink(struct inode *ino, struct dentry *dentry)
+{
+	char *file;
+	int err;
+
+	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	err = unlink_file(file);
+	kfree(file);
+	return(err);
+}
+
+int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
+{
+	char *file;
+	int err;
+
+	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	err = make_symlink(file, to);
+	kfree(file);
+	return(err);
+}
+
+int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
+{
+	char *file;
+	int err;
+
+	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	err = do_mkdir(file, mode);
+	kfree(file);
+	return(err);
+}
+
+int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
+{
+	char *file;
+	int err;
+
+	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	err = do_rmdir(file);
+	kfree(file);
+	return(err);
+}
+
+int hostfs_mknod(struct inode *ino, struct dentry *dentry, int mode, int dev)
+{
+	char *file;
+	int err;
+
+	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	err = do_mknod(file, mode, dev);
+	kfree(file);
+	return(err);
+}
+
+int hostfs_rename(struct inode *from_ino, struct dentry *from,
+		  struct inode *to_ino, struct dentry *to)
+{
+	char *from_name, *to_name;
+	int err;
+
+	if((from_name = inode_dentry_name(from_ino, from)) == NULL)
+		return(-ENOMEM);
+	if((to_name = inode_dentry_name(to_ino, to)) == NULL){
+		kfree(from_name);
+		return(-ENOMEM);
+	}
+	err = rename_file(from_name, to_name);
+	kfree(from_name);
+	kfree(to_name);
+	return(err);
+}
+
+void hostfs_truncate(struct inode *ino)
+{
+	not_implemented();
+}
+
+int hostfs_permission(struct inode *ino, int desired)
+{
+	char *name;
+	int r = 0, w = 0, x = 0, err;
+
+	if(desired & MAY_READ) r = 1;
+	if(desired & MAY_WRITE) w = 1;
+	if(desired & MAY_EXEC) x = 1;
+	name = inode_name(ino, 0);
+	if(name == NULL) return(-ENOMEM);
+	err = access_file(name, r, w, x);
+	kfree(name);
+	if(!err) err = vfs_permission(ino, desired);
+	return(err);
+}
+
+int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct hostfs_iattr attrs;
+	char *name;
+	int err;
+
+	attrs.ia_valid = 0;
+	if(attr->ia_valid & ATTR_MODE){
+		attrs.ia_valid |= HOSTFS_ATTR_MODE;
+		attrs.ia_mode = attr->ia_mode;
+	}
+	if(attr->ia_valid & ATTR_UID){
+		attrs.ia_valid |= HOSTFS_ATTR_UID;
+		attrs.ia_uid = attr->ia_uid;
+	}
+	if(attr->ia_valid & ATTR_GID){
+		attrs.ia_valid |= HOSTFS_ATTR_GID;
+		attrs.ia_gid = attr->ia_gid;
+	}
+	if(attr->ia_valid & ATTR_SIZE){
+		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
+		attrs.ia_size = attr->ia_size;
+	}
+	if(attr->ia_valid & ATTR_ATIME){
+		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
+		attrs.ia_atime = attr->ia_atime;
+	}
+	if(attr->ia_valid & ATTR_MTIME){
+		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
+		attrs.ia_mtime = attr->ia_mtime;
+	}
+	if(attr->ia_valid & ATTR_CTIME){
+		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
+		attrs.ia_ctime = attr->ia_ctime;
+	}
+	if(attr->ia_valid & ATTR_ATIME_SET){
+		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
+	}
+	if(attr->ia_valid & ATTR_MTIME_SET){
+		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
+	}
+	name = dentry_name(dentry, 0);
+	if(name == NULL) return(-ENOMEM);
+	err = set_attr(name, &attrs);
+	kfree(name);
+	return(err);
+}
+
+int hostfs_getattr(struct dentry *dentry, struct iattr *attr)
+{
+	not_implemented();
+	return(-EINVAL);
+}
+
+static struct inode_operations hostfs_iops = {
+	create:		hostfs_create,
+	lookup:		hostfs_lookup,
+	link:		hostfs_link,
+	unlink:		hostfs_unlink,
+	symlink:	hostfs_symlink,
+	mkdir:		hostfs_mkdir,
+	rmdir:		hostfs_rmdir,
+	mknod:		hostfs_mknod,
+	rename:		hostfs_rename,
+	truncate:	hostfs_truncate,
+	permission:	hostfs_permission,
+	setattr:	hostfs_setattr,
+	getattr:	hostfs_getattr,
+};
+
+int hostfs_link_readpage(struct file *file, struct page *page)
+{
+	char *buffer, *name;
+	long long start;
+	int err;
+
+	start = page->index << PAGE_CACHE_SHIFT;
+	buffer = kmap(page);
+	name = inode_name(page->mapping->host, 0);
+	if(name == NULL) return(-ENOMEM);
+	err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
+	kfree(name);
+	if(err == 0){
+		flush_dcache_page(page);
+		SetPageUptodate(page);
+		if (PageError(page)) ClearPageError(page);
+	}
+	kunmap(page);
+	UnlockPage(page);
+	return(err);
+}
+
+static struct address_space_operations hostfs_link_aops = {
+	readpage:	hostfs_link_readpage,
+};
+
+static struct super_block *hostfs_read_super_common(struct super_block *sb, 
+						    char *data)
+{
+	struct inode * root_inode;
+	char *name;
+
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_magic = HOSTFS_SUPER_MAGIC;
+	sb->s_op = &hostfs_sbops;
+	if((data == NULL) || (*((char *) data) == '\0')) data = root_ino;
+	name = kmalloc(strlen(data) + 1, GFP_KERNEL);
+	if(name == NULL) return(NULL);
+	strcpy(name, data);
+	root_inode = get_inode(sb, NULL, NULL);
+	if(root_inode == NULL){
+		kfree(name);
+		return(NULL);
+	}
+	root_inode->u.hostfs_i.host_filename = name;
+	sb->s_root = d_alloc_root(root_inode);
+	if(read_inode(root_inode)){
+		iput(root_inode);
+		return(NULL);
+	}
+	return(sb);
+}
+
+struct super_block *hostfs_read_super(struct super_block *sb, void *data, 
+				      int silent)
+{
+	return(hostfs_read_super_common(sb, data));
+}
+
+struct super_block *hostfs_root_read_super(struct super_block *sb, void *data, 
+					   int silent)
+{
+	struct buffer_head * bh;
+	struct super_block *ret = NULL;
+	kdev_t dev = sb->s_dev;
+	int blocksize = get_hardsect_size(dev);
+
+	if(blocksize == 0) blocksize = BLOCK_SIZE;
+	set_blocksize (dev, blocksize);
+	if(!(bh = bread (dev, 0, blocksize))) return NULL;
+	if(strncmp(bh->b_data, "HOSTFS:", strlen("HOSTFS:"))) goto out;
+	ret = hostfs_read_super_common(sb, bh->b_data + strlen("HOSTFS:"));
+ out:
+	brelse (bh);
+	return(ret);
+}
+
+DECLARE_FSTYPE(hostfs_type, "hostfs", hostfs_read_super, 0);
+DECLARE_FSTYPE_DEV(hostfs_root_type, "root-hostfs", hostfs_root_read_super);
+
+static int __init init_hostfs(void)
+{
+	return(register_filesystem(&hostfs_type) ||
+	       register_filesystem(&hostfs_root_type));
+}
+
+static void __exit exit_hostfs(void)
+{
+	unregister_filesystem(&hostfs_type);
+	unregister_filesystem(&hostfs_root_type);
+}
+
+module_init(init_hostfs)
+module_exit(exit_hostfs)
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/fs/hostfs/hostfs_user.c linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs_user.c
--- linux/arch/um/fs/hostfs/hostfs_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/fs/hostfs/hostfs_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,337 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <utime.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vfs.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "user.h"
+
+int stat_file(const char *path, int *dev_out, unsigned long long *inode_out,
+	      int *mode_out, int *nlink_out, int *uid_out, int *gid_out, 
+	      unsigned long long *size_out, unsigned long *atime_out,
+	      unsigned long *mtime_out, unsigned long *ctime_out,
+	      int *blksize_out, unsigned long long *blocks_out)
+{
+	struct stat64 buf;
+
+	if(lstat64(path, &buf) < 0) 
+		return(-errno);
+	if(dev_out != NULL) *dev_out = buf.st_dev;
+
+	/* See the Makefile for why STAT64_INO_FIELD is passed in
+	 * by the build
+	 */
+	if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
+	if(mode_out != NULL) *mode_out = buf.st_mode;
+	if(nlink_out != NULL) *nlink_out = buf.st_nlink;
+	if(uid_out != NULL) *uid_out = buf.st_uid;
+	if(gid_out != NULL) *gid_out = buf.st_gid;
+	if(size_out != NULL) *size_out = buf.st_size;
+	if(atime_out != NULL) *atime_out = buf.st_atime;
+	if(mtime_out != NULL) *mtime_out = buf.st_mtime;
+	if(ctime_out != NULL) *ctime_out = buf.st_ctime;
+	if(blksize_out != NULL) *blksize_out = buf.st_blksize;
+	if(blocks_out != NULL) *blocks_out = buf.st_blocks;
+	return(0);
+}
+
+int file_type(const char *path, int *rdev)
+{
+ 	struct stat64 buf;
+
+	if(lstat64(path, &buf) < 0) return(-errno);
+	*rdev = buf.st_rdev;
+	if(S_ISDIR(buf.st_mode)) return(HOSTFS_DIR);
+	else if(S_ISLNK(buf.st_mode)) return(HOSTFS_SYMLINK);
+	else if(S_ISCHR(buf.st_mode)) return(HOSTFS_CHARDEV);
+	else if(S_ISBLK(buf.st_mode)) return(HOSTFS_BLOCDEV);
+	else if(S_ISFIFO(buf.st_mode))return(HOSTFS_FIFO);
+	else if(S_ISSOCK(buf.st_mode))return(HOSTFS_SOCK);
+
+	else return(HOSTFS_FILE);
+}
+
+int access_file(char *path, int r, int w, int x)
+{
+	int mode = 0;
+
+	if(r) mode = R_OK;
+	if(w) mode |= W_OK;
+	if(x) mode |= X_OK;
+	if(access(path, mode) != 0) return(-errno);
+	else return(0);
+}
+
+int open_file(char *path, int r, int w)
+{
+	int mode = 0, fd;
+
+	if(r && !w) mode = O_RDONLY;
+	else if(!r && w) mode = O_WRONLY;
+	else if(r && w) mode = O_RDWR;
+	else panic("Impossible mode in open_file");
+	fd = open64(path, mode);
+	if(fd < 0) return(-errno);
+	else return(fd);
+}
+
+void *open_dir(char *path, int *err_out)
+{
+	DIR *dir;
+
+	dir = opendir(path);
+	*err_out = errno;
+	if(dir == NULL) return(NULL);
+	return(dir);
+}
+
+char *read_dir(void *stream, unsigned long long *pos, 
+	       unsigned long long *ino_out, int *len_out)
+{
+	DIR *dir = stream;
+	struct dirent *ent;
+
+	seekdir(dir, *pos);
+	ent = readdir(dir);
+	if(ent == NULL) return(NULL);
+	*len_out = strlen(ent->d_name);
+	*ino_out = ent->d_ino;
+	*pos = telldir(dir);
+	return(ent->d_name);
+}
+
+int read_file(int fd, unsigned long long *offset, char *buf, int len)
+{
+	int n;
+
+	n = pread64(fd, buf, len, *offset);
+	if(n < 0) return(-errno);
+	*offset += n;
+	return(n);
+}
+
+int write_file(int fd, unsigned long long *offset, const char *buf, int len)
+{
+	int n;
+
+	n = pwrite64(fd, buf, len, *offset);
+	if(n < 0) return(-errno);
+	*offset += n;
+	return(n);
+}
+
+int lseek_file(int fd, long long offset, int whence)
+{
+	int ret;
+
+	ret = lseek64(fd, offset, whence);
+	if(ret < 0) return(-errno);
+	return(0);
+}
+
+void close_file(void *stream)
+{
+	close(*((int *) stream));
+}
+
+void close_dir(void *stream)
+{
+	closedir(stream);
+}
+
+int file_create(char *name, int ur, int uw, int ux, int gr, 
+		int gw, int gx, int or, int ow, int ox)
+{
+	int mode, fd;
+
+	mode = 0;
+	mode |= ur ? S_IRUSR : 0;
+	mode |= uw ? S_IWUSR : 0;
+	mode |= ux ? S_IXUSR : 0;
+	mode |= gr ? S_IRGRP : 0;
+	mode |= gw ? S_IWGRP : 0;
+	mode |= gx ? S_IXGRP : 0;
+	mode |= or ? S_IROTH : 0;
+	mode |= ow ? S_IWOTH : 0;
+	mode |= ox ? S_IXOTH : 0;
+	fd = open64(name, O_CREAT, mode);
+	if(fd < 0) return(-errno);
+	close(fd);
+	return(0);
+}
+
+int set_attr(const char *file, struct hostfs_iattr *attrs)
+{
+	struct utimbuf buf;
+	int err, ma;
+
+	if(attrs->ia_valid & HOSTFS_ATTR_MODE){
+		if(chmod(file, attrs->ia_mode) != 0) return(-errno);
+	}
+	if(attrs->ia_valid & HOSTFS_ATTR_UID){
+		if(chown(file, attrs->ia_uid, -1)) return(-errno);
+	}
+	if(attrs->ia_valid & HOSTFS_ATTR_GID){
+		if(chown(file, -1, attrs->ia_gid)) return(-errno);
+	}
+	if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
+		if(truncate(file, attrs->ia_size)) return(-errno);
+	}
+	ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
+	if((attrs->ia_valid & ma) == ma){
+		buf.actime = attrs->ia_atime;
+		buf.modtime = attrs->ia_mtime;
+		if(utime(file, &buf) != 0) return(-errno);
+	}
+	else {
+		if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
+			err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+					NULL, NULL, NULL, &buf.modtime, NULL,
+					NULL, NULL);
+			if(err != 0) return(err);
+			buf.actime = attrs->ia_atime;
+			if(utime(file, &buf) != 0) return(-errno);
+		}
+		if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
+			err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+					NULL, NULL, &buf.actime, NULL, NULL, 
+					NULL, NULL);
+			if(err != 0) return(err);
+			buf.modtime = attrs->ia_mtime;
+			if(utime(file, &buf) != 0) return(-errno);
+		}
+	}
+	if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
+	if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
+		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+				NULL, NULL, &attrs->ia_atime, &attrs->ia_mtime,
+				NULL, NULL, NULL);
+		if(err != 0) return(err);
+	}
+	return(0);
+}
+
+int make_symlink(const char *from, const char *to)
+{
+	int err;
+
+	err = symlink(to, from);
+	if(err) return(-errno);
+	return(0);
+}
+
+int unlink_file(const char *file)
+{
+	int err;
+
+	err = unlink(file);
+	if(err) return(-errno);
+	return(0);
+}
+
+int do_mkdir(const char *file, int mode)
+{
+	int err;
+
+	err = mkdir(file, mode);
+	if(err) return(-errno);
+	return(0);
+}
+
+int do_rmdir(const char *file)
+{
+	int err;
+
+	err = rmdir(file);
+	if(err) return(-errno);
+	return(0);
+}
+
+int do_mknod(const char *file, int mode, int dev)
+{
+	int err;
+
+	err = mknod(file, mode, dev);
+	if(err) return(-errno);
+	return(0);
+}
+
+int link_file(const char *to, const char *from)
+{
+	int err;
+
+	err = link(to, from);
+	if(err) return(-errno);
+	return(0);
+}
+
+int do_readlink(char *file, char *buf, int size)
+{
+	int err;
+
+	err = readlink(file, buf, size);
+	if(err < 0) return(-errno);
+	if(err < size) buf[err] = '\0';
+	return(0);	
+}
+
+int rename_file(char *from, char *to)
+{
+	int err;
+
+	err = rename(from, to);
+	if(err < 0) return(-errno);
+	return(0);	
+}
+
+int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
+	      long long *bfree_out, long long *bavail_out, 
+	      long long *files_out, long long *ffree_out,
+	      void *fsid_out, int fsid_size, long *namelen_out, 
+	      long *spare_out)
+{
+	struct statfs64 buf;
+	int err;
+
+	err = statfs64(root, &buf);
+	if(err < 0) return(-errno);
+	*bsize_out = buf.f_bsize;
+	*blocks_out = buf.f_blocks;
+	*bfree_out = buf.f_bfree;
+	*bavail_out = buf.f_bavail;
+	*files_out = buf.f_files;
+	*ffree_out = buf.f_ffree;
+	memcpy(fsid_out, &buf.f_fsid, 
+	       sizeof(buf.f_fsid) > fsid_size ? fsid_size : 
+	       sizeof(buf.f_fsid));
+	*namelen_out = buf.f_namelen;
+	spare_out[0] = buf.f_spare[0];
+	spare_out[1] = buf.f_spare[1];
+	spare_out[2] = buf.f_spare[2];
+	spare_out[3] = buf.f_spare[3];
+	spare_out[4] = buf.f_spare[4];
+	spare_out[5] = buf.f_spare[5];
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/2_5compat.h linux-2.4.19-pre5-mjc/arch/um/include/2_5compat.h
--- linux/arch/um/include/2_5compat.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/2_5compat.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,121 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __2_5_COMPAT_H__
+#define __2_5_COMPAT_H__
+
+#include "linux/version.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+
+#define major(dev) MAJOR(dev)
+#define minor(dev) MINOR(dev)
+#define kdev_same(dev1, dev2) ((dev1) == (dev2))
+#define mk_kdev(maj, min) MKDEV(maj, min)
+#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
+	name :		dev_name, \
+	write :		write_proc, \
+	read :		NULL, \
+	device :	device_proc, \
+	wait_key :	NULL, \
+	unblank :	NULL, \
+	setup :		setup_proc, \
+	flags :		f, \
+	index :		-1, \
+	cflag :		0, \
+	next :		NULL \
+}
+
+#define INIT_GENDISK(maj, name, parts, bsizes, max, blops) { \
+	major :		maj, \
+	major_name : 	name, \
+	minor_shift :	0, \
+	max_p : 	1, \
+	part : 		parts, \
+	sizes : 	bsizes, \
+	nr_real : 	max, \
+	real_devices : 	NULL, \
+	next : 		NULL, \
+	fops : 		blops, \
+	de_arr : 	NULL, \
+	flags : 	0 \
+}
+
+#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request)
+
+#define ELV_NOOP ELEVATOR_NOOP
+#define INIT_ELV(queue, elv) elevator_init(elv, ELV_NOOP)
+
+#define REQUEST_LOCK io_request_lock
+
+#define INIT_HARDSECT(arr, maj, sizes) arr[maj] = sizes
+
+#define IS_WRITE(req) ((req)->cmd == WRITE)
+#define IS_READ(req) ((req)->cmd == READ)
+
+#define CPU(task) ((task)->processor)
+
+#define yield() do { current->policy |= SCHED_YIELD; schedule(); } while(0)
+
+#define SET_PRI(task) \
+	do { (task)->nice = 20; (task)->counter = -100; } while(0);
+
+#else
+
+#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
+	name :		dev_name, \
+	write :		write_proc, \
+	read :		NULL, \
+	device :	device_proc, \
+	setup :		setup_proc, \
+	flags :		f, \
+	index :		-1, \
+	cflag :		0, \
+	next :		NULL \
+}
+
+#define INIT_GENDISK(maj, name, parts, bsizes, max, blops) { \
+	major :		maj, \
+	major_name : 	name, \
+	minor_shift :	0, \
+	part : 		parts, \
+	sizes : 	bsizes, \
+	nr_real : 	max, \
+	next : 		NULL, \
+	fops : 		blops, \
+	de_arr : 	NULL, \
+	flags : 	0 \
+}
+
+#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock)
+
+#define ELV_NOOP elevator_noop
+#define INIT_ELV(queue, elv) elevator_init(queue, elv, ELV_NOOP)
+
+#define REQUEST_LOCK ubd_lock
+
+#define INIT_HARDSECT(arr, maj, sizes)
+
+#define IS_WRITE(req) (rq_data_dir(req) == WRITE)
+#define IS_READ(req) (rq_data_dir(req) == READ)
+
+#define CPU(task) ((task)->cpu)
+
+#define SET_PRI(task) do ; while(0)
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/Makefile linux-2.4.19-pre5-mjc/arch/um/include/Makefile
--- linux/arch/um/include/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,7 @@
+all : sc.h
+
+sc.h : ../util/mk_sc
+	../util/mk_sc > $@
+
+../util/mk_sc :
+	$(MAKE) -C ../util mk_sc
diff -Nru linux/arch/um/include/chan_kern.h linux-2.4.19-pre5-mjc/arch/um/include/chan_kern.h
--- linux/arch/um/include/chan_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/chan_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __CHAN_KERN_H__
+#define __CHAN_KERN_H__
+
+#include "linux/tty.h"
+#include "linux/list.h"
+#include "chan_user.h"
+
+struct chan {
+	struct list_head list;
+	unsigned int primary:1;
+	unsigned int input:1;
+	unsigned int output:1;
+	unsigned int opened:1;
+	int fd;
+	enum chan_init_pri pri;
+	struct chan_ops *ops;
+	void *data;
+};
+
+extern void chan_interrupt(struct list_head *chans, struct tty_struct *tty,
+			   int irq);
+extern int parse_chan_pair(char *str, struct list_head *chans, int pri, 
+			   int device, struct chan_opts *opts);
+extern int open_chan(struct list_head *chans);
+extern int write_chan(struct list_head *chans, const char *buf, int len,
+			     int write_irq);
+extern int console_write_chan(struct list_head *chans, const char *buf, 
+			      int len);
+extern void close_chan(struct list_head *chans);
+extern void chan_enable_winch(struct list_head *chans, void *line);
+extern void enable_chan(struct list_head *chans, 
+			int (*irq_setup)(int fd, int input, int output, 
+					 void *data), 
+			void *data);
+extern void disable_chan(struct list_head *chans, int irq, void *dev);
+extern int chan_window_size(struct list_head *chans, 
+			     unsigned short *rows_out, 
+			     unsigned short *cols_out);
+extern int chan_out_fd(struct list_head *chans);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/chan_user.h linux-2.4.19-pre5-mjc/arch/um/include/chan_user.h
--- linux/arch/um/include/chan_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/chan_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,66 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __CHAN_USER_H__
+#define __CHAN_USER_H__
+
+#include "init.h"
+
+struct chan_opts {
+	void (*announce)(char *dev_name, int dev);
+	char *xterm_title;
+	int raw;
+};
+
+enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
+
+struct chan_ops {
+	void *(*init)(char *, int, struct chan_opts *);
+	int (*open)(int, int, int, void *);
+	void (*close)(int, void *);
+	int (*read)(int, void *);
+	int (*write)(int, const char *, int, void *);
+	int (*console_write)(int, const char *, int, void *);
+	int (*window_size)(int, void *, unsigned short *, unsigned short *);
+	void (*free)(void *);
+	int winch;
+};
+
+extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops,
+	tty_ops, xterm_ops;
+	
+
+extern void generic_close(int fd, void *unused);
+extern int generic_read(int fd, void *unused);
+extern int generic_write(int fd, const char *buf, int n, void *unused);
+extern int generic_console_write(int fd, const char *buf, int n, void *state);
+extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+			       unsigned short *cols_out);
+extern void generic_free(void *data);
+extern int getmaster(char *line);
+
+extern void register_winch(int fd, void *device_data);
+extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
+extern void setup_tracer_winch(void);
+
+#define __channel_help(fn, prefix) \
+__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
+"    Attach a console or serial line to a host channel.  See\n" \
+"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
+"    description of this switch.\n\n" \
+);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/debug.h linux-2.4.19-pre5-mjc/arch/um/include/debug.h
--- linux/arch/um/include/debug.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/debug.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and
+ * Lars Brinkhoff.
+ * Licensed under the GPL
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+extern int debugger_proxy(int status, pid_t pid);
+extern void child_proxy(pid_t pid, int status);
+extern void init_proxy (pid_t pid, int waiting, int status);
+extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
+extern void fake_child_exit(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/frame.h linux-2.4.19-pre5-mjc/arch/um/include/frame.h
--- linux/arch/um/include/frame.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/frame.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,51 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_H_
+#define __FRAME_H_
+
+#include "sysdep/frame.h"
+
+struct sc_frame {
+	void *data;
+	int len;
+	int sig_index;
+	int sc_index;
+	int sr_index;
+	int sr_relative;
+	int sp_index;
+	struct arch_frame_data arch;
+};
+
+extern struct sc_frame signal_frame_sc;
+
+struct si_frame {
+	void *data;
+	int len;
+	int sig_index;
+	int sip_index;
+	int si_index;
+	int sr_index;
+	int sr_relative;
+	int sp_index;
+};
+
+extern struct si_frame signal_frame_si;
+
+extern void capture_signal_stack(void);
+extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/frame_kern.h linux-2.4.19-pre5-mjc/arch/um/include/frame_kern.h
--- linux/arch/um/include/frame_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/frame_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,35 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_KERN_H_
+#define __FRAME_KERN_H_
+
+extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 
+				 unsigned long handler,
+				 void (*restorer)(void), 
+				 struct pt_regs *regs, 
+				 void *context_sc, 
+				 struct arch_signal_context *arch, 
+				 sigset_t *mask);
+extern int setup_signal_stack_si(unsigned long stack_top, int sig, 
+				 unsigned long handler, 
+				 void (*restorer)(void), 
+				 struct pt_regs *regs, void *context_sc, 
+				 siginfo_t *info, 
+				 struct arch_signal_context *arch, 
+				 sigset_t *mask);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/hostaudio.h linux-2.4.19-pre5-mjc/arch/um/include/hostaudio.h
--- linux/arch/um/include/hostaudio.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/hostaudio.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#ifndef HOSTAUDIO_H
+#define HOSTAUDIO_H
+
+#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
+#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
+
+struct hostaudio_state {
+  int fd;
+};
+
+struct hostmixer_state {
+  int fd;
+};
+
+/* UML user-side protoypes */
+extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
+				   size_t count, loff_t *ppos);
+extern ssize_t hostaudio_write_user(struct hostaudio_state *state, 
+				    const char *buffer, size_t count, 
+				    loff_t *ppos);
+extern int hostaudio_ioctl_user(struct hostaudio_state *state, 
+				unsigned int cmd, unsigned long arg);
+extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, 
+			       char *dsp);
+extern int hostaudio_release_user(struct hostaudio_state *state);
+extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
+				unsigned int cmd, unsigned long arg);
+extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, 
+				      int w, char *mixer);
+extern int hostmixer_release_mixdev_user(struct hostmixer_state *state);
+
+#endif /* HOSTAUDIO_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/init.h linux-2.4.19-pre5-mjc/arch/um/include/init.h
--- linux/arch/um/include/init.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/init.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,106 @@
+#ifndef _LINUX_UML_INIT_H
+#define _LINUX_UML_INIT_H
+
+/* These macros are used to mark some functions or
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ *
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * If the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * You should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * Don't forget to initialize data not at file scope, i.e. within a function,
+ * as gcc otherwise puts the data into the bss section and not into the init
+ * section.
+ *
+ * Also note, that this data cannot be "const".
+ */
+
+#ifndef _LINUX_INIT_H
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init          __attribute__ ((__section__ (".text.init")))
+#define __exit          __attribute__ ((unused, __section__(".text.exit")))
+#define __initdata      __attribute__ ((__section__ (".data.init")))
+
+#endif
+struct uml_param {
+        const char *str;
+        int (*setup_func)(char *, int *);
+};
+
+extern initcall_t __uml_initcall_start, __uml_initcall_end;
+extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
+extern const char *__uml_help_start, *__uml_help_end;
+
+#define __uml_initcall(fn)					  	\
+	static initcall_t __uml_initcall_##fn __uml_init_call = fn
+
+#define __uml_exitcall(fn)						\
+	static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
+
+extern struct uml_param __uml_setup_start, __uml_setup_end;
+
+#define __uml_postsetup(fn)						\
+	static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
+
+#define __non_empty_string(dummyname,string)				\
+	struct __uml_non_empty_string_struct_##dummyname		\
+	{								\
+		char _string[sizeof(string)-2];				\
+	}
+
+#define __uml_setup(str, fn, help...)					\
+	__non_empty_string(fn ##_setup, str);				\
+	__uml_help(fn, help);						\
+	static char __uml_setup_str_##fn[] __initdata = str;		\
+	static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
+
+#define __uml_help(fn, help...)						\
+	__non_empty_string(fn ##__help, help);				\
+	static char __uml_help_str_##fn[] __initdata = help;		\
+	static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
+
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __uml_init_setup	__attribute__ ((unused,__section__ (".uml.setup.init")))
+#define __uml_setup_help	__attribute__ ((unused,__section__ (".uml.help.init")))
+#define __uml_init_call		__attribute__ ((unused,__section__ (".uml.initcall.init")))
+#define __uml_postsetup_call	__attribute__ ((unused,__section__ (".uml.postsetup.init")))
+#define __uml_exit_call		__attribute__ ((unused,__section__ (".uml.exitcall.exit")))
+
+#endif /* _LINUX_UML_INIT_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/initrd.h linux-2.4.19-pre5-mjc/arch/um/include/initrd.h
--- linux/arch/um/include/initrd.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/initrd.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __INITRD_USER_H__
+#define __INITRD_USER_H__
+
+extern int load_initrd(char *filename, void *buf, int size);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/irq_user.h linux-2.4.19-pre5-mjc/arch/um/include/irq_user.h
--- linux/arch/um/include/irq_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/irq_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,32 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __IRQ_USER_H__
+#define __IRQ_USER_H__
+
+enum { IRQ_READ, IRQ_WRITE };
+
+extern void sigio_handler(int sig, struct uml_pt_regs *regs);
+extern int activate_fd(int irq, int fd, int type, void *dev_id);
+extern void free_irq_by_dev(void *dev_id);
+extern void free_irq_by_fd(int fd);
+extern void reactivate_fd(int fd, int irqnum);
+extern void deactivate_fd(int fd, int irqnum);
+extern void forward_interrupts(int pid);
+extern void init_irq_signals(int on_sigstack);
+extern void forward_ipi(int fd, int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/kern.h linux-2.4.19-pre5-mjc/arch/um/include/kern.h
--- linux/arch/um/include/kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __KERN_H__
+#define __KERN_H__
+
+/* These are all user-mode things which are convenient to call directly
+ * from kernel code and for which writing a wrapper is too much of a pain.
+ * The regular include files can't be included because this file is included
+ * only into kernel code, and user-space includes conflict with kernel
+ * includes.
+ */
+
+extern int errno;
+
+extern int getpid(void);
+extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
+extern int sleep(int);
+extern int printf(char *fmt, ...);
+extern char *strerror(int errnum);
+extern char *ptsname(int __fd);
+extern int munmap(void *, int);
+extern void *sbrk(int increment);
+extern void *malloc(int size);
+extern void perror(char *err);
+extern int kill(int pid, int sig);
+extern int getuid(void);
+extern int pause(void);
+extern int write(int, const void *, int);
+extern int exit(int);
+extern int close(int);
+extern int read(unsigned int, char *, int);
+extern int pipe(int *);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/kern_util.h linux-2.4.19-pre5-mjc/arch/um/include/kern_util.h
--- linux/arch/um/include/kern_util.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/kern_util.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,125 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __KERN_UTIL_H__
+#define __KERN_UTIL_H__
+
+#include "sysdep/ptrace.h"
+
+extern int ncpus;
+extern char *linux_prog;
+extern char *gdb_init;
+extern int kmalloc_ok;
+
+#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
+#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
+
+extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
+extern unsigned long stack_sp(unsigned long page);
+extern int kernel_thread_proc(void *data);
+extern void syscall_segv(int sig);
+extern int current_pid(void);
+extern void set_init_pid(int pid);
+extern unsigned long alloc_stack(void);
+extern int do_signal(int error);
+extern int is_stack_fault(unsigned long sp);
+extern unsigned long segv(unsigned long address, unsigned long ip, 
+			  int is_write, int is_user);
+extern int set_user_mode(void *task, int protect_mem);
+extern void syscall_ready(void);
+extern void set_tracing(void *t, int tracing);
+extern int is_tracing(void *task);
+extern int segv_syscall(void);
+extern void ret_from_sys_call(void);
+extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
+extern int page_size(void);
+extern int page_mask(void);
+extern int need_finish_fork(void);
+extern int do_proc_op(void *t, int proc_id);
+extern void free_stack(unsigned long stack);
+extern void add_input_request(int op, void (*proc)(int), void *arg);
+extern int sys_execve(char *file, char **argv, char **env);
+extern char *current_cmd(void);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
+extern int set_signals(int enable);
+extern void force_sigbus(void);
+extern int pid_to_processor_id(int pid);
+extern void block_signals(void);
+extern void unblock_signals(void);
+extern void deliver_signals(void *t);
+extern void lock_syscall(void);
+extern void unlock_syscall(void);
+extern void lock_trap(void);
+extern void unlock_trap(void);
+extern void lock_pid(void);
+extern void unlock_pid(void);
+extern void cpu_idle(void);
+extern void finish_fork(void);
+extern void paging_init(void);
+extern unsigned long um_virt_to_phys(void *t, unsigned long addr);
+extern void init_flush_vm(void);
+extern void *syscall_sp(void *t);
+extern void syscall_trace(void);
+extern int hz(void);
+extern void idle_timer(void);
+extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
+extern int external_pid(void *t);
+extern int pid_to_processor_id(int pid);
+extern void boot_timer_handler(int sig);
+extern void interrupt_end(void);
+extern void tracing_reboot(void);
+extern void tracing_halt(void);
+extern void tracing_cb(void (*proc)(void *), void *arg);
+extern int debugger_signal(int status, int pid);
+extern void child_signal(int pid, int status);
+extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
+extern void check_stack_overflow(void *ptr);
+extern void relay_signal(int sig, struct uml_pt_regs *regs);
+extern int singlestepping(void *t);
+extern void not_implemented(void);
+extern int user_context(unsigned long sp);
+extern void timer_irq(struct uml_pt_regs *regs);
+extern void unprotect_stack(unsigned long stack);
+extern void do_exitcalls(void);
+extern void do_uml_exitcalls(void);
+extern int attach_debugger(int idle_pid, int pid, int stop);
+extern void *round_up(unsigned long addr);
+extern void *round_down(unsigned long addr);
+extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
+extern int config_gdb(char *str);
+extern int remove_gdb(void);
+extern char *uml_strdup(char *string);
+extern void unprotect_kernel_mem(int delay_signals);
+extern void protect_kernel_mem(int delay_signals);
+extern unsigned long get_kmem_end(void);
+extern void set_kmem_end(unsigned long);
+extern void set_task_sizes(int arg);
+extern void uml_cleanup(void);
+extern int pid_to_processor_id(int pid);
+extern void set_current(void *t);
+extern void lock_signalled_task(void *t);
+extern void IPI_handler(int cpu);
+extern int jail_setup(char *line, int *add);
+extern void *get_init_task(void);
+extern int copy_to_user_proc(void *to, void *from, int size);
+extern int copy_from_user_proc(void *to, void *from, int size);
+extern void set_thread_sc(void *sc);
+extern void bus_handler(int sig, struct uml_pt_regs *regs);
+extern long execute_syscall(void *r);
+extern int smp_sigio_handler(void);
+extern void *get_current(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/line.h linux-2.4.19-pre5-mjc/arch/um/include/line.h
--- linux/arch/um/include/line.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/line.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,65 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __LINE_H__
+#define __LINE_H__
+
+#include "linux/list.h"
+#include "asm/semaphore.h"
+#include "chan_user.h"
+
+struct line {
+	char *init_str;
+	int init_pri;
+	struct list_head chan_list;
+	int valid;
+	int count;
+	struct tty_struct *tty;
+	struct semaphore sem;
+	char *buffer;
+	char *head;
+	char *tail;
+	int write_irq;
+	int sigio;
+};
+
+#define LINE_INIT(str, irq) \
+	{ init_str :	str, \
+	  init_pri :	INIT_STATIC, \
+	  chan_list : 	{ }, \
+	  valid :	1, \
+	  count :	0, \
+	  tty :		NULL, \
+	  sem : 	{ }, \
+	  buffer :	NULL, \
+	  head :	NULL, \
+	  tail :	NULL, \
+	  write_irq :	irq, \
+	  sigio :	0 }
+ 
+
+extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
+extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
+extern void line_close(struct line *lines, int n, int irq);
+extern int line_open(struct line *lines, int n, struct tty_struct *tty, 
+		     int (*setup_irq)(int fd, int input, int output, 
+				      void *data),
+		     struct chan_opts *opts);
+extern void line_setup(struct line *lines, int num, char *init);
+extern int line_write(struct line *line, const char *buf, int len);
+extern int line_write_room(struct tty_struct *tty);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/mconsole.h linux-2.4.19-pre5-mjc/arch/um/include/mconsole.h
--- linux/arch/um/include/mconsole.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/mconsole.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Licensed under the GPL
+ */
+
+#ifndef __MCONSOLE_H__
+#define __MCONSOLE_H__
+
+#define MCONSOLE_MAGIC (0xcafebabe)
+#define MCONSOLE_MAX_DATA (512)
+#define MCONSOLE_VERSION 1
+
+struct mconsole_request {
+	unsigned long magic;
+	int version;
+	int len;
+	char data[MCONSOLE_MAX_DATA];
+};
+
+struct mconsole_reply {
+	int err;
+	int more;
+	int len;
+	char data[MCONSOLE_MAX_DATA];
+};
+
+struct mc_request;
+
+struct mconsole_command
+{
+	char *command;
+	void (*handler)(struct mc_request *req);
+	int as_interrupt;
+};
+
+struct mc_request
+{
+	int len;
+	int as_interrupt;
+
+	int originating_fd;
+	int originlen;
+	unsigned char origin[128];			/* sockaddr_un */
+
+	struct mconsole_request request;
+	struct mconsole_command *cmd;
+};
+
+extern char mconsole_socket_name[];
+
+extern int mconsole_unlink_socket(void);
+extern int mconsole_reply(struct mc_request *req, char *reply, int err,
+			  int more);
+extern void mconsole_version(struct mc_request *req);
+extern void mconsole_help(struct mc_request *req);
+extern void mconsole_halt(struct mc_request *req);
+extern void mconsole_reboot(struct mc_request *req);
+extern void mconsole_config(struct mc_request *req);
+extern void mconsole_remove(struct mc_request *req);
+extern void mconsole_sysrq(struct mc_request *req);
+extern void mconsole_cad(struct mc_request *req);
+extern int mconsole_create_listening_socket(void);
+extern int mconsole_get_request(int fd, struct mc_request *req);
+extern void mconsole_open_for_business(char *socket);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/mconsole_kern.h linux-2.4.19-pre5-mjc/arch/um/include/mconsole_kern.h
--- linux/arch/um/include/mconsole_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/mconsole_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MCONSOLE_KERN_H__
+#define __MCONSOLE_KERN_H__
+
+#include "linux/config.h"
+#include "linux/list.h"
+#include "mconsole.h"
+
+struct mconsole_entry {
+	struct list_head list;
+	struct mc_request request;
+};
+
+struct mc_device {
+	struct list_head list;
+	char *name;
+	int (*config)(char *);
+	int (*remove)(char *);
+};
+
+#ifdef CONFIG_MCONSOLE
+
+extern void mconsole_register_dev(struct mc_device *new);
+
+#else
+
+static inline void mconsole_register_dev(struct mc_device *new)
+{
+}
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/mem_user.h linux-2.4.19-pre5-mjc/arch/um/include/mem_user.h
--- linux/arch/um/include/mem_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/mem_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,64 @@
+/*
+ * arch/um/include/mem_user.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * user side memory interface for support IO memory inside user mode linux
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEM_USER_H
+#define _MEM_USER_H
+
+#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
+
+extern unsigned long host_task_size;
+extern unsigned long task_size;
+
+extern int init_mem_user(void);
+extern int create_mem_file(unsigned long len);
+extern void setup_range(int fd, char *driver, unsigned long start,
+			unsigned long usable, unsigned long total);
+extern int map(unsigned long virt, void *p, unsigned long len, 
+		int r, int w, int x);
+extern int unmap(void *addr, int len);
+extern int protect(unsigned long addr, unsigned long len, int r, int w, 
+		   int x, int must_succeed);
+extern int parse_iomem(char *str, int *add);
+extern void setup_memory(void);
+extern unsigned long find_iomem(char *driver, unsigned long *len_out);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/process.h linux-2.4.19-pre5-mjc/arch/um/include/process.h
--- linux/arch/um/include/process.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/process.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PROCESS_H__
+#define __PROCESS_H__
+
+#include <asm/sigcontext.h>
+
+extern void sig_handler(int sig, struct sigcontext sc);
+extern void irq_handler(int sig, struct sigcontext sc);
+extern void alarm_handler(int sig, struct sigcontext sc);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/ptrace_user.h linux-2.4.19-pre5-mjc/arch/um/include/ptrace_user.h
--- linux/arch/um/include/ptrace_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/ptrace_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,15 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PTRACE_USER_H__
+#define __PTRACE_USER_H__
+
+#include <linux/ptrace.h>
+#include "sysdep/ptrace_user.h"
+
+extern int ptrace_getregs(long pid, unsigned long *regs_out);
+extern int ptrace_setregs(long pid, unsigned long *regs_in);
+
+#endif
diff -Nru linux/arch/um/include/sigcontext.h linux-2.4.19-pre5-mjc/arch/um/include/sigcontext.h
--- linux/arch/um/include/sigcontext.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sigcontext.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UML_SIGCONTEXT_H__
+#define __UML_SIGCONTEXT_H__
+
+#include "sysdep/sigcontext.h"
+
+extern int sc_size(void *data);
+extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data);
+extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data);
+extern void sc_to_sc(void *to_ptr, void *from_ptr);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sigcontext_kern.h linux-2.4.19-pre5-mjc/arch/um/include/sigcontext_kern.h
--- linux/arch/um/include/sigcontext_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sigcontext_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UML_SIGCONTEXT_KERN_H__
+#define __UML_SIGCONTEXT_KERN_H__
+
+#include "asm/signal.h"
+
+extern int copy_sigmask_from_user(sigset_t *mask, void *sc, 
+				  struct arch_signal_context *arch);
+extern int copy_sigmask_to_user(sigset_t *mask, void *sc, 
+				struct arch_signal_context *arch);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sigio.h linux-2.4.19-pre5-mjc/arch/um/include/sigio.h
--- linux/arch/um/include/sigio.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sigio.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGIO_H__
+#define __SIGIO_H__
+
+extern int write_sigio_irq(int fd);
+extern int register_sigio_fd(int fd);
+extern int read_sigio_fd(int fd);
+extern int add_sigio_fd(int fd);
+extern int ignore_sigio_fd(int fd);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/signal_kern.h linux-2.4.19-pre5-mjc/arch/um/include/signal_kern.h
--- linux/arch/um/include/signal_kern.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/signal_kern.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGNAL_KERN_H__
+#define __SIGNAL_KERN_H__
+
+#include "sysdep/ptrace.h"
+
+extern void signal_deliverer(int sig);
+extern int probe_stack(unsigned long sp, int delta);
+extern int have_signals(void *t);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/signal_user.h linux-2.4.19-pre5-mjc/arch/um/include/signal_user.h
--- linux/arch/um/include/signal_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/signal_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGNAL_USER_H__
+#define __SIGNAL_USER_H__
+
+extern int signal_stack_size;
+
+extern int change_sig(int signal, int on);
+extern void set_sigstack(void *stack, int size);
+extern void set_handler(int sig, void (*handler)(int), int flags, ...);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/syscall_user.h linux-2.4.19-pre5-mjc/arch/um/include/syscall_user.h
--- linux/arch/um/include/syscall_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/syscall_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSCALL_USER_H__
+#define __SYSCALL_USER_H__
+
+#include <asm/sigcontext.h>
+
+extern void syscall_handler(int sig, struct sigcontext sc);
+extern void exit_kernel(int pid, void *task);
+extern int do_syscall(void *task, int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-i386/frame.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/frame.h
--- linux/arch/um/include/sysdep-i386/frame.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/frame.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,89 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_I386_H
+#define __FRAME_I386_H
+
+#include <asm/page.h>
+
+/* This stuff is to calculate the size of the fp state struct at runtime
+ * because it has changed between 2.2 and 2.4 and it would be good for a
+ * UML compiled on one to work on the other.
+ * So, setup_arch_frame_raw fills in the arch struct with the raw data, which
+ * just contains the address of the end of the sigcontext.  This is invoked
+ * from the signal handler.
+ * setup_arch_frame uses that data to figure out what 
+ * arch_frame_data.fpstate_size should be.  It really has no idea, since it's
+ * not allowed to do sizeof(struct fpstate) but it's safe to consider that it's
+ * everything from the end of the sgcontext up to the top of the stack.  So,
+ * it masks off the page number to get the offset within the page and subtracts
+ * that from the page size, and that's how big the fpstate struct will be
+ * considered to be.
+ */
+
+struct arch_frame_data_raw {
+	unsigned long sc_end;
+};
+
+static inline void setup_arch_frame_raw(struct arch_frame_data_raw *data,
+					struct sigcontext *sc)
+{
+	data->sc_end = (unsigned long) sc;
+	data->sc_end += sizeof(*sc);
+}
+
+struct arch_frame_data {
+	int fpstate_size;
+};
+
+static inline void setup_arch_frame(struct arch_frame_data_raw *in, 
+				    struct arch_frame_data *out)
+{
+	unsigned long fpstate_start = in->sc_end;
+
+	fpstate_start &= ~PAGE_MASK;
+	out->fpstate_size = PAGE_SIZE - fpstate_start;
+}
+
+/* This figures out where on the stack the SA_RESTORER function address
+ * is stored.  For i386, it's the signal handler return address, so it's
+ * located next to the frame pointer.
+ * This is inlined, so __builtin_frame_address(0) is correct.  Otherwise,
+ * it would have to be __builtin_frame_address(1).
+ */
+
+static inline unsigned long frame_restorer(void)
+{
+	unsigned long *fp;
+
+	fp = __builtin_frame_address(0);
+	return((unsigned long) (fp + 1));
+}
+
+/* Similarly, this returns the value of sp when the handler was first
+ * entered.  This is used to calculate the proper sp when delivering
+ * signals.
+ */
+
+static inline unsigned long frame_sp(void)
+{
+	unsigned long *fp;
+
+	fp = __builtin_frame_address(0);
+	return((unsigned long) (fp + 1));
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-i386/ptrace.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/ptrace.h
--- linux/arch/um/include/sysdep-i386/ptrace.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/ptrace.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,114 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_PTRACE_H
+#define __SYSDEP_I386_PTRACE_H
+
+#include "sysdep/sc.h"
+
+struct uml_pt_regs {
+	unsigned long args[6];
+	long syscall;
+	int is_user;
+	void *sc;
+};
+
+#define EMPTY_UML_PT_REGS { \
+	syscall : 	-1, \
+	args : 		{ [0 ... 5] = 0 }, \
+	is_user :	0, \
+	sc : 		NULL }
+
+#define UPT_IP(regs) SC_IP((regs)->sc)
+#define UPT_SP(regs) SC_SP((regs)->sc)
+#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc)
+#define UPT_EAX(regs) SC_EAX((regs)->sc)
+#define UPT_EBX(regs) SC_EBX((regs)->sc)
+#define UPT_ECX(regs) SC_ECX((regs)->sc)
+#define UPT_EDX(regs) SC_EDX((regs)->sc)
+#define UPT_ESI(regs) SC_ESI((regs)->sc)
+#define UPT_EDI(regs) SC_EDI((regs)->sc)
+#define UPT_EBP(regs) SC_EBP((regs)->sc)
+#define UPT_ORIG_EAX(regs) ((regs)->syscall)
+#define UPT_CS(regs) SC_CS((regs)->sc)
+#define UPT_SS(regs) SC_SS((regs)->sc)
+#define UPT_DS(regs) SC_DS((regs)->sc)
+#define UPT_ES(regs) SC_ES((regs)->sc)
+#define UPT_FS(regs) SC_FS((regs)->sc)
+#define UPT_GS(regs) SC_GS((regs)->sc)
+
+#define UPT_REG(regs, reg) \
+	({	unsigned long val; \
+		switch(reg){ \
+		case EIP: val = UPT_IP(regs); break; \
+		case UESP: val = UPT_SP(regs); break; \
+		case EAX: val = UPT_EAX(regs); break; \
+		case EBX: val = UPT_EBX(regs); break; \
+		case ECX: val = UPT_ECX(regs); break; \
+		case EDX: val = UPT_EDX(regs); break; \
+		case ESI: val = UPT_ESI(regs); break; \
+		case EDI: val = UPT_EDI(regs); break; \
+		case EBP: val = UPT_EBP(regs); break; \
+		case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \
+		case CS: val = UPT_CS(regs); break; \
+		case SS: val = UPT_SS(regs); break; \
+		case DS: val = UPT_DS(regs); break; \
+		case ES: val = UPT_ES(regs); break; \
+		case FS: val = UPT_FS(regs); break; \
+		case GS: val = UPT_GS(regs); break; \
+		case EFL: val = UPT_EFLAGS(regs); break; \
+		default :  \
+			panic("Bad register in UPT_REG : %d\n", reg);  \
+			val = -1; \
+		} \
+	        val; \
+	})
+	
+
+#define UPT_SET(regs, reg, val) \
+	do { \
+		switch(reg){ \
+		case EIP: UPT_IP(regs) = val; break; \
+		case UESP: UPT_SP(regs) = val; break; \
+		case EAX: UPT_EAX(regs) = val; break; \
+		case EBX: UPT_EBX(regs) = val; break; \
+		case ECX: UPT_ECX(regs) = val; break; \
+		case EDX: UPT_EDX(regs) = val; break; \
+		case ESI: UPT_ESI(regs) = val; break; \
+		case EDI: UPT_EDI(regs) = val; break; \
+		case EBP: UPT_EBP(regs) = val; break; \
+		case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \
+		case CS: UPT_CS(regs) = val; break; \
+		case SS: UPT_SS(regs) = val; break; \
+		case DS: UPT_DS(regs) = val; break; \
+		case ES: UPT_ES(regs) = val; break; \
+		case FS: UPT_FS(regs) = val; break; \
+		case GS: UPT_GS(regs) = val; break; \
+		case EFL: UPT_EFLAGS(regs) = val; break; \
+		default :  \
+			panic("Bad register in UPT_SET : %d\n", reg);  \
+			break; \
+		} \
+	} while (0)
+
+#define UPT_SET_SYSCALL_RETURN(regs, res) \
+	SC_SET_SYSCALL_RETURN((regs)->sc, (res))
+#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc)
+#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs)
+#define UPT_SYSCALL_NR(regs) ((regs)->syscall)
+#define UPT_SYSCALL_RET(regs) UPT_EAX(regs)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-i386/ptrace_user.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/ptrace_user.h
--- linux/arch/um/include/sysdep-i386/ptrace_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/ptrace_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,45 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_PTRACE_USER_H__
+#define __SYSDEP_I386_PTRACE_USER_H__
+
+#include <asm/ptrace.h>
+
+#define PT_OFFSET(r) ((r) * sizeof(long))
+
+#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX])
+#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX)
+
+#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX)
+#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX)
+#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
+#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
+#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+
+#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
+
+#define PT_IP_OFFSET PT_OFFSET(EIP)
+#define PT_IP(regs) ((regs)[EIP])
+#define PT_SP(regs) ((regs)[UESP])
+
+#ifndef FRAME_SIZE
+#define FRAME_SIZE (17)
+#endif
+#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
+
+#define FP_FRAME_SIZE (27)
+#define FPX_FRAME_SIZE (128)
+
+#define UM_HAVE_GETREGS
+#define UM_HAVE_SETREGS
+
+#define UM_HAVE_GETFPREGS
+#define UM_HAVE_SETFPREGS
+
+#define UM_HAVE_GETFPXREGS
+#define UM_HAVE_SETFPXREGS
+
+#endif
diff -Nru linux/arch/um/include/sysdep-i386/sigcontext.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/sigcontext.h
--- linux/arch/um/include/sysdep-i386/sigcontext.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/sigcontext.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,47 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_SIGCONTEXT_I386_H
+#define __SYS_SIGCONTEXT_I386_H
+
+#define SC_RESTART_SYSCALL(sc) (SC_IP(sc) -= 2)
+#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0)
+
+#define SC_FAULT_ADDR(sc) SC_CR2(sc)
+#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2)
+
+/* ptrace expects that, at the start of a system call, %eax contains
+ * -ENOSYS, so this makes it so.
+ */
+#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
+
+/* These are General Protection and Page Fault */
+#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14))
+
+static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
+			      unsigned long syscall)
+{
+	regs->syscall = syscall;
+	regs->args[0] = SC_EBX(sc);
+	regs->args[1] = SC_ECX(sc);
+	regs->args[2] = SC_EDX(sc);
+	regs->args[3] = SC_ESI(sc);
+	regs->args[4] = SC_EDI(sc);
+	regs->args[5] = SC_EBP(sc);
+}
+
+extern unsigned long *sc_sigmask(void *sc_ptr);
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-i386/syscalls.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/syscalls.h
--- linux/arch/um/include/sysdep-i386/syscalls.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-i386/syscalls.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,59 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/unistd.h"
+
+typedef long syscall_handler_t(struct pt_regs);
+
+#define EXECUTE_SYSCALL(syscall, regs) (*sys_call_table[syscall])(*regs);
+
+extern syscall_handler_t sys_modify_ldt;
+extern syscall_handler_t old_mmap_i386;
+extern syscall_handler_t old_select;
+extern syscall_handler_t sys_ni_syscall;
+
+#define ARCH_SYSCALLS \
+	[ __NR_mmap ] = old_mmap_i386, \
+	[ __NR_select ] = old_select, \
+	[ __NR_vm86old ] = sys_ni_syscall, \
+        [ __NR_modify_ldt ] = sys_modify_ldt, \
+	[ __NR_lchown32 ] = sys_lchown, \
+	[ __NR_getuid32 ] = sys_getuid, \
+	[ __NR_getgid32 ] = sys_getgid, \
+	[ __NR_geteuid32 ] = sys_geteuid, \
+	[ __NR_getegid32 ] = sys_getegid, \
+	[ __NR_setreuid32 ] = sys_setreuid, \
+	[ __NR_setregid32 ] = sys_setregid, \
+	[ __NR_getgroups32 ] = sys_getgroups, \
+	[ __NR_setgroups32 ] = sys_setgroups, \
+	[ __NR_fchown32 ] = sys_fchown, \
+	[ __NR_setresuid32 ] = sys_setresuid, \
+	[ __NR_getresuid32 ] = sys_getresuid, \
+	[ __NR_setresgid32 ] = sys_setresgid, \
+	[ __NR_getresgid32 ] = sys_getresgid, \
+	[ __NR_chown32 ] = sys_chown, \
+	[ __NR_setuid32 ] = sys_setuid, \
+	[ __NR_setgid32 ] = sys_setgid, \
+	[ __NR_setfsuid32 ] = sys_setfsuid, \
+	[ __NR_setfsgid32 ] = sys_setfsgid, \
+	[ __NR_pivot_root ] = sys_pivot_root, \
+	[ __NR_mincore ] = sys_mincore, \
+	[ __NR_madvise ] = sys_madvise, \
+        [ 222 ] = sys_ni_syscall, 
+        
+/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
+
+#define LAST_ARCH_SYSCALL 222
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ia64/ptrace.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/ptrace.h
--- linux/arch/um/include/sysdep-ia64/ptrace.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/ptrace.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_PTRACE_H
+#define __SYSDEP_IA64_PTRACE_H
+
+struct sys_pt_regs {
+  int foo;
+};
+
+#define EMPTY_REGS { 0 }
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ia64/sigcontext.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/sigcontext.h
--- linux/arch/um/include/sysdep-ia64/sigcontext.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/sigcontext.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SIGCONTEXT_H
+#define __SYSDEP_IA64_SIGCONTEXT_H
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ia64/syscalls.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/syscalls.h
--- linux/arch/um/include/sysdep-ia64/syscalls.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ia64/syscalls.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SYSCALLS_H
+#define __SYSDEP_IA64_SYSCALLS_H
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ppc/ptrace.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/ptrace.h
--- linux/arch/um/include/sysdep-ppc/ptrace.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/ptrace.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,104 @@
+/* 
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_PTRACE_PPC_H
+#define __SYS_PTRACE_PPC_H
+
+#include "linux/config.h"
+#include "linux/types.h"
+
+/* the following taken from <asm-ppc/ptrace.h> */
+
+#ifdef CONFIG_PPC64
+#define PPC_REG unsigned long /*long*/
+#else
+#define PPC_REG unsigned long
+#endif
+struct sys_pt_regs_s {
+	PPC_REG gpr[32];
+	PPC_REG nip;
+	PPC_REG msr;
+	PPC_REG orig_gpr3;	/* Used for restarting system calls */
+	PPC_REG ctr;
+	PPC_REG link;
+	PPC_REG xer;
+	PPC_REG ccr;
+	PPC_REG mq;		/* 601 only (not used at present) */
+				/* Used on APUS to hold IPL value. */
+	PPC_REG trap;		/* Reason for being here */
+	PPC_REG dar;		/* Fault registers */
+	PPC_REG dsisr;
+	PPC_REG result; 	/* Result of a system call */
+};
+
+#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG))
+
+struct sys_pt_regs {
+    PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)];
+};
+
+#define UM_MAX_REG (PT_FPR0)
+#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG))
+
+#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } }
+
+#define UM_REG(r, n) ((r)->regs[n])
+
+#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3)
+#define UM_SP(r) UM_REG(r, PT_R1)
+#define UM_IP(r) UM_REG(r, PT_NIP)
+#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR)
+#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0)
+#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3)
+#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4)
+#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5)
+#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6)
+#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7)
+#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8)
+
+#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG))
+#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG))
+#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG))
+#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG))
+#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG))
+
+#define UM_SET_SYSCALL_RETURN(_regs, result)	        \
+do {                                                    \
+        if (result < 0) {				\
+		(_regs)->regs[PT_CCR] |= 0x10000000;	\
+		UM_SYSCALL_RET((_regs)) = -result;	\
+        } else {					\
+		UM_SYSCALL_RET((_regs)) = result;	\
+        }                                               \
+} while(0)
+
+extern void shove_aux_table(unsigned long sp);
+#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp);
+
+/* These aren't actually defined.  The undefs are just to make sure
+ * everyone's clear on the concept.
+ */
+#undef UML_HAVE_GETREGS
+#undef UML_HAVE_GETFPREGS
+#undef UML_HAVE_SETREGS
+#undef UML_HAVE_SETFPREGS
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ppc/sigcontext.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/sigcontext.h
--- linux/arch/um/include/sysdep-ppc/sigcontext.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/sigcontext.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,62 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_SIGCONTEXT_PPC_H
+#define __SYS_SIGCONTEXT_PPC_H
+
+#define DSISR_WRITE 0x02000000
+
+#define SC_FAULT_ADDR(sc) ({ \
+		struct sigcontext_struct *_sc = (sc); \
+		long retval = -1; \
+		switch (_sc->regs->trap) { \
+		case 0x300: \
+			/* data exception */ \
+			retval = _sc->regs->dar; \
+			break; \
+		case 0x400: \
+			/* instruction exception */ \
+			retval = _sc->regs->nip; \
+			break; \
+		default: \
+			panic("SC_FAULT_ADDR: unhandled trap type\n"); \
+		} \
+		retval; \
+	})
+
+#define SC_FAULT_WRITE(sc) ({ \
+		struct sigcontext_struct *_sc = (sc); \
+		long retval = -1; \
+		switch (_sc->regs->trap) { \
+		case 0x300: \
+			/* data exception */ \
+			retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
+			break; \
+		case 0x400: \
+			/* instruction exception: not a write */ \
+			retval = 0; \
+			break; \
+		default: \
+			panic("SC_FAULT_ADDR: unhandled trap type\n"); \
+		} \
+		retval; \
+	})
+
+#define SC_IP(sc) ((sc)->regs->nip)
+#define SC_SP(sc) ((sc)->regs->gpr[1])
+#define SEGV_IS_FIXABLE(sc) (1)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysdep-ppc/syscalls.h linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/syscalls.h
--- linux/arch/um/include/sysdep-ppc/syscalls.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysdep-ppc/syscalls.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,50 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2,
+			       unsigned long arg3, unsigned long arg4,
+			       unsigned long arg5, unsigned long arg6);
+
+#define EXECUTE_SYSCALL(syscall, regs) \
+        (*sys_call_table[syscall])(UM_SYSCALL_ARG1(&regs), \
+			           UM_SYSCALL_ARG2(&regs), \
+				   UM_SYSCALL_ARG3(&regs), \
+				   UM_SYSCALL_ARG4(&regs), \
+				   UM_SYSCALL_ARG5(&regs), \
+				   UM_SYSCALL_ARG6(&regs))
+
+extern syscall_handler_t sys_mincore;
+extern syscall_handler_t sys_madvise;
+
+/* old_mmap needs the correct prototype since syscall_kern.c includes
+ * this file.
+ */
+int old_mmap(unsigned long addr, unsigned long len,
+	     unsigned long prot, unsigned long flags,
+	     unsigned long fd, unsigned long offset);
+
+#define ARCH_SYSCALLS \
+	[ __NR_modify_ldt ] = sys_ni_syscall, \
+	[ __NR_pciconfig_read ] = sys_ni_syscall, \
+	[ __NR_pciconfig_write ] = sys_ni_syscall, \
+	[ __NR_pciconfig_iobase ] = sys_ni_syscall, \
+	[ __NR_pivot_root ] = sys_ni_syscall, \
+	[ __NR_multiplexer ] = sys_ni_syscall, \
+	[ __NR_mmap ] = old_mmap, \
+	[ __NR_madvise ] = sys_madvise, \
+	[ __NR_mincore ] = sys_mincore, 
+
+#define LAST_ARCH_SYSCALL __NR_mincore
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/sysrq.h linux-2.4.19-pre5-mjc/arch/um/include/sysrq.h
--- linux/arch/um/include/sysrq.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/sysrq.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SYSRQ_H
+#define __UM_SYSRQ_H
+
+extern void show_trace(unsigned long *stack);
+
+#endif
diff -Nru linux/arch/um/include/tlb.h linux-2.4.19-pre5-mjc/arch/um/include/tlb.h
--- linux/arch/um/include/tlb.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/tlb.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TLB_H__
+#define __TLB_H__
+
+extern void mprotect_kernel_vm(int w);
+extern void force_flush_all(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/ubd_user.h linux-2.4.19-pre5-mjc/arch/um/include/ubd_user.h
--- linux/arch/um/include/ubd_user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/ubd_user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,74 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_UBD_USER_H
+#define __UM_UBD_USER_H
+
+enum ubd_req { UBD_READ, UBD_WRITE };
+
+struct io_thread_req {
+	enum ubd_req op;
+	int fds[2];
+	unsigned long offsets[2];
+	unsigned long long offset;
+	unsigned long length;
+	char *buffer;
+	int sectorsize;
+	unsigned long sector_mask;
+	unsigned long cow_offset;
+	unsigned long bitmap_words[2];
+	int error;
+};
+
+extern int open_ubd_file(char *file, int *openflags, char **backing_file_out, 
+			 int *bitmap_offset_out, unsigned long *bitmap_len_out,
+			 int *data_offset_out, int *create_cow_out);
+extern int create_cow_file(char *cow_file, char *backing_file, int sectorsize, 
+			   int *bitmap_offset_out, 
+			   unsigned long *bitmap_len_out,
+			   int *data_offset_out);
+extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
+extern int read_ubd_fs(int fd, void *buffer, int len);
+extern int write_ubd_fs(int fd, char *buffer, int len);
+extern int start_io_thread(unsigned long sp, int *fds_out);
+extern void do_io(struct io_thread_req *req);
+extern int ubd_is_dir(char *file);
+
+static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+{
+	__u64 n;
+	int bits, off;
+
+	bits = sizeof(data[0]) * 8;
+	n = bit / bits;
+	off = bit % bits;
+	return((data[n] & (1 << off)) != 0);
+}
+
+static inline void ubd_set_bit(__u64 bit, unsigned char *data)
+{
+	__u64 n;
+	int bits, off;
+
+	bits = sizeof(data[0]) * 8;
+	n = bit / bits;
+	off = bit % bits;
+	data[n] |= (1 << off);
+}
+
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/umid.h linux-2.4.19-pre5-mjc/arch/um/include/umid.h
--- linux/arch/um/include/umid.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/umid.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+extern int umid_file_name(char *name, char *buf, int len);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/umn.h linux-2.4.19-pre5-mjc/arch/um/include/umn.h
--- linux/arch/um/include/umn.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/umn.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UMN_H
+#define __UMN_H
+
+extern int open_umn_tty(int *slave_out, int *slipno_out);
+extern void close_umn_tty(int master, int slave);
+extern int umn_send_packet(int fd, void *data, int len);
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern void slip_unesc(unsigned char s);
+extern void umn_read(int fd);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/user.h linux-2.4.19-pre5-mjc/arch/um/include/user.h
--- linux/arch/um/include/user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/user.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,29 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __USER_H__
+#define __USER_H__
+
+extern void panic(const char *fmt, ...);
+extern int printk(const char *fmt, ...);
+extern void schedule(void);
+extern void *um_kmalloc(int size);
+extern void *um_kmalloc_atomic(int size);
+extern void kfree(void *ptr);
+extern int in_aton(char *str);
+extern int open_gdb_chan(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/include/user_util.h linux-2.4.19-pre5-mjc/arch/um/include/user_util.h
--- linux/arch/um/include/user_util.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/include/user_util.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,122 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __USER_UTIL_H__
+#define __USER_UTIL_H__
+
+#include "sysdep/ptrace.h"
+
+extern int grantpt(int __fd);
+extern int unlockpt(int __fd);
+extern char *ptsname(int __fd);
+
+enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+
+struct cpu_task {
+	int pid;
+	void *task;
+};
+
+extern struct cpu_task cpu_tasks[];
+
+extern unsigned long low_physmem;
+extern unsigned long high_physmem;
+extern unsigned long uml_physmem;
+extern unsigned long end_vm;
+extern unsigned long start_vm;
+
+extern int tracing_pid;
+extern int honeypot;
+
+extern char host_info[];
+
+extern char saved_command_line[];
+extern char command_line[];
+
+extern int gdb_pid;
+
+extern char *tempdir;
+
+extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
+extern unsigned long _unprotected_end;
+extern void *brk_start;
+
+extern void *open_maps(void);
+extern void close_maps(void *fd);
+extern unsigned long get_brk(void);
+extern void stop(void);
+extern int proc_start_thread(unsigned long ip, unsigned long sp);
+extern void stack_protections(unsigned long address);
+extern void task_protections(unsigned long address);
+extern void abandon_proc_space(int (*proc)(void *), unsigned long sp);
+extern int signals(int (*init_proc)(void *), void *sp);
+extern void stop_pid(int pid);
+extern void kill_pid(int pid);
+extern void usr1_pid(int pid);
+extern int __personality(int);
+extern int wait_for_stop(int pid, int sig, int cont_type);
+extern void *add_signal_handler(int sig, void (*handler)(int));
+extern void signal_init(void);
+extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
+			    int clone_flags, int (*tramp)(void *));
+extern void trace_myself(void);
+extern void timer(void);
+extern void get_profile_timer(void);
+extern void disable_profile_timer(void);
+extern void set_timers(int set_signal);
+extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
+extern int input_loop(void);
+extern void continue_execing_proc(int pid);
+extern int linux_main(int argc, char **argv);
+extern void remap_data(void *segment_start, void *segment_end, int w);
+extern void set_cmdline(char *cmd);
+extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
+extern void setup_input(void);
+extern int get_pty(void);
+extern void save_signal_state(int *sig_ptr);
+extern void *um_kmalloc(int size);
+extern int raw(int fd, int complain);
+extern int switcheroo(int fd, int prot, void *from, void *to, int size);
+extern void idle_sleep(int secs);
+extern void setup_machinename(char *machine_out);
+extern void setup_hostinfo(void);
+extern void add_arg(char *cmd_line, char *arg);
+extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
+extern void attach_process(int pid);
+extern void calc_sigframe_size(void);
+extern int fork_tramp(void *sig_stack);
+extern void do_exec(int old_pid, int new_pid);
+extern void tracer_panic(char *msg, ...);
+extern void close_fd(int);
+extern int make_tempfile(const char *template, char **tempname, int do_unlink);
+extern char *get_umid(void);
+extern void do_longjmp(void *p);
+extern void term_handler(int sig);
+extern void suspend_new_thread(int fd);
+extern int detach(int pid, int sig);
+extern int attach(int pid);
+extern void kill_child_dead(int pid);
+extern int cont(int pid);
+extern void check_ptrace(void);
+extern void check_sigio(void);
+extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
+extern int user_read(int fd, char *buf, int len);
+extern int user_write(int fd, char *buf, int len);
+extern void write_sigio_workaround(int fd);
+extern void arch_check_bugs(void);
+extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/Makefile linux-2.4.19-pre5-mjc/arch/um/kernel/Makefile
--- linux/arch/um/kernel/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,71 @@
+OBJ = um.o
+
+OBJS = exec_kern.o exec_user.o frame_kern.o frame.o init_task.o irq.o \
+	irq_user.o mem.o mem_user.o process.o ptrace.o reboot.o resource.o \
+	setup.o sigio_user.o sigio_kern.o signal_user.o smp.o syscall_kern.o \
+	syscall_user.o sysrq.o sys_call_table.o time.o time_kern.o tlb.o \
+	trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o user_util.o
+
+ifeq ($(CONFIG_BLK_DEV_INITRD), y)
+  OBJS += initrd_kern.o initrd_user.o
+endif
+
+# user_syms.o not included here because Rules.make has its own ideas about
+# building anything in export-objs
+
+USER_OBJS = $(filter %_user.o,$(OBJS)) process.o time.o umid.o user_util.o
+
+export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o
+
+UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
+UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
+
+ifeq ($(CONFIG_MODULES), y)
+  DMODULES = -D__CONFIG_MODULES__
+endif
+
+ifeq ($(CONFIG_MODVERSIONS), y)
+  DMODVERSIONS = -D__CONFIG_MODVERSIONS__
+endif
+
+ifeq ($(CONFIG_GPROF), y)
+    OBJS += gprof_syms.o
+    export-objs += gprof_syms.o
+endif
+
+ifeq ($(CONFIG_GCOV), y)
+    OBJS += gmon_syms.o
+    export-objs += gmon_syms.o
+endif
+
+CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) -I- \
+	-I../include
+
+CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
+
+all: $(OBJ) unmap_fin.o
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+unmap.o: unmap.c
+	$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
+
+frame.o: frame.c
+	$(CC) $(CFLAGS_$@) -c -o $@ $<
+
+unmap_fin.o : unmap.o
+	ld -r -o $@ $< -lc -L/usr/lib
+
+$(OBJ): $(OBJS) $(export-objs)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+
+clean:
+	rm -f $(OBJS) $(export-objs)
+
+modules:
+
+fastdep:
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/kernel/exec_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/exec_kern.c
--- linux/arch/um/kernel/exec_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/exec_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,123 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/slab.h"
+#include "linux/smp_lock.h"
+#include "asm/ptrace.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "tlb.h"
+#include "2_5compat.h"
+
+/* See comment above fork_tramp for why sigstop is defined and used like
+ * this
+ */
+
+static int sigstop = SIGSTOP;
+
+static int exec_tramp(void *sig_stack)
+{
+	int sig = sigstop;
+
+	block_signals();
+	init_new_thread(sig_stack, NULL);
+	kill(getpid(), sig);
+	return(0);
+}
+
+void flush_thread(void)
+{
+	unsigned long stack;
+	int new_pid;
+
+	stack = alloc_stack();
+	if(stack == 0){
+		printk(KERN_ERR 
+		       "flush_thread : failed to allocate temporary stack\n");
+		do_exit(SIGKILL);
+	}
+		
+	new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
+				   stack, 0, exec_tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR 
+		       "flush_thread : new thread failed, errno = %d\n",
+		       -new_pid);
+		do_exit(SIGKILL);
+	}
+
+	if(CPU(current) == 0)
+		forward_interrupts(new_pid);
+	current->thread.request.op = OP_EXEC;
+	current->thread.request.u.exec.pid = new_pid;
+	unprotect_stack((unsigned long) current);
+	usr1_pid(getpid());
+
+	free_page(stack);
+	protect(uml_physmem, high_physmem - uml_physmem, 1, 1, 0, 1);
+	task_protections((unsigned long) current);
+	force_flush_all();
+	unblock_signals();
+}
+
+void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
+{
+	set_fs(USER_DS);
+	flush_tlb_mm(current->mm);
+	PT_REGS_IP(regs) = eip;
+	PT_REGS_SP(regs) = esp;
+	PT_FIX_EXEC_STACK(esp);
+}
+
+static int execve1(char *file, char **argv, char **env)
+{
+        int error;
+
+        error = do_execve(file, argv, env, &current->thread.regs);
+        if (error == 0){
+                current->ptrace &= ~PT_DTRACE;
+                set_cmdline(current_cmd());
+        }
+        return(error);
+}
+
+int um_execve(char *file, char **argv, char **env)
+{
+	if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp);
+	return(-1);
+}
+
+int sys_execve(char *file, char **argv, char **env)
+{
+	int error;
+	char *filename;
+
+	lock_kernel();
+	filename = getname((char *) file);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename)) goto out;
+	error = execve1(filename, argv, env);
+	putname(filename);
+ out:
+	unlock_kernel();
+	return(error);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/exec_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/exec_user.c
--- linux/arch/um/kernel/exec_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/exec_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,50 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ptrace_user.h"
+
+void do_exec(int old_pid, int new_pid)
+{
+	unsigned long regs[FRAME_SIZE];
+
+	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) ||
+	   (waitpid(new_pid, 0, WUNTRACED) < 0))
+		tracer_panic("do_exec failed to attach proc - errno = %d",
+			     errno);
+
+	if(ptrace_getregs(old_pid, regs) < 0)
+		tracer_panic("do_exec failed to get registers - errno = %d",
+			     errno);
+
+	kill(old_pid, SIGKILL);
+
+	if(ptrace_setregs(new_pid, regs) < 0)
+		tracer_panic("do_exec failed to start new proc - errno = %d",
+			     errno);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/frame.c linux-2.4.19-pre5-mjc/arch/um/kernel/frame.c
--- linux/arch/um/kernel/frame.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/frame.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,291 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <wait.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "sysdep/frame.h"
+#include "sysdep/sigcontext.h"
+#include "frame.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+
+static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
+			 unsigned long top, void **data_out)
+{
+	unsigned long regs[FRAME_SIZE];
+	int pid, status, n, len;
+
+	/* Start the child as a thread */
+	pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);
+	if(pid < 0){
+		printf("capture_stack : clone failed - errno = %d\n", errno);
+		exit(1);
+	}
+
+	/* Wait for it to stop itself and continue it with a SIGUSR1 to force 
+	 * it into the signal handler.
+	 */
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
+		fprintf(stderr, "capture_stack : Expected SIGSTOP, "
+			"got status = 0x%x\n", status);
+		exit(1);
+	}
+	if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){
+		printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	/* Wait for it to stop itself again and grab its registers again.  
+	 * At this point, the handler has stuffed the addresses of
+	 * sig, sc, and SA_RESTORER in raw.
+	 */
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
+		fprintf(stderr, "capture_stack : Expected SIGSTOP, "
+			"got status = 0x%x\n", status);
+		exit(1);
+	}
+	if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){
+		printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	/* It has outlived its usefulness, so continue it so it can exit */
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){
+		printf("capture_stack : mmap failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(waitpid(pid, &status, 0) < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+		printf("capture_stack : Expected exit status 0, "
+		       "got status = 0x%x\n", status);
+		exit(1);
+	}
+
+	/* The frame that we want is the top of the signal stack */
+	len = top - PT_SP(regs);
+	*data_out = malloc(len);
+	if(*data_out == NULL){
+		printf("capture_stack : malloc failed - errno = %d\n", errno);
+		exit(1);
+	}
+	memcpy(*data_out, (void *) PT_SP(regs), len);
+
+	return(len);
+}
+
+static void child_common(void *sp, int size, sighandler_t handler, int flags)
+{
+	stack_t ss;
+	struct sigaction sa;
+
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+		printf("PTRACE_TRACEME failed, errno = %d\n", errno);
+	}
+	ss.ss_sp = sp;
+	ss.ss_flags = 0;
+	ss.ss_size = size;
+	if(sigaltstack(&ss, NULL) < 0){
+		printf("sigaltstack failed - errno = %d\n", errno);
+		exit(1);
+	}
+
+	sa.sa_handler = handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_ONSTACK | flags;
+	if(sigaction(SIGUSR1, &sa, NULL) < 0){
+		printf("sigaction failed - errno = %d\n", errno);
+		exit(1);
+	}
+
+	kill(getpid(), SIGSTOP);
+}
+
+struct sc_frame signal_frame_sc;
+
+struct sc_frame_raw {
+	void *stack;
+	int size;
+	unsigned long sig;
+	unsigned long sc;
+	unsigned long sr;
+	unsigned long sp;
+	struct arch_frame_data_raw arch;
+};
+
+static struct sc_frame_raw *raw_sc = NULL;
+
+static void sc_handler(int sig, struct sigcontext sc)
+{
+	raw_sc->sig = (unsigned long) &sig;
+	raw_sc->sc = (unsigned long) &sc;
+	raw_sc->sr = frame_restorer();
+	raw_sc->sp = frame_sp();
+	setup_arch_frame_raw(&raw_sc->arch, &sc);
+	kill(getpid(), SIGSTOP);
+	exit(0);
+}
+
+static int sc_child(void *arg)
+{
+	raw_sc = arg;
+	child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, 
+		     0);
+	return(-1);
+}
+
+struct si_frame signal_frame_si;
+
+struct si_frame_raw {
+	void *stack;
+	int size;
+	unsigned long sig;
+	unsigned long sip;
+	unsigned long si;
+	unsigned long sr;
+	unsigned long sp;
+};
+
+static struct si_frame_raw *raw_si = NULL;
+
+static void si_handler(int sig, siginfo_t *si)
+{
+	raw_si->sig = (unsigned long) &sig;
+	raw_si->sip = (unsigned long) &si;
+	raw_si->si = (unsigned long) si;
+	raw_si->sr = frame_restorer();
+	raw_si->sp = frame_sp();
+	kill(getpid(), SIGSTOP);
+	exit(0);
+}
+
+static int si_child(void *arg)
+{
+	raw_si = arg;
+	child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler,
+		     SA_SIGINFO);
+	return(-1);
+}
+
+void capture_signal_stack(void)
+{
+	struct sc_frame_raw raw_sc;
+	struct si_frame_raw raw_si;
+	void *stack, *sigstack;
+	unsigned long top, sig_top, base;
+
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){
+		printf("capture_signal_stack : mmap failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+	sig_top = (unsigned long) sigstack + PAGE_SIZE;
+
+	raw_sc.stack = sigstack;
+	raw_sc.size = PAGE_SIZE;
+	signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
+					    sig_top, &signal_frame_sc.data);
+
+	/* These are the offsets within signal_frame_sc.data (counting from
+	 * the bottom) of sig, sc, SA_RESTORER, and the initial sp.
+	 */
+	base = sig_top - signal_frame_sc.len;
+	signal_frame_sc.sig_index = raw_sc.sig - base;
+	signal_frame_sc.sc_index = raw_sc.sc - base;
+	signal_frame_sc.sr_index = raw_sc.sr - base;
+	if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) == 
+	   (unsigned long) sigstack){
+		unsigned long *sr = (unsigned long *) raw_sc.sr;
+		unsigned long frame = (unsigned long) signal_frame_sc.data;
+
+		signal_frame_sc.sr_relative = 1;
+		*sr -= raw_sc.sr;
+		*((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
+	}
+	else signal_frame_sc.sr_relative = 0;
+	signal_frame_sc.sp_index = raw_sc.sp - base;
+	setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
+
+	/* Repeat for the siginfo variant */
+
+	raw_si.stack = sigstack;
+	raw_si.size = PAGE_SIZE;
+	signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
+					    sig_top, &signal_frame_si.data);
+	base = sig_top - signal_frame_si.len;
+	signal_frame_si.sig_index = raw_si.sig - base;
+	signal_frame_si.sip_index = raw_si.sip - base;
+	signal_frame_si.si_index = raw_si.si - base;
+	signal_frame_si.sr_index = raw_si.sr - base;
+	if((*((unsigned long *) raw_si.sr) & PAGE_MASK) == 
+	   (unsigned long) sigstack){
+		unsigned long *sr = (unsigned long *) raw_si.sr;
+		unsigned long frame = (unsigned long) signal_frame_si.data;
+
+		signal_frame_sc.sr_relative = 1;
+		*sr -= raw_si.sr;
+		*((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
+	}
+	else signal_frame_si.sr_relative = 0;
+	signal_frame_si.sp_index = raw_si.sp - base;
+
+	if((munmap(stack, PAGE_SIZE) < 0) || 
+	   (munmap(sigstack, PAGE_SIZE) < 0)){
+		printf("capture_signal_stack : munmap failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+}
+
+void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
+{
+	struct sigcontext *sc = sc_ptr;
+
+	SC_IP(sc) = ip;
+	SC_SP(sc) = sp;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/frame_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/frame_kern.c
--- linux/arch/um/kernel/frame_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/frame_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,132 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/signal.h"
+#include "frame.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+#include "sigcontext_kern.h"
+#include "sysdep/ptrace.h"
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (from->si_code < 0)
+		return __copy_to_user(to, from, sizeof(siginfo_t));
+	else {
+		int err;
+
+		/* If you change siginfo_t structure, please be sure
+		   this code is fixed accordingly.
+		   It should never copy any pad contained in the structure
+		   to avoid security leaks, but must copy the generic
+		   3 ints plus the relevant union member.  */
+		err = __put_user(from->si_signo, &to->si_signo);
+		err |= __put_user(from->si_errno, &to->si_errno);
+		err |= __put_user((short)from->si_code, &to->si_code);
+		/* First 32bits of unions are always present.  */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		switch (from->si_code >> 16) {
+		case __SI_FAULT >> 16:
+			break;
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		}
+		return err;
+	}
+}
+
+static int copy_restorer(void (*restorer)(void), unsigned long start, 
+			 unsigned long sr_index, int sr_relative)
+{
+	if(restorer != 0){
+		if(copy_to_user((void *) (start + sr_index), &restorer, 
+				sizeof(restorer)))
+			return(1);
+	}
+	else if(sr_relative){
+		unsigned long *sr = (unsigned long *) (start + sr_index);
+		*sr += (unsigned long) sr;
+	}
+	return(0);
+}
+
+int setup_signal_stack_si(unsigned long stack_top, int sig, 
+			  unsigned long handler, void (*restorer)(void), 
+			  struct pt_regs *regs, void *context_sc, 
+			  siginfo_t *info, struct arch_signal_context *arch, 
+			  sigset_t *mask)
+{
+	unsigned long start, sc;
+	void *sip;
+
+	start = stack_top - signal_frame_si.len - 
+		sc_size(&signal_frame_sc.arch);
+	sip = (void *) (start + signal_frame_si.si_index);
+	sc = start + signal_frame_si.len;
+	if(copy_sc_to_user((void *) sc, regs->regs.sc, 
+			   &signal_frame_sc.arch) ||
+	   copy_to_user(context_sc, (void *) sc, sizeof(context_sc)) ||
+	   copy_to_user((void *) start, signal_frame_si.data,
+			signal_frame_si.len) ||
+	   copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, 
+			sizeof(sig)) ||
+	   copy_siginfo_to_user(sip, info) ||
+	   copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
+			sizeof(sip)) ||
+	   copy_sigmask_to_user(mask, NULL, arch) ||
+	   copy_restorer(restorer, start, signal_frame_si.sr_index,
+			 signal_frame_si.sr_relative))
+		return(1);
+	
+	PT_REGS_IP(regs) = handler;
+	PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+	return(0);
+}
+
+int setup_signal_stack_sc(unsigned long stack_top, int sig, 
+			  unsigned long handler, void (*restorer)(void), 
+			  struct pt_regs *regs, void *context_sc,
+			  struct arch_signal_context *arch, sigset_t *mask)
+{
+	unsigned long start = stack_top - signal_frame_sc.len;
+	void *user_sc = (void *) (start + signal_frame_sc.sc_index);
+	
+	if(copy_to_user((void *) start, signal_frame_sc.data, 
+			signal_frame_sc.len) ||
+	   copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
+			sizeof(sig)) ||
+	   copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) ||
+	   copy_to_user(context_sc, &user_sc, sizeof(user_sc)) ||
+	   copy_sigmask_to_user(mask, user_sc, arch) ||
+	   copy_restorer(restorer, start, signal_frame_sc.sr_index,
+			 signal_frame_sc.sr_relative))
+		return(1);
+
+	PT_REGS_IP(regs) = handler;
+	PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+
+	set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/gmon_syms.c linux-2.4.19-pre5-mjc/arch/um/kernel/gmon_syms.c
--- linux/arch/um/kernel/gmon_syms.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/gmon_syms.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+
+extern void __bb_init_func(void *);
+EXPORT_SYMBOL(__bb_init_func);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/gprof_syms.c linux-2.4.19-pre5-mjc/arch/um/kernel/gprof_syms.c
--- linux/arch/um/kernel/gprof_syms.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/gprof_syms.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/init_task.c linux-2.4.19-pre5-mjc/arch/um/kernel/init_task.c
--- linux/arch/um/kernel/init_task.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/init_task.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,63 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/sched.h"
+#include "linux/version.h"
+#include "asm/uaccess.h"
+#include "asm/pgtable.h"
+#include "user_util.h"
+#include "mem_user.h"
+
+static struct fs_struct init_fs = INIT_FS;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+#endif
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+
+union task_union init_task_union 
+__attribute__((__section__(".data.init_task"))) = 
+{ INIT_TASK(init_task_union.task) };
+
+struct task_struct *alloc_task_struct(void){
+	struct task_struct *task;
+
+	task = (struct task_struct *) __get_free_pages(GFP_KERNEL, 2);
+	if(task == NULL) return(NULL);
+	return(task);
+}
+
+void unprotect_stack(unsigned long stack)
+{
+	protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
+}
+
+void free_task_struct(struct task_struct *task)
+{
+	/* free_pages decrements the page counter and only actually frees
+	 * the pages if they are now not accessed by anything.
+	 */
+	free_pages((unsigned long) task, 2);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/initrd_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/initrd_kern.c
--- linux/arch/um/kernel/initrd_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/initrd_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/blk.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "initrd.h"
+#include "init.h"
+
+extern __s64 file_size(char *file);
+
+static char *initrd __initdata = NULL;
+
+static int __init read_initrd(void)
+{
+	void *area;
+	int size;
+
+	if(initrd == NULL) return 0;
+	size = file_size(initrd);
+	if(size < 0) return 0;
+	area = alloc_bootmem(size);
+	if(area == NULL) return 0;
+	if(load_initrd(initrd, area, size) == -1) return 0;
+	initrd_start = (unsigned long) area;
+	initrd_end = initrd_start + size;
+	return 0;
+}
+
+__uml_postsetup(read_initrd);
+
+static int __init uml_initrd_setup(char *line, int *add)
+{
+	initrd = line;
+	return 0;
+}
+
+__uml_setup("initrd=", uml_initrd_setup, 
+"initrd=<initrd image>\n"
+"    This is used to boot UML from an initrd image.  The argument is the\n"
+"    name of the file containing the image.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/initrd_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/initrd_user.c
--- linux/arch/um/kernel/initrd_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/initrd_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "initrd.h"
+
+int load_initrd(char *filename, void *buf, int size)
+{
+	int fd, n;
+
+	if((fd = open(filename, O_RDONLY)) == -1){
+		printk("Opening '%s' failed - errno = %d\n", filename, errno);
+		return(-1);
+	}
+	if((n = read(fd, buf, size)) != size){
+		printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
+		       size, filename, n, errno);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/irq.c linux-2.4.19-pre5-mjc/arch/um/kernel/irq.c
--- linux/arch/um/kernel/irq.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/irq.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,813 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
+ *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/irq.h"
+#include "linux/kernel_stat.h"
+#include "linux/interrupt.h"
+#include "linux/random.h"
+#include "linux/slab.h"
+#include "linux/file.h"
+#include "linux/proc_fs.h"
+#include "linux/init.h"
+#include "linux/seq_file.h"
+#include "asm/irq.h"
+#include "asm/hw_irq.h"
+#include "asm/hardirq.h"
+#include "asm/atomic.h"
+#include "asm/signal.h"
+#include "asm/system.h"
+#include "asm/errno.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+
+static void register_irq_proc (unsigned int irq);
+
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+        { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+#if CONFIG_X86
+	printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Currently unexpected vectors happen only on SMP and APIC.
+	 * We _must_ ack these because every local APIC has only N
+	 * irq slots per priority level, and a 'hanging, unacked' IRQ
+	 * holds up an irq slot - in excessive cases (when multiple
+	 * unexpected vectors occur) that might lock up the APIC
+	 * completely.
+	 */
+	ack_APIC_irq();
+#endif
+#endif
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+volatile unsigned long irq_err_count;
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int get_irq_list(char *buf)
+{
+	int i, j;
+	struct irqaction * action;
+	char *p = buf;
+
+	p += sprintf(p, "           ");
+	for (j=0; j<smp_num_cpus; j++)
+		p += sprintf(p, "CPU%d       ",j);
+	*p++ = '\n';
+
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_desc[i].action;
+		if (!action) 
+			continue;
+		p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j = 0; j < smp_num_cpus; j++)
+			p += sprintf(p, "%10u ",
+				kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+		p += sprintf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			p += sprintf(p, ", %s", action->name);
+		*p++ = '\n';
+	}
+	p += sprintf(p, "\n");
+#ifdef notdef
+#if CONFIG_SMP
+	p += sprintf(p, "LOC: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10u ",
+			apic_timer_irqs[cpu_logical_map(j)]);
+	p += sprintf(p, "\n");
+#endif
+#endif
+	p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+	return p - buf;
+}
+
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, 
+		     struct irqaction * action)
+{
+	int status;
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, irq);
+
+	status = 1;	/* Force the "do bottom halves" bit */
+
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
+
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	__cli();
+
+	irq_exit(cpu, irq);
+
+	return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
+ 
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void inline disable_irq_nosync(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		desc->status |= IRQ_DISABLED;
+		desc->handler->disable(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. That is for two disables you need two enables. This
+ *	function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
+ 
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+
+	if (!local_irq_count(smp_processor_id())) {
+		do {
+			barrier();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
+}
+
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line
+ *	providing no disable_irq calls are now in effect.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void enable_irq(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
+	case 1: {
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
+		}
+		desc->handler->enable(irq);
+		/* fall-through */
+	}
+	default:
+		desc->depth--;
+		break;
+	case 0:
+		printk(KERN_ERR "enable_irq() unbalanced from %p\n",
+		       __builtin_return_address(0));
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
+{	
+	/* 
+	 * 0 return value means that this irq is already being
+	 * handled by some other CPU. (or is disabled)
+	 */
+	int cpu = smp_processor_id();
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
+	unsigned int status;
+
+	kstat.irqs[cpu][irq]++;
+	spin_lock(&desc->lock);
+	desc->handler->ack(irq);
+	/*
+	   REPLAY is when Linux resends an IRQ that was dropped earlier
+	   WAITING is used by probe to mark irqs that are being tested
+	   */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		status |= IRQ_INPROGRESS; /* we are handling it */
+	}
+	desc->status = status;
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	   Since we set PENDING, if another processor is handling
+	   a different instance of this same irq, the other processor
+	   will take care of it.
+	 */
+	if (!action)
+		goto out;
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in do_IRQ
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		spin_unlock(&desc->lock);
+		handle_IRQ_event(irq, (struct pt_regs *) regs, action);
+		spin_lock(&desc->lock);
+		
+		if (!(desc->status & IRQ_PENDING))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+	desc->status &= ~IRQ_INPROGRESS;
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	desc->handler->end(irq);
+	spin_unlock(&desc->lock);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+	return 1;
+}
+
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board 
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+ 
+int request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{
+	int retval;
+	struct irqaction * action;
+
+#if 1
+	/*
+	 * Sanity-check: shared interrupts should REALLY pass in
+	 * a real dev-ID, otherwise we'll have trouble later trying
+	 * to figure out which interrupt is which (messes up the
+	 * interrupt freeing logic etc).
+	 */
+	if (irqflags & SA_SHIRQ) {
+		if (!dev_id)
+			printk(KERN_ERR "Bad boy: %s (at 0x%x) called us "
+			       "without a dev_id!\n", devname, (&irq)[-1]);
+	}
+#endif
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+
+	action = (struct irqaction *)
+			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+	return retval;
+}
+
+int um_request_irq(unsigned int irq, int fd, int type,
+		   void (*handler)(int, void *, struct pt_regs *),
+		   unsigned long irqflags, const char * devname,
+		   void *dev_id)
+{
+	int retval;
+
+	retval = request_irq(irq, handler, irqflags, devname, dev_id);
+	if(retval) return(retval);
+	return(activate_fd(irq, fd, type, dev_id));
+}
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	unsigned long flags;
+	struct irqaction *old, **p;
+	irq_desc_t *desc = irq_desc + irq;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&desc->lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		desc->depth = 0;
+		desc->status &= ~IRQ_DISABLED;
+		desc->handler->startup(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	register_irq_proc(irq);
+	return 0;
+}
+
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function. The function
+ *	does not return until any executing interrupts for this IRQ
+ *	have completed.
+ *
+ *	This function may be called from interrupt context. 
+ *
+ *	Bugs: Attempting to free an irq in a handler for the same irq hangs
+ *	      the machine.
+ */
+ 
+void free_irq(unsigned int irq, void *dev_id)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS)
+		return;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
+			}
+			free_irq_by_dev(dev_id);
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+			/* Wait to make sure it's not being used on another CPU */
+			while (desc->status & IRQ_INPROGRESS)
+				barrier();
+#endif
+			kfree(action);
+			return;
+		}
+		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return;
+	}
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
+{
+	unsigned char hexnum [HEX_DIGITS];
+	unsigned long value;
+	int i;
+
+	if (!count)
+		return -EINVAL;
+	if (count > HEX_DIGITS)
+		count = HEX_DIGITS;
+	if (copy_from_user(hexnum, buffer, count))
+		return -EFAULT;
+
+	/*
+	 * Parse the first 8 characters as a hex string, any non-hex char
+	 * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+	 */
+	value = 0;
+
+	for (i = 0; i < count; i++) {
+		unsigned int c = hexnum[i];
+
+		switch (c) {
+			case '0' ... '9': c -= '0'; break;
+			case 'a' ... 'f': c -= 'a'-10; break;
+			case 'A' ... 'F': c -= 'A'-10; break;
+		default:
+			goto out;
+		}
+		value = (value << 4) | c;
+	}
+out:
+	*ret = value;
+	return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	int irq = (long) data, full_count = count, err;
+	unsigned long new_value;
+
+	if (!irq_desc[irq].handler->set_affinity)
+		return -EIO;
+
+	err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+	/*
+	 * Do not allow disabling IRQs completely - it's a too easy
+	 * way to make the system unusable accidentally :-) At least
+	 * one online CPU still has to be targeted.
+	 */
+	if (!(new_value & cpu_online_map))
+		return -EINVAL;
+#endif
+
+	irq_affinity[irq] = new_value;
+	irq_desc[irq].handler->set_affinity(irq, new_value);
+
+	return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	unsigned long *mask = (unsigned long *) data;
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	unsigned long *mask = (unsigned long *) data, full_count = count, err;
+	unsigned long new_value;
+
+	err = parse_hex_value(buffer, count, &new_value);
+	if (err)
+		return err;
+
+	*mask = new_value;
+	return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+	struct proc_dir_entry *entry;
+	char name [MAX_NAMELEN];
+
+	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+	    irq_dir[irq])
+		return;
+
+	memset(name, 0, MAX_NAMELEN);
+	sprintf(name, "%d", irq);
+
+	/* create /proc/irq/1234 */
+	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+	/* create /proc/irq/1234/smp_affinity */
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+	entry->nlink = 1;
+	entry->data = (void *)(long)irq;
+	entry->read_proc = irq_affinity_read_proc;
+	entry->write_proc = irq_affinity_write_proc;
+
+	smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void __init init_irq_proc (void)
+{
+	struct proc_dir_entry *entry;
+	int i;
+
+	/* create /proc/irq */
+	root_irq_dir = proc_mkdir("irq", 0);
+
+	/* create /proc/irq/prof_cpu_mask */
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+	entry->nlink = 1;
+	entry->data = (void *)&prof_cpu_mask;
+	entry->read_proc = prof_cpu_mask_read_proc;
+	entry->write_proc = prof_cpu_mask_write_proc;
+
+	/*
+	 * Create entries for all existing IRQs.
+	 */
+	for (i = 0; i < NR_IRQS; i++)
+		register_irq_proc(i);
+}
+
+unsigned long probe_irq_on(void)
+{
+	return(0);
+}
+
+int probe_irq_off(unsigned long val)
+{
+	return(0);
+}
+
+static unsigned int startup_SIGIO_irq(unsigned int irq)
+{
+	return(0);
+}
+
+static void shutdown_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void enable_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void disable_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void mask_and_ack_SIGIO(unsigned int irq)
+{
+}
+
+static void end_SIGIO_irq(unsigned int irq)
+{
+}
+
+static unsigned int startup_SIGVTALRM_irq(unsigned int irq)
+{
+	return(0);
+}
+
+static void shutdown_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void enable_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void disable_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void mask_and_ack_SIGVTALRM(unsigned int irq)
+{
+}
+
+static void end_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type SIGIO_irq_type = {
+	"SIGIO",
+	startup_SIGIO_irq,
+	shutdown_SIGIO_irq,
+	enable_SIGIO_irq,
+	disable_SIGIO_irq,
+	mask_and_ack_SIGIO,
+	end_SIGIO_irq,
+	NULL
+};
+
+static struct hw_interrupt_type SIGVTALRM_irq_type = {
+	"SIGVTALRM",
+	startup_SIGVTALRM_irq,
+	shutdown_SIGVTALRM_irq,
+	enable_SIGVTALRM_irq,
+	disable_SIGVTALRM_irq,
+	mask_and_ack_SIGVTALRM,
+	end_SIGVTALRM_irq,
+	NULL
+};
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
+	irq_desc[TIMER_IRQ].action = 0;
+	irq_desc[TIMER_IRQ].depth = 1;
+	irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
+	enable_irq(TIMER_IRQ);
+	for(i=1;i<NR_IRQS;i++){
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &SIGIO_irq_type;
+		enable_irq(i);
+	}
+	init_irq_signals(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/irq_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/irq_user.c
--- linux/arch/um/kernel/irq_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/irq_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,321 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_user.h"
+#include "sigio.h"
+#include "irq_user.h"
+
+struct irq_fd {
+	struct irq_fd *next;
+	void *id;
+	int fd;
+	int type;
+	int irq;
+	int pid;
+	int events;
+	int current_events;
+};
+
+static struct irq_fd *active_fds = NULL;
+static struct irq_fd **last_irq_ptr = &active_fds;
+
+static struct pollfd *pollfds = NULL;
+static int pollfds_num = 0;
+static int pollfds_size = 0;
+
+extern int io_count, intr_count;
+
+void sigio_handler(int sig, struct uml_pt_regs *regs)
+{
+	struct irq_fd *irq_fd, *next;
+	int i, n;
+
+	if(smp_sigio_handler()) return;
+	while(1){
+		if((n = poll(pollfds, pollfds_num, 0)) < 0){
+			if(errno == EINTR) continue;
+			printk("sigio_handler : poll returned %d, "
+			       "errno = %d\n", n, errno);
+			break;
+		}
+		if(n == 0) break;
+
+		irq_fd = active_fds;
+		for(i = 0; i < pollfds_num; i++){
+			if(pollfds[i].revents != 0){
+				irq_fd->current_events = pollfds[i].revents;
+				pollfds[i].events = 0;
+			}
+			irq_fd = irq_fd->next;
+		}
+
+		for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
+			/* This mysterious assignment protects us against
+			 * the irq handler freeing the irq from under us.
+			 */
+			next = irq_fd->next;
+			if(irq_fd->current_events != 0){
+				irq_fd->current_events = 0;
+				do_IRQ(irq_fd->irq, regs);
+			}
+		}
+	}
+}
+
+static int prepare_fd_async(int fd, int pid)
+{
+	int retval;
+
+	if((retval = fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK)) < 0){
+		printk("Failed to set O_ASYNC and O_NONBLOCK on fd # %d, "
+		       "errno = %d\n", fd, errno);
+		return(-retval);
+	}
+
+	if(((retval = fcntl(fd, F_SETSIG, SIGIO)) < 0) ||
+	   ((retval = fcntl(fd, F_SETOWN, pid)) < 0)){
+		printk("Failed to fcntl F_SETOWN (or F_SETSIG) "
+		       "fd %d to pid %d, errno = %d\n", fd, pid, errno);
+		return(-retval);
+	}
+
+	return(0);
+}
+
+int activate_ipi(int fd, int pid)
+{
+	return prepare_fd_async(fd, pid);
+}
+
+int activate_fd(int irq, int fd, int type, void *dev_id)
+{
+	struct irq_fd *new_fd;
+	int pid, retval, events, err;
+
+	for(new_fd = active_fds;new_fd;new_fd = new_fd->next){
+		if((new_fd->fd == fd) && (new_fd->type == type)){
+			printk("Registering fd %d twice\n", fd);
+			printk("Irqs : %d, %d\n", new_fd->irq, irq);
+			printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id);
+			return(-EIO);
+		}
+	}
+	pid = cpu_tasks[0].pid;
+	if ((retval = prepare_fd_async(fd, pid)) != 0)
+		return(retval);
+	new_fd = um_kmalloc(sizeof(*new_fd));
+	err = -ENOMEM;
+	if(new_fd == NULL) return(err);
+	pollfds_num++;
+	if(pollfds_num > pollfds_size){
+		struct pollfd *tmp_pfd;
+
+		tmp_pfd = um_kmalloc(pollfds_num * sizeof(pollfds[0]));
+		if(tmp_pfd == NULL){
+			pollfds_num--;
+			goto out_irq;
+		}
+		if(pollfds != NULL){
+			memcpy(tmp_pfd, pollfds,
+			       sizeof(pollfds[0]) * pollfds_size);
+			kfree(pollfds);
+		}
+		pollfds = tmp_pfd;
+		pollfds_size = pollfds_num;
+	}
+
+	if(type == IRQ_READ) events = POLLIN | POLLPRI;
+	else events = POLLOUT;
+	*new_fd = ((struct irq_fd) { next : 		NULL,
+				     id :		dev_id,
+				     fd :		fd,
+				     type :		type,
+				     irq :		irq,
+				     pid : 		pid,
+				     events :		events,
+				     current_events: 	0 } );
+
+	*last_irq_ptr = new_fd;
+	last_irq_ptr = &new_fd->next;
+
+	if(type == IRQ_WRITE) events = 0;
+
+	pollfds[pollfds_num - 1] = ((struct pollfd) { fd :	fd,
+						      events :	events,
+						      revents :	0 });
+
+	if(type == IRQ_WRITE) write_sigio_workaround(fd);
+
+	return(0);
+
+ out_irq:
+	kfree(new_fd);
+	return(err);
+}
+
+static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+{
+	struct irq_fd **prev;
+	int i = 0;
+
+	prev = &active_fds;
+	while(*prev != NULL){
+		if((*test)(*prev, arg)){
+			struct irq_fd *old_fd = *prev;
+			if(pollfds[i].fd != (*prev)->fd){
+				printk("free_irq_by_cb - mismatch between "
+				       "active_fds and pollfds, fd %d vs %d\n",
+				       (*prev)->fd, pollfds[i].fd);
+				return;
+			}
+			memcpy(&pollfds[i], &pollfds[i + 1],
+			       (pollfds_num - i - 1) * sizeof(pollfds[0]));
+			pollfds_num--;
+			if(last_irq_ptr == &old_fd->next) 
+				last_irq_ptr = prev;
+			*prev = (*prev)->next;
+			if(old_fd->type == IRQ_WRITE) 
+				ignore_sigio_fd(old_fd->fd);
+			kfree(old_fd);
+			continue;
+		}
+		prev = &(*prev)->next;
+		i++;
+	}
+}
+
+static int same_dev(struct irq_fd *irq, void *dev)
+{
+	return(irq->id == dev);
+}
+
+void free_irq_by_dev(void *dev)
+{
+	free_irq_by_cb(same_dev, dev);
+}
+
+static int same_fd(struct irq_fd *irq, void *fd)
+{
+	return(irq->fd == *((int *) fd));
+}
+
+void free_irq_by_fd(int fd)
+{
+	free_irq_by_cb(same_fd, &fd);
+}
+
+static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
+{
+	struct irq_fd *irq;
+	int i = 0;
+	
+	for(irq=active_fds; irq != NULL; irq = irq->next){
+		if((irq->fd == fd) && (irq->irq == irqnum)) break;
+		i++;
+	}
+	if(irq == NULL){
+		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
+		return(NULL);
+	}
+	if(pollfds[i].fd != fd){
+		printk("find_irq_by_fd - mismatch between active_fds and "
+		       "pollfds, fd %d vs %d, need %d\n", irq->fd, 
+		       pollfds[i].fd, fd);
+		return(NULL);
+	}
+	*index_out = i;
+	return(irq);
+}
+
+void reactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	int i;
+
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL) return;
+	pollfds[i].events = irq->events;
+	if(irq->type == IRQ_WRITE)
+		add_sigio_fd(fd);
+}
+
+void deactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	int i;
+
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL) return;
+	pollfds[i].events = 0;
+}
+
+void forward_ipi(int fd, int pid)
+{
+	if(fcntl(fd, F_SETOWN, pid) < 0){
+		int save_errno = errno;
+		if(fcntl(fd, F_GETOWN, 0) != pid){
+			printk("forward_ipi: F_SETOWN failed, fd = %d, "
+			       "me = %d, target = %d, errno = %d\n", fd, 
+			       getpid(), pid, save_errno);
+		}
+	}
+}
+
+void forward_interrupts(int pid)
+{
+	struct irq_fd *irq;
+
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		if(fcntl(irq->fd, F_SETOWN, pid) < 0){
+			int save_errno = errno;
+			if(fcntl(irq->fd, F_GETOWN, 0) != pid){
+				/* XXX Just remove the irq rather than
+				 * print out an infinite stream of these
+				 */
+				printk("Failed to forward %d to pid %d, "
+				       "errno = %d\n", irq->fd, pid, 
+				       save_errno);
+			}
+		}
+		irq->pid = pid;
+	}
+}
+
+void init_irq_signals(int on_sigstack)
+{
+	int flags;
+
+	flags = on_sigstack ? SA_ONSTACK : 0;
+	set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, 
+		    flags | SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, 
+		    SIGWINCH, -1);
+	set_handler(SIGIO, (__sighandler_t) irq_handler, flags | SA_RESTART,
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	signal(SIGWINCH, SIG_IGN);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/ksyms.c linux-2.4.19-pre5-mjc/arch/um/kernel/ksyms.c
--- linux/arch/um/kernel/ksyms.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/ksyms.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,31 @@
+#include "linux/module.h"
+#include "linux/string.h"
+#include "asm/current.h"
+#include "asm/delay.h"
+#include "asm/processor.h"
+#include "asm/unistd.h"
+#include "asm/pgalloc.h"
+#include "asm/page.h"
+#include "kern_util.h"
+#include "user_util.h"
+
+EXPORT_SYMBOL(stop);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(uml_physmem);
+EXPORT_SYMBOL(set_signals);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(sys_waitpid);
+EXPORT_SYMBOL(task_size);
+EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_strncpy_from_user);
+EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(__do_clear_user);
+EXPORT_SYMBOL(honeypot);
+EXPORT_SYMBOL(host_task_size);
+EXPORT_SYMBOL(arch_validate);
+
+/* This is here because UML expands open to sys_open, not to a system
+ * call instruction.
+ */
+EXPORT_SYMBOL(sys_open);
diff -Nru linux/arch/um/kernel/mem.c linux-2.4.19-pre5-mjc/arch/um/kernel/mem.c
--- linux/arch/um/kernel/mem.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/mem.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,253 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/types.h"
+#include "linux/mm.h"
+#include "linux/fs.h"
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/swap.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/bitops.h"
+#include "asm/uaccess.h"
+#include "asm/tlb.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "kern.h"
+#include "init.h"
+
+unsigned long high_physmem;
+
+unsigned long low_physmem;
+
+unsigned long vm_start;
+
+unsigned long vm_end;
+
+pgd_t swapper_pg_dir[1024];
+
+unsigned long *empty_zero_page = NULL;
+
+unsigned long *empty_bad_page = NULL;
+
+const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
+
+static unsigned long totalram_pages = 0;
+
+extern char __init_begin, __init_end;
+extern long physmem_size;
+
+#ifdef CONFIG_SMP
+mmu_gather_t mmu_gathers[NR_CPUS];
+#endif
+
+int kmalloc_ok = 0;
+
+void mem_init(void)
+{
+	max_mapnr = num_physpages = max_low_pfn;
+
+        /* clear the zero-page */
+        memset((void *) empty_zero_page, 0, PAGE_SIZE);
+
+	/* this will put all low memory onto the freelists */
+	totalram_pages += free_all_bootmem();
+	printk(KERN_INFO "Memory: %luk available\n", 
+	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
+	kmalloc_ok = 1;
+}
+
+void paging_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES];
+	int i;
+
+	empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+	empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+	for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) 
+		zones_size[i] = 0;
+	zones_size[1] = (high_physmem >> PAGE_SHIFT) - 
+		(uml_physmem >> PAGE_SHIFT) - zones_size[0];
+	free_area_init(zones_size);
+}
+
+static int meminfo_22 = 0;
+
+static int meminfo_compat(char *str)
+{
+	meminfo_22 = 1;
+	return(1);
+}
+
+__setup("22_meminfo", meminfo_compat);
+
+void si_meminfo(struct sysinfo *val)
+{
+	val->totalram = totalram_pages;
+	val->sharedram = 0;
+	val->freeram = nr_free_pages();
+	val->bufferram = atomic_read(&buffermem_pages);
+	val->totalhigh = 0;
+	val->freehigh = 0;
+	val->mem_unit = PAGE_SIZE;
+	if(meminfo_22){
+		val->freeram <<= PAGE_SHIFT;
+		val->bufferram <<= PAGE_SHIFT;
+		val->totalram <<= PAGE_SHIFT;
+		val->sharedram <<= PAGE_SHIFT;
+	}
+}
+
+pte_t __bad_page(void)
+{
+	clear_page(empty_bad_page);
+        return pte_mkdirty(mk_pte((struct page *) empty_bad_page, 
+				  PAGE_SHARED));
+}
+
+/* This can't do anything because nothing in the kernel image can be freed
+ * since it's not in kernel physical memory.
+ */
+
+void free_initmem(void)
+{
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	if (start < end)
+		printk ("Freeing initrd memory: %ldk freed\n", 
+			(end - start) >> 10);
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(start));
+		set_page_count(virt_to_page(start), 1);
+		free_page(start);
+		totalram_pages++;
+	}
+}
+	
+#endif
+
+int do_check_pgt_cache(int low, int high)
+{
+        int freed = 0;
+        if(pgtable_cache_size > high) {
+                do {
+                        if (pgd_quicklist) {
+                                free_pgd_slow(get_pgd_fast());
+                                freed++;
+                        }
+                        if (pmd_quicklist) {
+                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+                                freed++;
+                        }
+                        if (pte_quicklist) {
+                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
+                                freed++;
+                        }
+                } while(pgtable_cache_size > low);
+        }
+        return freed;
+}
+
+void show_mem(void)
+{
+        int i, total = 0, reserved = 0;
+        int shared = 0, cached = 0;
+        int highmem = 0;
+
+        printk("Mem-info:\n");
+        show_free_areas();
+        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+        i = max_mapnr;
+        while (i-- > 0) {
+                total++;
+                if (PageHighMem(mem_map+i))
+                        highmem++;
+                if (PageReserved(mem_map+i))
+                        reserved++;
+                else if (PageSwapCache(mem_map+i))
+                        cached++;
+                else if (page_count(mem_map+i))
+                        shared += page_count(mem_map+i) - 1;
+        }
+        printk("%d pages of RAM\n", total);
+        printk("%d pages of HIGHMEM\n",highmem);
+        printk("%d reserved pages\n",reserved);
+        printk("%d pages shared\n",shared);
+        printk("%d pages swap cached\n",cached);
+        printk("%ld pages in page table cache\n",pgtable_cache_size);
+        show_buffers();
+}
+
+unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+	if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM;
+	return(kmem_top);
+}
+
+void set_kmem_end(unsigned long new)
+{
+	kmem_top = new;
+}
+
+static int __init uml_mem_setup(char *line, int *add)
+{
+	char *retptr;
+	physmem_size = memparse(line,&retptr);
+	return 0;
+}
+__uml_setup("mem=",uml_mem_setup,
+"mem=<Amount of desired ram>\n"
+"    This controls how much \"physical\" memory the kernel allocates\n"
+"    for the system. The size is specified as a number followed by\n"
+"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+"    This is not related to the amount of memory in the physical\n"
+"    machine. It can be more, and the excess, if it's ever used, will\n"
+"    just be swapped out.\n        Example: mem=64M\n\n"
+);
+
+struct page *arch_validate(struct page *page, int mask, int order)
+{
+	unsigned long addr, zero = 0;
+	int i;
+
+ again:
+	if(page == NULL) return(page);
+	addr = (unsigned long) page_address(page);
+	for(i = 0; i < (1 << order); i++){
+		current->thread.fault_addr = (void *) addr;
+		if(__do_copy_to_user((void *) addr, &zero, 
+				     sizeof(zero),
+				     &current->thread.fault_addr,
+				     &current->thread.fault_catcher)){
+			if(!(mask & __GFP_WAIT)) return(NULL);
+			else break;
+		}
+		addr += PAGE_SIZE;
+	}
+	if(i == (1 << order)) return(page);
+	page = _alloc_pages(mask, order);
+	goto again;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/mem_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/mem_user.c
--- linux/arch/um/kernel/mem_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/mem_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,264 @@
+/*
+ * arch/um/kernel/mem_user.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * user side memory routines for supporting IO memory inside user mode linux
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "kern_util.h"
+#include "user.h"
+#include "user_util.h"
+#include "init.h"
+
+struct mem_region {
+	struct mem_region *next;
+	char *driver;
+	unsigned long start;
+	unsigned long usable;
+	unsigned long total;
+	int fd;
+};
+
+struct mem_region physmem_region;
+
+struct mem_region *mem_list = &physmem_region;
+
+#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
+
+int create_mem_file(unsigned long len)
+{
+	int fd;
+	char zero;
+
+	fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
+	if (fchmod(fd, 0777) < 0){
+		perror("fchmod");
+		exit(1);
+	}
+	if(lseek(fd, len, SEEK_SET) < 0){
+		perror("lseek");
+		exit(1);
+	}
+	zero = 0;
+	if(write(fd, &zero, 1) != 1){
+		perror("write");
+		exit(1);
+	}
+	if(fcntl(fd, F_SETFD, 1) != 0)
+		perror("Setting FD_CLOEXEC failed");
+	return(fd);
+}
+
+void setup_range(int fd, char *driver, unsigned long start, 
+		 unsigned long usable, unsigned long total)
+{
+	struct mem_region *region, *next;
+
+	if(fd == -1){
+		fd = create_mem_file(usable);
+		region = &physmem_region;
+		next = physmem_region.next;
+	}
+	else {
+		region = malloc(sizeof(*region));
+		if(region == NULL){
+			perror("Allocating iomem struct");
+			exit(1);
+		}
+		next = physmem_region.next;
+	}
+	*region = ((struct mem_region) { next, driver, start, usable, 
+					 total, fd } );
+	if(region != &physmem_region) physmem_region.next = region;
+}
+
+void __init setup_memory(void)
+{
+	struct mem_region *region;
+	void *loc;
+	unsigned long start;
+	int page;
+
+	start = -1;
+	region = mem_list;
+	page = page_size();
+	while(region){
+		if(region->start != -1) start = region->start;
+		else region->start = start;
+		loc = mmap((void *) region->start, region->usable,
+			   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
+			   region->fd, 0);
+		if(loc != (void *) region->start){
+			perror("Mapping memory");
+			exit(1);
+		}
+		start += region->total;
+		start = (start + page - 1) & ~(page - 1);
+		region = region->next;
+	}
+}
+
+static int __init parse_iomem(char *str, int *add)
+{
+	struct stat buf;
+	char *file, *driver;
+	int fd;
+
+	driver = str;
+	file = strchr(str,',');
+	if(file == NULL){
+		printk(__FUNCTION__ " failed to parse iomem\n");
+		return 1;
+	}
+	*file = '\0';
+	file++;
+	fd = open(file, O_RDWR);
+	if(fd < 0){
+		perror("Couldn't open io file");
+		return 1;
+	}
+	if(fstat(fd, &buf) < 0) {
+		perror(__FUNCTION__ "fstat - cannot fstat file");
+		exit(1);
+	}
+	setup_range(fd, driver, -1, buf.st_size, buf.st_size);
+	return 0;
+}
+__uml_setup("iomem=",parse_iomem,
+"iomem=<name>,<file>\n"
+"    Configure <file> as a named IO memory region named <name>.\n\n"
+);
+
+#ifdef notdef
+int logging = 0;
+int logging_fd = -1;
+
+int logging_line = 0;
+char logging_buf[256];
+
+void log(char *fmt, ...)
+{
+	va_list ap;
+	struct timeval tv;
+
+	if(logging == 0) return;
+	if(logging_fd == -1)
+		logging_fd = open("log", O_RDWR | O_CREAT | O_TRUNC, 0644);
+	gettimeofday(&tv, NULL);
+	sprintf(logging_buf, "%d\t %u.%u  ", logging_line++, tv.tv_sec, 
+		tv.tv_usec);
+	va_start(ap, fmt);
+	vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
+	va_end(ap);
+	write(logging_fd, logging_buf, strlen(logging_buf));
+}
+#endif
+
+void map(unsigned long virt, void *p, unsigned long len, 
+	 int r, int w, int x)
+{
+	struct mem_region *region;
+	unsigned long phys = (unsigned long) p;
+	void *loc;
+	int prot;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+	for(region = mem_list; region ; region = region->next) {
+		if((phys < region->start) || 
+		   (phys >= region->start + region->usable))
+			continue;
+		phys -= region->start;
+		loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
+			   region->fd, phys);
+		if(loc != (void *) virt){
+			panic("Error mapping a page - errno = %d", errno);
+		}
+		return;
+	}
+	panic("No physical or IO memory region for address 0x%x\n", phys);
+}
+
+int unmap(void *addr, int len)
+{
+	int err;
+
+	err = munmap(addr, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int protect(unsigned long addr, unsigned long len, int r, int w, int x,
+	     int must_succeed)
+{
+	int prot;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+	if(mprotect((void *) addr, len, prot) == -1){
+		if(must_succeed)
+			panic("protect failed, errno = %d", errno);
+		else return(-errno);
+	}
+	return(0);
+}
+
+unsigned long find_iomem(char *driver, unsigned long *len_out)
+{
+	struct mem_region *region;
+
+	for(region = mem_list; region ; region = region->next) {
+		if((region->driver != NULL) &&
+		   !strcmp(region->driver, driver)){
+			*len_out = region->usable;
+			return(region->start);
+		}
+	}
+	*len_out = 0;
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/mprot.h linux-2.4.19-pre5-mjc/arch/um/kernel/mprot.h
--- linux/arch/um/kernel/mprot.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/mprot.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,6 @@
+#ifndef __MPROT_H__
+#define __MPROT_H__
+
+extern void no_access(unsigned long addr, unsigned int len);
+
+#endif
diff -Nru linux/arch/um/kernel/process.c linux-2.4.19-pre5-mjc/arch/um/kernel/process.c
--- linux/arch/um/kernel/process.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/process.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,259 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#ifdef PROFILING
+#include <sys/gmon.h>
+#endif
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "irq_user.h"
+#include "syscall_user.h"
+#include "ptrace_user.h"
+#include "init.h"
+
+void stop_pid(int pid)
+{
+	kill(pid, SIGSTOP);
+}
+
+void kill_pid(int pid)
+{
+	kill(pid, SIGKILL);
+}
+
+void usr1_pid(int pid)
+{
+	kill(pid, SIGUSR1);
+}
+
+void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
+{
+	int flags = 0;
+
+	if(sig_stack != NULL){
+		set_sigstack(sig_stack, 2 * page_size());
+		flags = SA_ONSTACK;
+	}
+	set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGUSR2, (__sighandler_t) syscall_handler, 
+		    SA_NOMASK | flags, -1);
+	if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+	signal(SIGCHLD, SIG_IGN);
+	signal(SIGHUP, SIG_IGN);
+	set_timers(1);  /* XXX A bit of a race here */
+	init_irq_signals(sig_stack != NULL);
+}
+
+struct tramp {
+	int (*tramp)(void *);
+	void *tramp_data;
+	unsigned long temp_stack;
+	int flags;
+	int pid;
+};
+
+/* See above for why sigkill is here */
+
+int sigkill = SIGKILL;
+
+int outer_tramp(void *arg)
+{
+	struct tramp *t;
+	int sig = sigkill;
+
+	t = arg;
+	t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+		       t->flags, t->tramp_data);
+	if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT);
+	kill(getpid(), sig);
+	exit(0);
+}
+
+int start_fork_tramp(void *thread_arg, unsigned long temp_stack, 
+		     int clone_flags, int (*tramp)(void *))
+{
+	struct tramp arg;
+	unsigned long sp;
+	int new_pid, status, err;
+
+	/* The trampoline will run on the temporary stack */
+	sp = stack_sp(temp_stack);
+
+	clone_flags |= CLONE_FILES | SIGCHLD;
+
+	arg.tramp = tramp;
+	arg.tramp_data = thread_arg;
+	arg.temp_stack = temp_stack;
+	arg.flags = clone_flags;
+
+	/* Start the process and wait for it to kill itself */
+	new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
+	if(new_pid < 0) return(-errno);
+	while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ;
+	if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", 
+			  errno);
+	if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+		panic("outer trampoline didn't exit with SIGKILL");
+
+	return(arg.pid);
+}
+
+void trace_myself(void)
+{
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+		panic("ptrace failed in trace_myself");
+}
+
+void attach_process(int pid)
+{
+	if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
+		tracer_panic("OP_FORK failed to attach pid");
+	wait_for_stop(pid, SIGSTOP, PTRACE_CONT);
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		tracer_panic("OP_FORK failed to continue process");
+}
+
+void tracer_panic(char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vprintf(format, ap);
+	printf("\n");
+	while(1) sleep(10);
+}
+
+void suspend_new_thread(int fd)
+{
+	char c;
+
+	kill(getpid(), SIGSTOP);
+
+	if(read(fd, &c, sizeof(c)) != sizeof(c))
+		panic("read failed in suspend_new_thread");
+}
+
+static int ptrace_child(void *arg)
+{
+	int pid = getpid();
+
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+		perror("ptrace");
+		exit(1);
+	}
+	kill(pid, SIGSTOP);
+	exit(getpid() == pid);
+}
+
+void __init check_ptrace(void)
+{
+	void *stack;
+	unsigned long sp;
+	int status, pid, n, syscall;
+
+	printk("Checking that ptrace can change system call numbers...");
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if(stack == MAP_FAILED)
+		panic("check_ptrace : mmap failed, errno = %d", errno);
+	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+	pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
+	if(pid < 0)
+		panic("check_ptrace : clone failed, errno = %d", errno);
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0)
+		panic("check_ptrace : wait failed, errno = %d", errno);
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
+		panic("check_ptrace : expected SIGSTOP, got status = %d",
+		      status);
+	while(1){
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			panic("check_ptrace : ptrace failed, errno = %d", 
+			      errno);
+		n = waitpid(pid, &status, WUNTRACED);
+		if(n < 0)
+			panic("check_ptrace : wait failed, errno = %d", errno);
+		if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+			panic("check_ptrace : expected SIGTRAP, "
+			      "got status = %d", status);
+		
+		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
+				 0);
+		if(syscall == __NR_getpid){
+			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
+				   __NR_getppid);
+			if(n < 0)
+				panic("check_ptrace : failed to modify system "
+				      "call, errno = %d", errno);
+			break;
+		}
+	}
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		panic("check_ptrace : ptrace failed, errno = %d", errno);
+	n = waitpid(pid, &status, 0);
+	if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+		panic("check_ptrace : child exited with status %d", status);
+
+	if(munmap(stack, PAGE_SIZE) < 0)
+		panic("check_ptrace : munmap failed, errno = %d", errno);
+	printk("OK\n");
+}
+
+int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+{
+	jmp_buf buf;
+
+	*jmp_ptr = &buf;
+	if(setjmp(buf)) return(1);
+	(*fn)(arg);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/process_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/process_kern.c
--- linux/arch/um/kernel/process_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/process_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,700 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/interrupt.h"
+#include "linux/mm.h"
+#include "linux/slab.h"
+#include "linux/utsname.h"
+#include "linux/fs.h"
+#include "linux/utime.h"
+#include "linux/smp_lock.h"
+#include "linux/module.h"
+#include "linux/init.h"
+#include "linux/capability.h"
+#include "asm/unistd.h"
+#include "asm/mman.h"
+#include "asm/segment.h"
+#include "asm/stat.h"
+#include "asm/pgtable.h"
+#include "asm/processor.h"
+#include "asm/pgalloc.h"
+#include "asm/spinlock.h"
+#include "asm/uaccess.h"
+#include "asm/user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "init.h"
+#include "irq_user.h"
+#include "mem_user.h"
+#include "tlb.h"
+#include "frame.h"
+#include "sigcontext.h"
+#include "2_5compat.h"
+
+struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
+
+int external_pid(void *t)
+{
+	struct task_struct *task = t ? t : current;
+
+	return(task->thread.extern_pid);
+}
+
+int pid_to_processor_id(int pid)
+{
+	int i;
+
+	for(i = 0; i < smp_num_cpus; i++){
+		if(cpu_tasks[i].pid == pid) return(i);
+	}
+	return(-1);
+}
+
+void free_stack(unsigned long stack)
+{
+	free_page(stack);
+}
+
+void set_init_pid(int pid)
+{
+	init_task.thread.extern_pid = pid;
+	if(pipe(init_task.thread.switch_pipe) < 0)
+		panic("Can't create switch pipe for init_task");
+}
+
+int set_user_mode(void *t, int protect_mem)
+{
+	struct task_struct *task;
+
+	task = t ? t : current;
+	if(task->thread.tracing) return(1);
+	task->thread.request.op = OP_TRACE_ON;
+	if(protect_mem) protect_kernel_mem(1);
+	usr1_pid(getpid());
+	return(0);
+}
+
+void set_tracing(void *task, int tracing)
+{
+	((struct task_struct *) task)->thread.tracing = tracing;
+}
+
+int is_tracing(void *t)
+{
+	return (((struct task_struct *) t)->thread.tracing);
+}
+
+unsigned long alloc_stack(void)
+{
+	unsigned long page;
+
+	if((page = __get_free_page(GFP_KERNEL)) == 0)
+		return(0);
+	stack_protections(page);
+	return(page);
+}
+
+extern void schedule_tail(struct task_struct *prev);
+
+static void new_thread_handler(int sig)
+{
+	int (*fn)(void *);
+	void *arg;
+
+	fn = current->thread.request.u.thread.proc;
+	arg = current->thread.request.u.thread.arg;
+	suspend_new_thread(current->thread.switch_pipe[0]);
+
+	free_page(current->thread.temp_stack);
+	set_cmdline("(kernel thread)");
+	force_flush_all();
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+	current->thread.regs.regs.sc = (void *) (&sig + 1);
+	change_sig(SIGUSR1, 1);
+	unblock_signals();
+	if(!run_kernel_thread(fn, arg, &current->thread.jmp))
+		do_exit(0);
+}
+
+static int new_thread_proc(void *stack)
+{
+	block_signals();
+	init_new_thread(stack, new_thread_handler);
+	usr1_pid(getpid());
+}
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	int pid;
+
+	current->thread.request.u.thread.proc = fn;
+	current->thread.request.u.thread.arg = arg;
+	pid = do_fork(CLONE_VM | flags, 0, NULL, 0);
+	if(pid < 0) panic("do_fork failed in kernel_thread");
+	return(pid);
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+	       struct task_struct *tsk, unsigned cpu)
+{
+	if (prev != next) 
+		clear_bit(cpu, &prev->cpu_vm_mask);
+	set_bit(cpu, &next->cpu_vm_mask);
+}
+
+void set_current(void *t)
+{
+	struct task_struct *task = t;
+
+	cpu_tasks[CPU(task)] = ((struct cpu_task) 
+		{ task->thread.extern_pid, task });
+}
+
+void *_switch_to(void *prev, void *next)
+{
+	struct task_struct *from, *to;
+	unsigned long flags;
+	int vtalrm, alrm, err;
+	char c;
+
+	from = prev;
+	to = next;
+
+	to->thread.prev_sched = from;
+
+	if(CPU(from) == 0) forward_interrupts(to->thread.extern_pid);
+	forward_ipi(cpu_data[CPU(from)].ipi_pipe[0], to->thread.extern_pid);
+	local_irq_save(flags);
+
+	vtalrm = change_sig(SIGVTALRM, 0);
+	alrm = change_sig(SIGALRM, 0);
+
+	c = 0;
+	set_current(to);
+	err = user_write(to->thread.switch_pipe[1], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("write of switch_pipe failed, errno = %d", -err);
+
+	if(from->state == TASK_ZOMBIE) kill_pid(getpid());
+	err = user_read(from->thread.switch_pipe[0], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read of switch_pipe failed, errno = %d", -err);
+
+	change_sig(SIGVTALRM, vtalrm);
+	change_sig(SIGALRM, alrm);
+
+	flush_tlb_all();
+	local_irq_restore(flags);
+
+	return(current->thread.prev_sched);
+}
+
+void ret_from_sys_call(void)
+{
+	if(current->need_resched) schedule();
+	if(current->sigpending != 0) do_signal(0);
+}
+
+void release_thread(struct task_struct *task)
+{
+	close(task->thread.switch_pipe[0]);
+	close(task->thread.switch_pipe[1]);
+	kill_pid(task->thread.extern_pid);
+}
+
+void exit_thread(void)
+{
+	unprotect_stack((unsigned long) current);
+}
+
+void finish_fork_handler(int sig)
+{
+	current->thread.regs.regs.sc = (void *) (&sig + 1);
+	suspend_new_thread(current->thread.switch_pipe[0]);
+	
+	force_flush_all();
+	if(current->mm != current->p_pptr->mm)
+		protect(uml_physmem, high_physmem - uml_physmem, 1, 1, 0, 1);
+	task_protections((unsigned long) current);
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	free_page(current->thread.temp_stack);
+	set_user_mode(current, 1);
+}
+
+void *get_current(void)
+{
+	return(current);
+}
+
+/* This sigusr1 business works around a bug in gcc's -pg support.  
+ * Normally a procedure's mcount call comes after esp has been copied to 
+ * ebp and the new frame is constructed.  With procedures with no locals,
+ * the mcount comes before, as the first thing that the procedure does.
+ * When that procedure is main for a thread, ebp comes in as NULL.  So,
+ * when mcount dereferences it, it segfaults.  So, UML works around this
+ * by adding a non-optimizable local to the various trampolines, fork_tramp
+ * and outer_tramp below, and exec_tramp.
+ */
+
+static int sigusr1 = SIGUSR1;
+
+int fork_tramp(void *stack)
+{
+	int sig = sigusr1;
+
+	block_signals();
+	init_new_thread(stack, finish_fork_handler);
+
+	kill(getpid(), sig);
+	return(0);
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+		unsigned long stack_top, struct task_struct * p, 
+		struct pt_regs *regs)
+{
+	int new_pid;
+	unsigned long stack;
+	int (*tramp)(void *);
+
+	p->thread = (struct thread_struct) INIT_THREAD;
+	p->thread.kernel_stack = (unsigned long) p + 2 * PAGE_SIZE;
+
+	if(current->thread.forking)
+		tramp = fork_tramp;
+	else {
+		tramp = new_thread_proc;
+		p->thread.request.u.thread = current->thread.request.u.thread;
+	}
+
+	if(pipe(p->thread.switch_pipe) < 0)
+		panic("copy_thread : pipe failed");
+
+	stack = alloc_stack();
+	if(stack == 0){
+		printk(KERN_ERR "copy_thread : failed to allocate "
+		       "temporary stack\n");
+		return(-ENOMEM);
+	}
+
+	clone_flags &= CLONE_VM;
+	p->thread.temp_stack = stack;
+	new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack,
+				   clone_flags, tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
+		       -new_pid);
+		return(new_pid);
+	}
+
+	if(current->thread.forking){
+		sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc);
+		PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
+		if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp;
+	}
+	else {
+		p->mm = NULL;
+		p->active_mm = NULL;
+	}
+	p->thread.extern_pid = new_pid;
+
+	current->thread.request.op = OP_FORK;
+	current->thread.request.u.fork.pid = new_pid;
+	usr1_pid(getpid());
+	return(0);
+}
+
+void tracing_reboot(void)
+{
+	current->thread.request.op = OP_REBOOT;
+	usr1_pid(getpid());
+}
+
+void tracing_halt(void)
+{
+	current->thread.request.op = OP_HALT;
+	usr1_pid(getpid());
+}
+
+void tracing_cb(void (*proc)(void *), void *arg)
+{
+	if(getpid() == tracing_pid){
+		(*proc)(arg);
+	}
+	else {
+		current->thread.request.op = OP_CB;
+		current->thread.request.u.cb.proc = proc;
+		current->thread.request.u.cb.arg = arg;
+		usr1_pid(getpid());
+	}
+}
+
+int do_proc_op(void *t, int proc_id)
+{
+	struct task_struct *task;
+	struct thread_struct *thread;
+	int op, pid;
+
+	task = t;
+	thread = &task->thread;
+	op = thread->request.op;
+	switch(op){
+	case OP_NONE:
+	case OP_TRACE_ON:
+		break;
+	case OP_EXEC:
+		pid = thread->request.u.exec.pid;
+		do_exec(thread->extern_pid, pid);
+		thread->extern_pid = pid;
+		cpu_tasks[CPU(task)].pid = pid;
+		break;
+	case OP_FORK:
+		attach_process(thread->request.u.fork.pid);
+		break;
+	case OP_CB:
+		(*thread->request.u.cb.proc)(thread->request.u.cb.arg);
+		break;
+	case OP_REBOOT:
+	case OP_HALT:
+		break;
+	default:
+		tracer_panic("Bad op in do_proc_op");
+		break;
+	}
+	thread->request.op = OP_NONE;
+	return(op);
+}
+
+unsigned long stack_sp(unsigned long page)
+{
+	return(page + PAGE_SIZE - sizeof(void *));
+}
+
+int current_pid(void)
+{
+	return(current->pid);
+}
+
+void cpu_idle(void)
+{
+ 	if(CPU(current) == 0) idle_timer();
+
+	atomic_inc(&init_mm.mm_count);
+	current->mm = &init_mm;
+	current->active_mm = &init_mm;
+
+	while(1){
+		/* endless idle loop with no priority at all */
+		SET_PRI(current);
+
+		/*
+		 * although we are an idle CPU, we do not want to
+		 * get into the scheduler unnecessarily.
+		 */
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+		}
+		idle_sleep(10);
+	}
+}
+
+int page_size(void)
+{
+	return(PAGE_SIZE);
+}
+
+int page_mask(void)
+{
+	return(PAGE_MASK);
+}
+
+unsigned long um_virt_to_phys(void *t, unsigned long addr)
+{
+	struct task_struct *task;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	task = t;
+	if(task->mm == NULL) return(0xffffffff);
+	pgd = pgd_offset(task->mm, addr);
+	pmd = pmd_offset(pgd, addr);
+	if(!pmd_present(*pmd)) return(0xffffffff);
+	pte = pte_offset(pmd, addr);
+	if(!pte_present(*pte)) return(0xffffffff);
+	return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
+}
+
+char *current_cmd(void)
+{
+#ifdef CONFIG_SMP
+	return("(Unknown)");
+#else
+	unsigned long addr;
+
+	if((addr = um_virt_to_phys(current, 
+				   current->mm->arg_start)) == 0xffffffff) 
+		return("(Unknown)");
+	else return((char *) addr);
+#endif
+}
+
+void force_sigbus(void)
+{
+	printk(KERN_ERR "Killing pid %d because of a lack of memory\n", 
+	       current->pid);
+	lock_kernel();
+	sigaddset(&current->pending.signal, SIGBUS);
+	recalc_sigpending(current);
+	current->flags |= PF_SIGNALED;
+	do_exit(SIGBUS | 0x80);
+}
+
+void dump_thread(struct pt_regs *regs, struct user *u)
+{
+}
+
+void enable_hlt(void)
+{
+	panic("enable_hlt");
+}
+
+void disable_hlt(void)
+{
+	panic("disable_hlt");
+}
+
+extern int signal_frame_size;
+
+void interrupt_end(void)
+{
+	if(current->need_resched) schedule();
+	do_signal(0);
+}
+
+void *um_kmalloc(int size)
+{
+	return(kmalloc(size, GFP_KERNEL));
+}
+
+void *um_kmalloc_atomic(int size)
+{
+	return(kmalloc(size, GFP_ATOMIC));
+}
+
+unsigned long get_fault_addr(void)
+{
+	return((unsigned long) current->thread.fault_addr);
+}
+
+EXPORT_SYMBOL(get_fault_addr);
+
+int singlestepping(void *t)
+{
+	struct task_struct *task;
+	int ret;
+
+	task = (struct task_struct *) t;
+	ret = (task->ptrace & PT_DTRACE);
+	task->ptrace &= ~PT_DTRACE;
+	return(ret);
+}
+
+void not_implemented(void)
+{
+	printk(KERN_DEBUG "Something isn't implemented in here\n");
+}
+
+EXPORT_SYMBOL(not_implemented);
+
+int user_context(unsigned long sp)
+{
+	return((sp & (PAGE_MASK << 1)) != current->thread.kernel_stack);
+}
+
+extern void remove_umid_dir(void);
+__uml_exitcall(remove_umid_dir);
+
+extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
+
+void do_uml_exitcalls(void)
+{
+	exitcall_t *call;
+
+	call = &__uml_exitcall_end;
+	while (--call >= &__uml_exitcall_begin)
+		(*call)();
+}
+
+extern exitcall_t __exitcall_begin, __exitcall_end;
+
+void do_exitcalls(void)
+{
+	exitcall_t *call;
+
+	call = &__exitcall_end;
+	while (--call >= &__exitcall_begin)
+		(*call)();
+	do_uml_exitcalls();
+}
+
+void *round_up(unsigned long addr)
+{
+	return(ROUND_UP(addr));
+}
+
+void *round_down(unsigned long addr)
+{
+	return(ROUND_DOWN(addr));
+}
+
+char *uml_strdup(char *string)
+{
+	char *new;
+
+	new = kmalloc(strlen(string) + 1, GFP_KERNEL);
+	if(new == NULL) return(NULL);
+	strcpy(new, string);
+	return(new);
+}
+
+int jail = 0;
+
+int __init jail_setup(char *line, int *add)
+{
+	int ok = 1;
+
+	if(jail) return(0);
+#ifdef CONFIG_SMP
+	printf("'jail' may not used used in a kernel with CONFIG_SMP "
+	       "enabled\n");
+	ok = 0;
+#endif
+#ifdef CONFIG_HOSTFS
+	printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
+	       "enabled\n");
+	ok = 0;
+#endif
+#ifdef CONFIG_MODULES
+	printf("'jail' may not used used in a kernel with CONFIG_MODULES "
+	       "enabled\n");
+	ok = 0;
+#endif	
+	if(!ok) exit(1);
+
+	/* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
+	 * Removing it from the bounding set eliminates the ability of anything
+	 * to acquire it, and thus read or write kernel memory.
+	 */
+	cap_lower(cap_bset, CAP_SYS_RAWIO);
+	jail = 1;
+	return(0);
+}
+
+__uml_setup("jail", jail_setup,
+"jail\n"
+"    Enables the protection of kernel memory from processes.\n\n"
+);
+
+static void mprotect_kernel_mem(int w, int delay_signals)
+{
+	unsigned long start, end, flags = 0;
+	int alrm = 0, vtalrm = 0;
+
+	if(!jail || (current == &init_task)) return;
+
+	if(delay_signals){
+		local_irq_save(flags);
+		alrm = change_sig(SIGALRM, 0);
+		vtalrm = change_sig(SIGVTALRM, 0);
+	}
+
+	start = (unsigned long) current + PAGE_SIZE;
+	end = (unsigned long) current + PAGE_SIZE * 4;
+	protect(uml_physmem, start - uml_physmem, 1, w, 1, 1);
+	protect(end, high_physmem - end, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&_stext);
+	end = (unsigned long) ROUND_UP(&_etext);
+	protect(start, end - start, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&_unprotected_end);
+	end = (unsigned long) ROUND_UP(&_edata);
+	protect(start, end - start, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&__bss_start);
+	end = (unsigned long) ROUND_UP(brk_start);
+	protect(start, end - start, 1, w, 1, 1);
+
+	mprotect_kernel_vm(w);
+
+	if(delay_signals){
+		local_irq_restore(flags);
+		change_sig(SIGALRM, alrm);
+		change_sig(SIGVTALRM, vtalrm);
+	}
+}
+
+void unprotect_kernel_mem(int delay_signals)
+{
+	mprotect_kernel_mem(1, delay_signals);
+}
+
+void protect_kernel_mem(int delay_signals)
+{
+	mprotect_kernel_mem(0, delay_signals);
+}
+
+void *get_init_task(void)
+{
+	return(&init_task_union.task);
+}
+
+int copy_to_user_proc(void *to, void *from, int size)
+{
+	return(copy_to_user(to, from, size));
+}
+
+int copy_from_user_proc(void *to, void *from, int size)
+{
+	return(copy_from_user(to, from, size));
+}
+
+void set_thread_sc(void *sc)
+{
+	current->thread.regs.regs.sc = sc;
+}
+
+int smp_sigio_handler(void)
+{
+#ifdef CONFIG_SMP
+	IPI_handler(hard_smp_processor_id());
+	if (hard_smp_processor_id() != 0) return(1);
+#endif
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/ptrace.c linux-2.4.19-pre5-mjc/arch/um/kernel/ptrace.c
--- linux/arch/um/kernel/ptrace.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/ptrace.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,244 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/errno.h"
+#include "linux/smp_lock.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int i, ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	switch (request) {
+		/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		ret = -EIO;
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
+
+		ret = -EIO;
+		if ((addr & 3) || addr < 0) 
+			break;
+
+		tmp = 0;  /* Default return condition */
+		if(addr < FRAME_SIZE_OFFSET){
+			tmp = getreg(child, addr);
+			ret = put_user(tmp,(unsigned long *) data);
+		}
+		break;
+	}
+
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = -EIO;
+		if (access_process_vm(child, addr, &data, sizeof(data), 
+				      1) != sizeof(data))
+			break;
+		ret = 0;
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0)
+			break;
+
+		if (addr < FRAME_SIZE_OFFSET) {
+			ret = putreg(child, addr, data);
+			break;
+		}
+
+		break;
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->ptrace |= PT_TRACESYS;
+		else
+			child->ptrace &= ~PT_TRACESYS;
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		ret = 0;
+		if (child->state == TASK_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->ptrace &= ~PT_TRACESYS;
+		child->ptrace |= PT_DTRACE;
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH:
+		/* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+ 		break;
+
+#ifdef PTRACE_GETREGS
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+	  	if (!access_ok(VERIFY_WRITE, (unsigned *)data, 
+			       FRAME_SIZE_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
+			__put_user(getreg(child, i),(unsigned long *) data);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+#endif
+#ifdef PTRACE_SETREGS
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp = 0;
+	  	if (!access_ok(VERIFY_READ, (unsigned *)data, 
+			       FRAME_SIZE_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
+			__get_user(tmp, (unsigned long *) data);
+			putreg(child, i, tmp);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+#endif
+#ifdef PTRACE_GETFPREGS
+	case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+	        ret = -EIO;
+		break;
+	}
+#endif
+#ifdef PTRACE_SETFPREGS
+	case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+	        ret = -EIO;
+		break;
+	}
+#endif
+	default:
+		ret = -EIO;
+		break;
+	}
+ out_tsk:
+	free_task_struct(child);
+ out:
+	unlock_kernel();
+	return ret;
+}
+
+void syscall_trace(void)
+{
+	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+	    != (PT_PTRACED|PT_TRACESYS))
+		return;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	notify_parent(current, SIGCHLD);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/reboot.c linux-2.4.19-pre5-mjc/arch/um/kernel/reboot.c
--- linux/arch/um/kernel/reboot.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/reboot.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,60 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+
+static void kill_off_processes(void)
+{
+	struct task_struct *p;
+	int me;
+
+	me = getpid();
+	for_each_task(p){
+		if(p->thread.extern_pid != me) kill_pid(p->thread.extern_pid);
+	}
+	if(init_task.thread.extern_pid != me) 
+		kill_pid(init_task.thread.extern_pid);
+}
+
+void uml_cleanup(void)
+{
+	kill_off_processes();
+	do_uml_exitcalls();
+}
+
+void machine_restart(char * __unused)
+{
+	do_exitcalls();
+	kill_off_processes();
+	tracing_reboot();
+	kill_pid(getpid());
+}
+
+void machine_power_off(void)
+{
+	do_exitcalls();
+	kill_off_processes();
+	tracing_halt();
+	kill_pid(getpid());
+}
+
+void machine_halt(void)
+{
+	machine_power_off();
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/resource.c linux-2.4.19-pre5-mjc/arch/um/kernel/resource.c
--- linux/arch/um/kernel/resource.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/resource.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/pci.h"
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+			     unsigned long start, unsigned long size)
+{
+	return start;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/setup.c linux-2.4.19-pre5-mjc/arch/um/kernel/setup.c
--- linux/arch/um/kernel/setup.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/setup.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,19 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/processor.h"
+
+struct cpuinfo_um boot_cpu_data = { 0, 0, 0, 0 };
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/sigio_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/sigio_kern.c
--- linux/arch/um/kernel/sigio_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/sigio_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/list.h"
+#include "linux/slab.h"
+#include "asm/irq.h"
+#include "init.h"
+#include "sigio.h"
+#include "irq_user.h"
+
+static int sigio_irq_fd = -1;
+
+void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	read_sigio_fd(sigio_irq_fd);
+	reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
+}
+
+int write_sigio_irq(int fd)
+{
+	if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", 
+			  NULL)){
+		printk("write_sigio_irq : um_request_irq failed\n");
+		return(-1);
+	}
+	sigio_irq_fd = fd;
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/sigio_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/sigio_user.c
--- linux/arch/um/kernel/sigio_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/sigio_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,368 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <pty.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include "init.h"
+#include "user.h"
+#include "kern_util.h"
+#include "sigio.h"
+
+static int pty_sigio_works = 0;
+
+static int got_sigio = 0;
+
+void __init handler(int sig)
+{
+	got_sigio = 1;
+}
+
+void __init check_sigio(void)
+{
+	struct sigaction old, new;
+	struct termios tt;
+	int master, slave, flags, n;
+	char buf[512];
+
+	printk("Checking that host ptys support output SIGIO...");
+	if(openpty(&master, &slave, NULL, NULL, NULL))
+		panic("check_sigio: Couldn't open a host pty");
+
+	if(tcgetattr(master, &tt) < 0)
+		panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
+	cfmakeraw(&tt);
+	if(tcsetattr(master, TCSADRAIN, &tt) < 0)
+		panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
+
+	if((flags = fcntl(master, F_GETFL)) < 0)
+		panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
+
+	if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+	   (fcntl(master, F_SETOWN, getpid()) < 0))
+		panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
+		      "errno = %d\n", errno);
+
+	if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+		panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", 
+		      errno);
+
+	if(sigaction(SIGIO, NULL, &old) < 0)
+		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+	new = old;
+	new.sa_handler = handler;
+	if(sigaction(SIGIO, &new, NULL) < 0)
+		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+		
+	while(write(master, buf, sizeof(buf)) > 0) ;
+	if(errno != EAGAIN)
+		panic("check_sigio : write failed, errno = %d\n", errno);
+
+	while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+	if(got_sigio){
+		printk("Yes\n");
+		pty_sigio_works = 1;
+	}
+	else if(errno == EAGAIN) printk("No, enabling workaround\n");
+	else panic("check_sigio : read failed, errno = %d\n", errno);
+
+	close(master);
+	close(slave);
+
+	if(sigaction(SIGIO, &old, NULL) < 0)
+		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static int write_sigio_pid = -1;
+static int write_sigio_fds[2] = { -1, -1 };
+static int sigio_private[2] = { -1, -1 };
+
+struct pollfds {
+	struct pollfd *poll;
+	int size;
+	int used;
+};
+
+struct pollfds current_poll = {
+	poll : 		NULL,
+	size :		0,
+	used :		0
+};
+
+struct pollfds next_poll = {
+	poll : 		NULL,
+	size :		0,
+	used :		0
+};
+
+static int write_sigio_thread(void *unused)
+{
+	struct pollfds *fds, tmp;
+	struct pollfd *p;
+	int i, n, respond_fd;
+	char c;
+
+	fds = &current_poll;
+	while(1){
+		n = poll(fds->poll, fds->used, -1);
+		if(n < 0){
+			if(errno == EINTR) continue;
+			printk("write_sigio_thread : poll returned %d, "
+			       "errno = %d\n", n, errno);
+		}
+		for(i = 0; i < fds->used; i++){
+			p = &fds->poll[i];
+			if(p->revents == 0) continue;
+			if(p->fd == sigio_private[1]){
+				n = read(sigio_private[1], &c, sizeof(c));
+				if(n != sizeof(c))
+					printk("write_sigio_thread : "
+					       "read failed, errno = %d\n",
+					       errno);
+				tmp = current_poll;
+				current_poll = next_poll;
+				next_poll = tmp;
+				respond_fd = sigio_private[1];
+			}
+			else {
+				respond_fd = write_sigio_fds[1];
+				fds->used--;
+				memmove(&fds->poll[i], &fds->poll[i + 1],
+					(fds->used - i) * sizeof(*fds->poll));
+			}
+
+			n = write(respond_fd, &c, sizeof(c));
+			if(n != sizeof(c))
+				printk("write_sigio_thread : write failed, "
+				       "errno = %d\n", errno);
+		}
+	}
+}
+
+struct sigio_tramp_info {
+	int err;
+	void *stack;
+};
+
+static void sigio_tramp(void *arg)
+{
+	struct sigio_tramp_info *info = arg;
+	int pid;
+
+	pid = clone(write_sigio_thread, info->stack, CLONE_FILES | SIGCHLD, 
+		    NULL);
+        if(pid > 0) write_sigio_pid = pid;
+	else info->err = errno;
+}
+
+/* XXX SMP locking needed here too */
+
+static int need_poll(int n)
+{
+	if(n <= next_poll.size){
+		next_poll.used = n;
+		return(0);
+	}
+	if(next_poll.poll != NULL) kfree(next_poll.poll);
+	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
+	if(next_poll.poll == NULL){
+		printk("need_poll : failed to allocate new pollfds\n");
+		next_poll.size = 0;
+		next_poll.used = 0;
+		return(-1);
+	}
+	next_poll.size = n;
+	next_poll.used = n;
+	return(0);
+}
+
+static void update_thread(void)
+{
+	unsigned long flags;
+	int n;
+	char c;
+
+	flags = set_signals(0);
+	n = write(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("add_sigio_fd : write failed, errno = %d\n", errno);
+		goto fail;
+	}
+
+	n = read(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("add_sigio_fd : read failed, errno = %d\n", errno);
+		goto fail;
+	}
+
+	set_signals(flags);
+	return;
+ fail:
+	kill(write_sigio_pid, SIGKILL);
+	write_sigio_pid = -1;
+	close(sigio_private[0]);
+	close(sigio_private[1]);	
+	close(write_sigio_fds[0]);
+	close(write_sigio_fds[1]);
+	set_signals(flags);
+}
+
+int add_sigio_fd(int fd)
+{
+	int err, i, n;
+
+	for(i = 0; i < current_poll.used; i++)
+		if(current_poll.poll[i].fd == fd) return(0);
+
+	n = current_poll.used + 1;
+	err = need_poll(n);
+	if(err) return(err);
+
+	for(i = 0; i < current_poll.used; i++)
+		next_poll.poll[i] = current_poll.poll[i];
+
+	next_poll.poll[n - 1] = ((struct pollfd) { fd : 	fd,
+						   events :	POLLOUT,
+						   revents :	0 });
+	update_thread();
+	return(0);
+}
+
+int ignore_sigio_fd(int fd)
+{
+	struct pollfd *p;
+	int err, i, n = 0;
+
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) break;
+	}
+	if(i == current_poll.used) return(0);
+	
+	err = need_poll(current_poll.used - 1);
+	if(err) return(err);
+
+	for(i = 0; i < current_poll.used; i++){
+		p = &current_poll.poll[i];
+		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
+	}
+	if(n == i){
+		printk("ignore_sigio_fd : fd %d not found\n", fd);
+		return(-1);
+	}
+
+	update_thread();
+	return(0);
+}
+
+static int setup_initial_poll(int fd)
+{
+	struct pollfd *p;
+
+	p = um_kmalloc(sizeof(struct pollfd));
+	if(p == NULL){
+		printk("setup_initial_poll : failed to allocate poll\n");
+		return(-1);
+	}
+	*p = ((struct pollfd) { fd : 	fd,
+				events :	POLLIN,
+				revents :	0 });
+	current_poll = ((struct pollfds) { poll :	p,
+					   used :	1,
+					   size :	1 });
+	return(0);
+}
+
+void write_sigio_workaround(int fd)
+{
+	struct sigio_tramp_info info;
+	unsigned long stack;
+
+	if((write_sigio_pid != -1) || pty_sigio_works || !isatty(fd)) return;
+
+	/* XXX This needs SMP locking */
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, write_sigio_fds) < 0){
+		printk("write_sigio_workaround - socketpair 1 failed, "
+		       "errno = %d\n", errno);
+		return;
+	}
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, sigio_private) < 0){
+		printk("write_sigio_workaround - socketpair 2 failed, "
+		       "errno = %d\n", errno);
+		goto out_close1;
+	}
+	if(setup_initial_poll(sigio_private[1]))
+		goto out_close2;
+
+	stack = alloc_stack();
+	if(stack == 0){
+		printk("write_sigio_workaround - failed to allocate stack\n");
+		goto out_close2;
+	}
+	stack += page_size() - sizeof(void *);
+
+	info = ((struct sigio_tramp_info) { err : 	0,
+					    stack :	(void *) stack });
+	tracing_cb(sigio_tramp, &info);
+	if(info.err != 0){
+		printk("write_sigio_workaround - failed to start "
+		       "sigio thread, errno = %d\n", errno);
+		goto out_close2;
+	}
+
+	if(write_sigio_irq(write_sigio_fds[0])) 
+		goto out_kill;
+
+	return;
+
+ out_kill:
+	kill(write_sigio_pid, SIGKILL);
+	write_sigio_pid = -1;
+ out_close2:
+	close(sigio_private[0]);
+	close(sigio_private[1]);	
+ out_close1:
+	close(write_sigio_fds[0]);
+	close(write_sigio_fds[1]);
+}
+
+int read_sigio_fd(int fd)
+{
+	int n;
+	char c;
+
+	n = read(fd, &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("read_sigio_fd - read failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	return(n);
+}
+
+static void sigio_cleanup(void)
+{
+	if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
+}
+
+__uml_exitcall(sigio_cleanup);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/signal_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/signal_kern.c
--- linux/arch/um/kernel/signal_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/signal_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,355 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/stddef.h"
+#include "linux/sys.h"
+#include "linux/sched.h"
+#include "linux/wait.h"
+#include "linux/kernel.h"
+#include "linux/smp_lock.h"
+#include "linux/module.h"
+#include "linux/slab.h"
+#include "asm/signal.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "kern.h"
+#include "frame_kern.h"
+#include "frame.h"
+#include "sigcontext.h"
+#include "sigcontext_kern.h"
+
+EXPORT_SYMBOL(block_signals);
+EXPORT_SYMBOL(unblock_signals);
+
+int probe_stack(unsigned long sp, int delta)
+{
+	int n;
+
+	if((get_user(n, (int *) sp) != 0) ||
+	   (put_user(n, (int *) sp) != 0) ||
+	   (get_user(n, (int *) (sp - delta)) != 0) ||
+	   (put_user(n, (int *) (sp - delta)) != 0))
+		return(-EFAULT);
+	return(0);
+}
+
+static void force_segv(int sig)
+{
+	if(sig == SIGSEGV){
+		struct k_sigaction *ka;
+
+		ka = &current->sig->action[SIGSEGV - 1];
+		ka->sa.sa_handler = SIG_DFL;
+	}
+	force_sig(SIGSEGV, current);
+}
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+/*
+ * OK, we're invoking a handler
+ */	
+static int handle_signal(struct pt_regs *regs, unsigned long signr, 
+			 struct k_sigaction *ka, siginfo_t *info, 
+			 sigset_t *oldset, int error)
+{
+	struct signal_context *context;
+        __sighandler_t handler;
+	void (*restorer)(void);
+	unsigned long sp;
+	sigset_t save;
+	int err, ret;
+
+	ret = 0;
+	switch(error){
+	case -ERESTARTNOHAND:
+		ret = -EINTR;
+		break;
+
+	case -ERESTARTSYS:
+		if (!(ka->sa.sa_flags & SA_RESTART)) {
+			ret = -EINTR;
+			break;
+		}
+		/* fallthrough */
+	case -ERESTARTNOINTR:
+		PT_REGS_RESTART_SYSCALL(regs);
+		PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+
+		/* This is because of the UM_SET_SYSCALL_RETURN and the fact
+		 * that on i386 the system call number and return value are
+		 * in the same register.  When the system call restarts, %eax
+		 * had better have the system call number in it.  Since the
+		 * return value doesn't matter (except that it shouldn't be
+		 * -ERESTART*), we'll stick the system call number there.
+		 */
+		ret = PT_REGS_SYSCALL_NR(regs);
+		break;
+	}
+
+	handler = ka->sa.sa_handler;
+	save = *oldset;
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked, &current->blocked, 
+			  &ka->sa.sa_mask);
+		sigaddset(&current->blocked, signr);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+
+	sp = PT_REGS_SP(regs);
+
+	if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+	
+	sp -= 4 * sizeof(void *) + sizeof(*context);
+	context = (struct signal_context *) sp;
+
+	if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret);
+
+	if(copy_to_user(&context->prev, &current->thread.signal_context,
+			sizeof(current->thread.signal_context)))
+		goto segv;
+	
+	current->thread.signal_context = context;
+	sp -= 4 * sizeof(void *);
+
+	if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
+	else restorer = NULL;
+
+	if(ka->sa.sa_flags & SA_SIGINFO)
+		err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
+					    restorer, regs, &context->sc, info,
+					    &context->arch, &save);
+	else
+		err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
+					    restorer, regs, &context->sc,
+					    &context->arch, &save);
+	if(err) goto segv;
+
+	return(0);
+ segv:
+	force_segv(signr);
+	return(1);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+
+static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	int err;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	for (;;) {
+		unsigned long signr;
+
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		if (!signr)
+			break;
+
+		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+                        case SIGSTOP: {
+                                struct signal_struct *sig;
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+                                sig = current->p_pptr->sig;
+                                if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+			}
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+				if (do_coredump(signr, &current->thread.regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
+			default:
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
+				/* NOTREACHED */
+			}
+		}
+
+		/* Whee!  Actually deliver the signal.  */
+		err = handle_signal(regs, signr, ka, &info, oldset, error);
+		if(!err) return(1);
+	}
+
+	/* Did we come from a system call? */
+	if(PT_REGS_SYSCALL_NR(regs) >= 0){
+		/* Restart the system call - no handlers present */
+		if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
+		   PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
+		   PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
+			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+			PT_REGS_RESTART_SYSCALL(regs);
+		}
+	}
+	return(0);
+}
+
+int do_signal(int error)
+{
+	return(kern_do_signal(&current->thread.regs, NULL, error));
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if(kern_do_signal(&current->thread.regs, &saveset, -EINTR))
+			return(-EINTR);
+	}
+}
+
+int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (kern_do_signal(&current->thread.regs, &saveset, -EINTR))
+			return(-EINTR);
+	}
+}
+
+int sys_sigreturn(struct pt_regs regs)
+{
+	struct signal_context *context = current->thread.signal_context;
+
+	spin_lock_irq(&current->sigmask_lock);
+	copy_sigmask_from_user(&current->blocked, context->sc, &context->arch);
+	sigdelsetmask(&current->blocked, ~_BLOCKABLE);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	current->thread.signal_context = context->prev;
+	if(context->sc != NULL){
+		copy_sc_from_user(current->thread.regs.regs.sc, context->sc,
+				  &signal_frame_sc.arch);
+	}
+	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/signal_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/signal_user.c
--- linux/arch/um/kernel/signal_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/signal_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,139 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
+#include "sigcontext.h"
+
+extern int timer_on;
+
+void set_sigstack(void *sig_stack, int size)
+{
+	stack_t stack;
+
+	stack.ss_sp = (__ptr_t) sig_stack;
+	stack.ss_flags = 0;
+	stack.ss_size = size - sizeof(void *);
+	if(sigaltstack(&stack, NULL) != 0)
+		panic("sigaltstack failed");
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+	struct sigaction action;
+	va_list ap;
+	int mask;
+
+	va_start(ap, flags);
+	action.sa_handler = handler;
+	sigemptyset(&action.sa_mask);
+	while((mask = va_arg(ap, int)) != -1){
+		sigaddset(&action.sa_mask, mask);
+	}
+	action.sa_flags = flags;
+	action.sa_restorer = NULL;
+	if(sigaction(sig, &action, NULL) < 0)
+		panic("sigaction failed");
+}
+
+int change_sig(int signal, int on)
+{
+	sigset_t sigset, old;
+
+	sigemptyset(&sigset);
+	sigaddset(&sigset, signal);
+	sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+	return(sigismember(&old, signal));
+}
+
+static void change_signals(int type)
+{
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	if(type == SIG_BLOCK) timer_on = 0;
+	else {
+		timer_on = 1;
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+	sigaddset(&mask, SIGIO);
+	sigaddset(&mask, SIGWINCH);
+	sigaddset(&mask, SIGPROF);
+	if(sigprocmask(type, &mask, NULL) < 0)
+		panic("Failed to change signal mask - errno = %d", errno);
+}
+
+void block_signals(void)
+{
+	change_signals(SIG_BLOCK);
+}
+
+void unblock_signals(void)
+{
+	change_signals(SIG_UNBLOCK);
+}
+
+#define SIGIO_BIT 0
+#define SIGVTALRM_BIT 1
+
+static int enable_mask(sigset_t *mask)
+{
+	int sigs;
+
+	sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
+	sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
+	sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
+	if(timer_on) sigs |= 1 << SIGVTALRM_BIT;
+	return(sigs);
+}
+
+int set_signals(int enable)
+{
+	sigset_t mask;
+	int ret;
+
+	sigemptyset(&mask);
+	if(enable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO);
+	if(enable & (1 << SIGVTALRM_BIT)){
+		timer_on = 1;
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+	if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
+		panic("Failed to enable signals");
+	ret = enable_mask(&mask);
+	sigemptyset(&mask);
+	if((enable & (1 << SIGIO_BIT)) == 0) sigaddset(&mask, SIGIO);
+	if((enable & (1 << SIGVTALRM_BIT)) == 0){
+		timer_on = 0;
+	}
+	if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
+		panic("Failed to block signals");
+	return(ret);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/smp.c linux-2.4.19-pre5-mjc/arch/um/kernel/smp.c
--- linux/arch/um/kernel/smp.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/smp.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,294 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+
+
+#ifdef CONFIG_SMP
+
+#include "linux/sched.h"
+#include "linux/threads.h"
+#include "linux/interrupt.h"
+#include "asm/smp.h"
+#include "asm/processor.h"
+#include "asm/spinlock.h"
+#include "asm/softirq.h"
+#include "asm/hardirq.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+
+/* Total count of live CPUs */
+int smp_num_cpus = 1;
+
+/* The 'big kernel lock' */
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_um cpu_data[NR_CPUS];
+
+/* CPU online map */
+unsigned long cpu_online_map;
+
+spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
+
+atomic_t global_bh_count;
+
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile long global_irq_lock;
+
+/* Set when the idlers are all forked */
+int smp_threads_ready = 0;
+int num_reschedules_sent = 0;
+
+void smp_send_reschedule(int cpu)
+{
+	write(cpu_data[cpu].ipi_pipe[1], "R", 1);
+	num_reschedules_sent++;
+}
+
+static void show(char * str)
+{
+	int cpu = smp_processor_id();
+
+	printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
+}
+	
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+	int count = MAXCOUNT;
+	do {
+		if (!--count) {
+			show("wait_on_bh");
+			count = ~0;
+		}
+		/* nothing .. wait for the other bh's to go away */
+	} while (atomic_read(&global_bh_count) != 0);
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler. 
+ */
+void synchronize_bh(void)
+{
+	if (atomic_read(&global_bh_count) && !in_interrupt())
+		wait_on_bh();
+}
+
+void smp_send_stop(void)
+{
+	printk(KERN_INFO "Stopping all CPUs\n");
+}
+
+
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+static volatile unsigned long smp_callin_map = 0;
+
+void smp_commence(void)
+{
+	printk("All CPUs are go!\n");
+
+	wmb();
+	atomic_set(&smp_commenced, 1);
+}
+
+static int idle_proc(void *unused)
+{
+	int cpu;
+
+	set_current(current);
+	del_from_runqueue(current);
+	unhash_process(current);
+
+	cpu = current->processor;
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, cpu_data[cpu].ipi_pipe) < 0)
+		panic("CPU#%d failed to create IPI pipe", cpu);
+
+	activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid);
+ 
+	wmb();
+	if (test_and_set_bit(current->processor, &smp_callin_map)) {
+		printk("huh, CPU#%d already present??\n", current->processor);
+		BUG();
+	}
+
+	while (!atomic_read(&smp_commenced))
+		cpu_relax();
+
+	init_idle();
+	cpu_idle();
+	return(0);
+}
+
+static int idle_thread(int (*fn)(void *), void *arg, int cpu)
+{
+	struct task_struct *new_task;
+	unsigned char c;
+
+	pid = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0);
+	if(pid < 0) panic("do_fork failed in idle_thread");
+	new_task = get_task(pid, 1);
+
+	cpu_tasks[cpu].pid = new_task->thread.extern_pid;
+	cpu_tasks[cpu].task = new_task;
+	inited_cpus++;
+	init_tasks[cpu] = new_task;
+	new_task->processor = cpu;
+	new_task->cpus_allowed = 1 << cpu;
+	new_task->cpus_runnable = new_task->cpus_allowed;
+	write(new_task->thread.switch_pipe[1], &c, sizeof(c));
+	return(new_task->thread.extern_pid);
+}
+
+void smp_boot_cpus(void)
+{
+	set_bit(0, &cpu_online_map);
+	set_bit(0, &smp_callin_map);
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, cpu_data[0].ipi_pipe) < 0)
+		panic("CPU#0 failed to create IPI pipe");
+	activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid);
+
+	if(ncpus < 1){
+		printk(KERN_INFO "ncpus set to 1\n");
+		ncpus = 1;
+	}
+	else if(ncpus > NR_CPUS){
+		printk(KERN_INFO 
+		       "ncpus can't be greater than NR_CPUS, set to %d\n",
+		       NR_CPUS);
+		ncpus = NR_CPUS;
+	}
+
+	if(ncpus > 1){
+		int i, pid;
+
+		printk(KERN_INFO "Starting up other processors:\n");
+		for(i=1;i<ncpus;i++){
+			int waittime;
+
+			/* Do this early, for hard_smp_processor_id()  */
+			cpu_tasks[i].pid = -1;
+			set_bit(i, &cpu_online_map);
+			smp_num_cpus++;
+
+			pid = kernel_thread1(idle_proc, NULL, CLONE_PID, i);
+			printk(KERN_INFO "\t#%d - idle thread pid = %d.. ",
+			       i, pid);
+
+			waittime = 200000000;
+			while (waittime-- && !test_bit(i, &smp_callin_map))
+				cpu_relax();
+
+			if (test_bit(i, &smp_callin_map))
+				printk("online\n");
+			else {
+				printk("failed\n");
+				clear_bit(i, &cpu_online_map);
+			}
+		}
+	}
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+	printk(KERN_INFO "setup_profiling_timer\n");
+	return(0);
+}
+
+void smp_call_function_slave(int cpu);
+
+void IPI_handler(int cpu)
+{
+	unsigned char c;
+	int fd;
+
+	fd = cpu_data[cpu].ipi_pipe[0];
+	while (read(fd, &c, 1) == 1) {
+		switch (c) {
+		case 'C':
+			smp_call_function_slave(cpu);
+			break;
+
+		case 'R':
+			current->need_resched = 1;
+			break;
+
+		default:
+			printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
+			break;
+		}
+	}
+}
+
+int inited_cpus = 1;
+
+int hard_smp_processor_id(void)
+{
+	return(pid_to_processor_id(getpid()));
+}
+
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static atomic_t scf_started;
+static atomic_t scf_finished;
+static void (*func)(void *info);
+static void *info;
+
+void smp_call_function_slave(int cpu)
+{
+	atomic_inc(&scf_started);
+	(*func)(info);
+	atomic_inc(&scf_finished);
+}
+
+int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
+		      int wait)
+{
+	int cpus = smp_num_cpus - 1;
+	int i;
+
+	if (!cpus)
+		return 0;
+
+	spin_lock_bh(&call_lock);
+	atomic_set(&scf_started, 0);
+	atomic_set(&scf_finished, 0);
+	func = _func;
+	info = _info;
+
+	for (i=0;i<NR_CPUS;i++)
+		if (i != current->processor && test_bit(i, &cpu_online_map))
+			write(cpu_data[i].ipi_pipe[1], "C", 1);
+
+	while (atomic_read(&scf_started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&scf_finished) != cpus)
+			barrier();
+
+	spin_unlock_bh(&call_lock);
+	return 0;
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/sys_call_table.c linux-2.4.19-pre5-mjc/arch/um/kernel/sys_call_table.c
--- linux/arch/um/kernel/sys_call_table.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/sys_call_table.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,472 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/unistd.h"
+#include "linux/version.h"
+#include "linux/sys.h"
+#include "asm/signal.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_exit;
+extern syscall_handler_t sys_fork;
+extern syscall_handler_t sys_read;
+extern syscall_handler_t sys_write;
+extern syscall_handler_t sys_creat;
+extern syscall_handler_t sys_link;
+extern syscall_handler_t sys_unlink;
+extern syscall_handler_t sys_chdir;
+extern syscall_handler_t sys_mknod;
+extern syscall_handler_t sys_chmod;
+extern syscall_handler_t sys_lchown16;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_stat;
+extern syscall_handler_t sys_lseek;
+extern syscall_handler_t sys_getpid;
+extern syscall_handler_t sys_oldumount;
+extern syscall_handler_t sys_setuid16;
+extern syscall_handler_t sys_getuid16;
+extern syscall_handler_t sys_ptrace;
+extern syscall_handler_t sys_alarm;
+extern syscall_handler_t sys_fstat;
+extern syscall_handler_t sys_pause;
+extern syscall_handler_t sys_utime;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_access;
+extern syscall_handler_t sys_nice;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_sync;
+extern syscall_handler_t sys_kill;
+extern syscall_handler_t sys_rename;
+extern syscall_handler_t sys_mkdir;
+extern syscall_handler_t sys_rmdir;
+extern syscall_handler_t sys_pipe;
+extern syscall_handler_t sys_times;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_brk;
+extern syscall_handler_t sys_setgid16;
+extern syscall_handler_t sys_getgid16;
+extern syscall_handler_t sys_signal;
+extern syscall_handler_t sys_geteuid16;
+extern syscall_handler_t sys_getegid16;
+extern syscall_handler_t sys_acct;
+extern syscall_handler_t sys_umount;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ioctl;
+extern syscall_handler_t sys_fcntl;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_setpgid;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_olduname;
+extern syscall_handler_t sys_umask;
+extern syscall_handler_t sys_chroot;
+extern syscall_handler_t sys_ustat;
+extern syscall_handler_t sys_dup2;
+extern syscall_handler_t sys_getppid;
+extern syscall_handler_t sys_getpgrp;
+extern syscall_handler_t sys_sigaction;
+extern syscall_handler_t sys_sgetmask;
+extern syscall_handler_t sys_ssetmask;
+extern syscall_handler_t sys_setreuid16;
+extern syscall_handler_t sys_setregid16;
+extern syscall_handler_t sys_sigsuspend;
+extern syscall_handler_t sys_sigpending;
+extern syscall_handler_t sys_sethostname;
+extern syscall_handler_t sys_setrlimit;
+extern syscall_handler_t sys_old_getrlimit;
+extern syscall_handler_t sys_getrusage;
+extern syscall_handler_t sys_gettimeofday;
+extern syscall_handler_t sys_settimeofday;
+extern syscall_handler_t sys_getgroups16;
+extern syscall_handler_t sys_setgroups16;
+extern syscall_handler_t sys_symlink;
+extern syscall_handler_t sys_lstat;
+extern syscall_handler_t sys_readlink;
+extern syscall_handler_t sys_uselib;
+extern syscall_handler_t sys_swapon;
+extern syscall_handler_t sys_reboot;
+extern syscall_handler_t old_readdir;
+extern syscall_handler_t sys_munmap;
+extern syscall_handler_t sys_truncate;
+extern syscall_handler_t sys_ftruncate;
+extern syscall_handler_t sys_fchmod;
+extern syscall_handler_t sys_fchown16;
+extern syscall_handler_t sys_getpriority;
+extern syscall_handler_t sys_setpriority;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_statfs;
+extern syscall_handler_t sys_fstatfs;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_socketcall;
+extern syscall_handler_t sys_syslog;
+extern syscall_handler_t sys_setitimer;
+extern syscall_handler_t sys_getitimer;
+extern syscall_handler_t sys_newstat;
+extern syscall_handler_t sys_newlstat;
+extern syscall_handler_t sys_newfstat;
+extern syscall_handler_t sys_uname;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_vhangup;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_swapoff;
+extern syscall_handler_t sys_sysinfo;
+extern syscall_handler_t sys_ipc;
+extern syscall_handler_t sys_fsync;
+extern syscall_handler_t sys_sigreturn;
+extern syscall_handler_t sys_clone;
+extern syscall_handler_t sys_setdomainname;
+extern syscall_handler_t sys_newuname;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_adjtimex;
+extern syscall_handler_t sys_mprotect;
+extern syscall_handler_t sys_sigprocmask;
+extern syscall_handler_t sys_create_module;
+extern syscall_handler_t sys_init_module;
+extern syscall_handler_t sys_delete_module;
+extern syscall_handler_t sys_get_kernel_syms;
+extern syscall_handler_t sys_quotactl;
+extern syscall_handler_t sys_getpgid;
+extern syscall_handler_t sys_fchdir;
+extern syscall_handler_t sys_bdflush;
+extern syscall_handler_t sys_sysfs;
+extern syscall_handler_t sys_personality;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_setfsuid16;
+extern syscall_handler_t sys_setfsgid16;
+extern syscall_handler_t sys_llseek;
+extern syscall_handler_t sys_getdents;
+extern syscall_handler_t sys_flock;
+extern syscall_handler_t sys_msync;
+extern syscall_handler_t sys_readv;
+extern syscall_handler_t sys_writev;
+extern syscall_handler_t sys_getsid;
+extern syscall_handler_t sys_fdatasync;
+extern syscall_handler_t sys_sysctl;
+extern syscall_handler_t sys_mlock;
+extern syscall_handler_t sys_munlock;
+extern syscall_handler_t sys_mlockall;
+extern syscall_handler_t sys_munlockall;
+extern syscall_handler_t sys_sched_setparam;
+extern syscall_handler_t sys_sched_getparam;
+extern syscall_handler_t sys_sched_setscheduler;
+extern syscall_handler_t sys_sched_getscheduler;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+extern syscall_handler_t sys_sched_yield;
+#endif
+extern syscall_handler_t sys_sched_get_priority_max;
+extern syscall_handler_t sys_sched_get_priority_min;
+extern syscall_handler_t sys_sched_rr_get_interval;
+extern syscall_handler_t sys_nanosleep;
+extern syscall_handler_t sys_mremap;
+extern syscall_handler_t sys_setresuid16;
+extern syscall_handler_t sys_getresuid16;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_query_module;
+extern syscall_handler_t sys_poll;
+extern syscall_handler_t sys_nfsservctl;
+extern syscall_handler_t sys_setresgid16;
+extern syscall_handler_t sys_getresgid16;
+extern syscall_handler_t sys_prctl;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_rt_sigaction;
+extern syscall_handler_t sys_rt_sigprocmask;
+extern syscall_handler_t sys_rt_sigpending;
+extern syscall_handler_t sys_rt_sigtimedwait;
+extern syscall_handler_t sys_rt_sigqueueinfo;
+extern syscall_handler_t sys_rt_sigsuspend;
+extern syscall_handler_t sys_pread;
+extern syscall_handler_t sys_pwrite;
+extern syscall_handler_t sys_chown16;
+extern syscall_handler_t sys_getcwd;
+extern syscall_handler_t sys_capget;
+extern syscall_handler_t sys_capset;
+extern syscall_handler_t sys_sigaltstack;
+extern syscall_handler_t sys_sendfile;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_vfork;
+extern syscall_handler_t sys_getrlimit;
+extern syscall_handler_t sys_mmap2;
+extern syscall_handler_t sys_truncate64;
+extern syscall_handler_t sys_ftruncate64;
+extern syscall_handler_t sys_stat64;
+extern syscall_handler_t sys_lstat64;
+extern syscall_handler_t sys_fstat64;
+extern syscall_handler_t sys_lchown;
+extern syscall_handler_t sys_getuid;
+extern syscall_handler_t sys_getgid;
+extern syscall_handler_t sys_geteuid;
+extern syscall_handler_t sys_getegid;
+extern syscall_handler_t sys_setreuid;
+extern syscall_handler_t sys_setregid;
+extern syscall_handler_t sys_getgroups;
+extern syscall_handler_t sys_setgroups;
+extern syscall_handler_t sys_fchown;
+extern syscall_handler_t sys_setresuid;
+extern syscall_handler_t sys_getresuid;
+extern syscall_handler_t sys_setresgid;
+extern syscall_handler_t sys_getresgid;
+extern syscall_handler_t sys_chown;
+extern syscall_handler_t sys_setuid;
+extern syscall_handler_t sys_setgid;
+extern syscall_handler_t sys_setfsuid;
+extern syscall_handler_t sys_setfsgid;
+extern syscall_handler_t sys_pivot_root;
+extern syscall_handler_t sys_mincore;
+extern syscall_handler_t sys_madvise;
+extern syscall_handler_t sys_fcntl64;
+extern syscall_handler_t sys_getdents64;
+extern syscall_handler_t sys_gettid;
+extern syscall_handler_t sys_readahead;
+
+extern syscall_handler_t um_mount;
+extern syscall_handler_t um_time;
+extern syscall_handler_t um_stime;
+
+#define LAST_GENERIC_SYSCALL __NR_fremovexattr
+
+#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+#define LAST_SYSCALL LAST_GENERIC_SYSCALL
+#else
+#define LAST_SYSCALL LAST_ARCH_SYSCALL
+#endif
+
+syscall_handler_t *sys_call_table[] = {
+	[ 0 ] = sys_ni_syscall,
+	[ __NR_exit ] = sys_exit,
+	[ __NR_fork ] = sys_fork,
+	[ __NR_read ] = sys_read,
+	[ __NR_write ] = sys_write,
+
+	/* These three are declared differently in asm/unistd.h */
+	[ __NR_open ] = (syscall_handler_t *) sys_open,
+	[ __NR_close ] = (syscall_handler_t *) sys_close,
+	[ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid,
+	[ __NR_creat ] = sys_creat,
+	[ __NR_link ] = sys_link,
+	[ __NR_unlink ] = sys_unlink,
+
+	/* declared differently in kern_util.h */
+	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
+	[ __NR_chdir ] = sys_chdir,
+	[ __NR_time ] = um_time,
+	[ __NR_mknod ] = sys_mknod,
+	[ __NR_chmod ] = sys_chmod,
+	[ __NR_lchown ] = sys_lchown16,
+	[ __NR_break ] = sys_ni_syscall,
+	[ __NR_oldstat ] = sys_stat,
+	[ __NR_lseek ] = sys_lseek,
+	[ __NR_getpid ] = sys_getpid,
+	[ __NR_mount ] = um_mount,
+	[ __NR_umount ] = sys_oldumount,
+	[ __NR_setuid ] = sys_setuid16,
+	[ __NR_getuid ] = sys_getuid16,
+	[ __NR_stime ] = um_stime,
+	[ __NR_ptrace ] = sys_ptrace,
+	[ __NR_alarm ] = sys_alarm,
+	[ __NR_oldfstat ] = sys_fstat,
+	[ __NR_pause ] = sys_pause,
+	[ __NR_utime ] = sys_utime,
+	[ __NR_stty ] = sys_ni_syscall,
+	[ __NR_gtty ] = sys_ni_syscall,
+	[ __NR_access ] = sys_access,
+	[ __NR_nice ] = sys_nice,
+	[ __NR_ftime ] = sys_ni_syscall,
+	[ __NR_sync ] = sys_sync,
+	[ __NR_kill ] = sys_kill,
+	[ __NR_rename ] = sys_rename,
+	[ __NR_mkdir ] = sys_mkdir,
+	[ __NR_rmdir ] = sys_rmdir,
+
+	/* Declared differently in asm/unistd.h */
+	[ __NR_dup ] = (syscall_handler_t *) sys_dup,
+	[ __NR_pipe ] = sys_pipe,
+	[ __NR_times ] = sys_times,
+	[ __NR_prof ] = sys_ni_syscall,
+	[ __NR_brk ] = sys_brk,
+	[ __NR_setgid ] = sys_setgid16,
+	[ __NR_getgid ] = sys_getgid16,
+	[ __NR_signal ] = sys_signal,
+	[ __NR_geteuid ] = sys_geteuid16,
+	[ __NR_getegid ] = sys_getegid16,
+	[ __NR_acct ] = sys_acct,
+	[ __NR_umount2 ] = sys_umount,
+	[ __NR_lock ] = sys_ni_syscall,
+	[ __NR_ioctl ] = sys_ioctl,
+	[ __NR_fcntl ] = sys_fcntl,
+	[ __NR_mpx ] = sys_ni_syscall,
+	[ __NR_setpgid ] = sys_setpgid,
+	[ __NR_ulimit ] = sys_ni_syscall,
+	[ __NR_oldolduname ] = sys_olduname,
+	[ __NR_umask ] = sys_umask,
+	[ __NR_chroot ] = sys_chroot,
+	[ __NR_ustat ] = sys_ustat,
+	[ __NR_dup2 ] = sys_dup2,
+	[ __NR_getppid ] = sys_getppid,
+	[ __NR_getpgrp ] = sys_getpgrp,
+	[ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
+	[ __NR_sigaction ] = sys_sigaction,
+	[ __NR_sgetmask ] = sys_sgetmask,
+	[ __NR_ssetmask ] = sys_ssetmask,
+	[ __NR_setreuid ] = sys_setreuid16,
+	[ __NR_setregid ] = sys_setregid16,
+	[ __NR_sigsuspend ] = sys_sigsuspend,
+	[ __NR_sigpending ] = sys_sigpending,
+	[ __NR_sethostname ] = sys_sethostname,
+	[ __NR_setrlimit ] = sys_setrlimit,
+	[ __NR_getrlimit ] = sys_old_getrlimit,
+	[ __NR_getrusage ] = sys_getrusage,
+	[ __NR_gettimeofday ] = sys_gettimeofday,
+	[ __NR_settimeofday ] = sys_settimeofday,
+	[ __NR_getgroups ] = sys_getgroups16,
+	[ __NR_setgroups ] = sys_setgroups16,
+	[ __NR_symlink ] = sys_symlink,
+	[ __NR_oldlstat ] = sys_lstat,
+	[ __NR_readlink ] = sys_readlink,
+	[ __NR_uselib ] = sys_uselib,
+	[ __NR_swapon ] = sys_swapon,
+	[ __NR_reboot ] = sys_reboot,
+	[ __NR_readdir ] = old_readdir,
+	[ __NR_munmap ] = sys_munmap,
+	[ __NR_truncate ] = sys_truncate,
+	[ __NR_ftruncate ] = sys_ftruncate,
+	[ __NR_fchmod ] = sys_fchmod,
+	[ __NR_fchown ] = sys_fchown16,
+	[ __NR_getpriority ] = sys_getpriority,
+	[ __NR_setpriority ] = sys_setpriority,
+	[ __NR_profil ] = sys_ni_syscall,
+	[ __NR_statfs ] = sys_statfs,
+	[ __NR_fstatfs ] = sys_fstatfs,
+	[ __NR_ioperm ] = sys_ni_syscall,
+	[ __NR_socketcall ] = sys_socketcall,
+	[ __NR_syslog ] = sys_syslog,
+	[ __NR_setitimer ] = sys_setitimer,
+	[ __NR_getitimer ] = sys_getitimer,
+	[ __NR_stat ] = sys_newstat,
+	[ __NR_lstat ] = sys_newlstat,
+	[ __NR_fstat ] = sys_newfstat,
+	[ __NR_olduname ] = sys_uname,
+	[ __NR_iopl ] = sys_ni_syscall,
+	[ __NR_vhangup ] = sys_vhangup,
+	[ __NR_idle ] = sys_ni_syscall,
+	[ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
+	[ __NR_swapoff ] = sys_swapoff,
+	[ __NR_sysinfo ] = sys_sysinfo,
+	[ __NR_ipc ] = sys_ipc,
+	[ __NR_fsync ] = sys_fsync,
+	[ __NR_sigreturn ] = sys_sigreturn,
+	[ __NR_clone ] = sys_clone,
+	[ __NR_setdomainname ] = sys_setdomainname,
+	[ __NR_uname ] = sys_newuname,
+	[ __NR_adjtimex ] = sys_adjtimex,
+	[ __NR_mprotect ] = sys_mprotect,
+	[ __NR_sigprocmask ] = sys_sigprocmask,
+	[ __NR_create_module ] = sys_create_module,
+	[ __NR_init_module ] = sys_init_module,
+	[ __NR_delete_module ] = sys_delete_module,
+	[ __NR_get_kernel_syms ] = sys_get_kernel_syms,
+	[ __NR_quotactl ] = sys_quotactl,
+	[ __NR_getpgid ] = sys_getpgid,
+	[ __NR_fchdir ] = sys_fchdir,
+	[ __NR_bdflush ] = sys_bdflush,
+	[ __NR_sysfs ] = sys_sysfs,
+	[ __NR_personality ] = sys_personality,
+	[ __NR_afs_syscall ] = sys_ni_syscall,
+	[ __NR_setfsuid ] = sys_setfsuid16,
+	[ __NR_setfsgid ] = sys_setfsgid16,
+	[ __NR__llseek ] = sys_llseek,
+	[ __NR_getdents ] = sys_getdents,
+	[ __NR__newselect ] = (syscall_handler_t *) sys_select,
+	[ __NR_flock ] = sys_flock,
+	[ __NR_msync ] = sys_msync,
+	[ __NR_readv ] = sys_readv,
+	[ __NR_writev ] = sys_writev,
+	[ __NR_getsid ] = sys_getsid,
+	[ __NR_fdatasync ] = sys_fdatasync,
+	[ __NR__sysctl ] = sys_sysctl,
+	[ __NR_mlock ] = sys_mlock,
+	[ __NR_munlock ] = sys_munlock,
+	[ __NR_mlockall ] = sys_mlockall,
+	[ __NR_munlockall ] = sys_munlockall,
+	[ __NR_sched_setparam ] = sys_sched_setparam,
+	[ __NR_sched_getparam ] = sys_sched_getparam,
+	[ __NR_sched_setscheduler ] = sys_sched_setscheduler,
+	[ __NR_sched_getscheduler ] = sys_sched_getscheduler,
+	[ __NR_sched_yield ] = sys_sched_yield,
+	[ __NR_sched_get_priority_max ] = sys_sched_get_priority_max,
+	[ __NR_sched_get_priority_min ] = sys_sched_get_priority_min,
+	[ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval,
+	[ __NR_nanosleep ] = sys_nanosleep,
+	[ __NR_mremap ] = sys_mremap,
+	[ __NR_setresuid ] = sys_setresuid16,
+	[ __NR_getresuid ] = sys_getresuid16,
+	[ __NR_vm86 ] = sys_ni_syscall,
+	[ __NR_query_module ] = sys_query_module,
+	[ __NR_poll ] = sys_poll,
+	[ __NR_nfsservctl ] = sys_nfsservctl,
+	[ __NR_setresgid ] = sys_setresgid16,
+	[ __NR_getresgid ] = sys_getresgid16,
+	[ __NR_prctl ] = sys_prctl,
+	[ __NR_rt_sigreturn ] = sys_ni_syscall,
+	[ __NR_rt_sigaction ] = sys_rt_sigaction,
+	[ __NR_rt_sigprocmask ] = sys_rt_sigprocmask,
+	[ __NR_rt_sigpending ] = sys_rt_sigpending,
+	[ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait,
+	[ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo,
+	[ __NR_rt_sigsuspend ] = sys_rt_sigsuspend,
+	[ __NR_pread ] = sys_pread,
+	[ __NR_pwrite ] = sys_pwrite,
+	[ __NR_chown ] = sys_chown16,
+	[ __NR_getcwd ] = sys_getcwd,
+	[ __NR_capget ] = sys_capget,
+	[ __NR_capset ] = sys_capset,
+	[ __NR_sigaltstack ] = sys_sigaltstack,
+	[ __NR_sendfile ] = sys_sendfile,
+	[ __NR_getpmsg ] = sys_ni_syscall,
+	[ __NR_putpmsg ] = sys_ni_syscall,
+	[ __NR_vfork ] = sys_vfork,
+	[ __NR_ugetrlimit ] = sys_getrlimit,
+	[ __NR_mmap2 ] = sys_mmap2,
+	[ __NR_truncate64 ] = sys_truncate64,
+	[ __NR_ftruncate64 ] = sys_ftruncate64,
+	[ __NR_stat64 ] = sys_stat64,
+	[ __NR_lstat64 ] = sys_lstat64,
+	[ __NR_fstat64 ] = sys_fstat64,
+	[ __NR_fcntl64 ] = sys_fcntl64,
+	[ __NR_getdents64 ] = sys_getdents64,
+        [ __NR_security ] = sys_ni_syscall,
+	[ __NR_gettid ] = sys_gettid,
+	[ __NR_readahead ] = sys_readahead,
+	[ __NR_setxattr ] = sys_ni_syscall,
+	[ __NR_lsetxattr ] = sys_ni_syscall,
+	[ __NR_fsetxattr ] = sys_ni_syscall,
+	[ __NR_getxattr ] = sys_ni_syscall,
+	[ __NR_lgetxattr ] = sys_ni_syscall,
+	[ __NR_fgetxattr ] = sys_ni_syscall,
+	[ __NR_listxattr ] = sys_ni_syscall,
+	[ __NR_llistxattr ] = sys_ni_syscall,
+	[ __NR_flistxattr ] = sys_ni_syscall,
+	[ __NR_removexattr ] = sys_ni_syscall,
+	[ __NR_lremovexattr ] = sys_ni_syscall,
+	[ __NR_fremovexattr ] = sys_ni_syscall,
+
+	ARCH_SYSCALLS
+	[ LAST_SYSCALL + 1 ... NR_syscalls ] = 
+	        (syscall_handler_t *) sys_ni_syscall
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/syscall_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/syscall_kern.c
--- linux/arch/um/kernel/syscall_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/syscall_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,439 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/file.h"
+#include "linux/smp_lock.h"
+#include "linux/mm.h"
+#include "linux/utsname.h"
+#include "linux/msg.h"
+#include "linux/shm.h"
+#include "linux/sys.h"
+#include "linux/unistd.h"
+#include "linux/slab.h"
+#include "linux/utime.h"
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/ipc.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "sysdep/syscalls.h"
+
+long um_mount(char * dev_name, char * dir_name, char * type,
+	      unsigned long new_flags, void * data)
+{
+	if(type == NULL) type = "";
+	return(sys_mount(dev_name, dir_name, type, new_flags, data));
+}
+
+long sys_fork(void)
+{
+	long ret;
+
+	current->thread.forking = 1;
+        ret = do_fork(SIGCHLD, 0, NULL, 0);
+	current->thread.forking = 0;
+	return(ret);
+}
+
+long sys_clone(unsigned long clone_flags, unsigned long newsp)
+{
+	long ret;
+
+	current->thread.forking = 1;
+	ret = do_fork(clone_flags, newsp, NULL, 0);
+	current->thread.forking = 0;
+	return(ret);
+}
+
+long sys_vfork(void)
+{
+	long ret;
+
+	current->thread.forking = 1;
+	ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0);
+	current->thread.forking = 0;
+	return(ret);
+}
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+	unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+ out:
+	return error;
+}
+
+long sys_mmap2(unsigned long addr, unsigned long len,
+	       unsigned long prot, unsigned long flags,
+	       unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+int old_mmap(unsigned long addr, unsigned long len,
+	     unsigned long prot, unsigned long flags,
+	     unsigned long fd, unsigned long offset)
+{
+	int err = -EINVAL;
+	if (offset & ~PAGE_MASK)
+		goto out;
+
+	err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+ out:
+	return err;
+}
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+int sys_pipe(unsigned long * fildes)
+{
+        int fd[2];
+        int error;
+
+        error = do_pipe(fd);
+        if (!error) {
+                if (copy_to_user(fildes, fd, 2*sizeof(int)))
+                        error = -EFAULT;
+        }
+        return error;
+}
+
+int sys_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
+}
+
+int sys_sigaction(int sig, const struct old_sigaction *act,
+			 struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+int sys_ipc (uint call, int first, int second,
+	     int third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	case SEMOP:
+		return sys_semop (first, (struct sembuf *)ptr, second);
+	case SEMGET:
+		return sys_semget (first, second, third);
+	case SEMCTL: {
+		union semun fourth;
+		if (!ptr)
+			return -EINVAL;
+		if (get_user(fourth.__pad, (void **) ptr))
+			return -EFAULT;
+		return sys_semctl (first, second, third, fourth);
+	}
+
+	case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+				   second, third);
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+			if (!ptr)
+				return -EINVAL;
+			
+			if (copy_from_user(&tmp,
+					   (struct ipc_kludge *) ptr, 
+					   sizeof (tmp)))
+				return -EFAULT;
+			return sys_msgrcv (first, tmp.msgp, second,
+					   tmp.msgtyp, third);
+		}
+		default:
+		        panic("msgrcv with version != 0");
+			return sys_msgrcv (first,
+					   (struct msgbuf *) ptr,
+					   second, fifth, third);
+		}
+	case MSGGET:
+		return sys_msgget ((key_t) first, second);
+	case MSGCTL:
+		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				return ret;
+			return put_user (raddr, (ulong *) third);
+		}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				return -EINVAL;
+			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+		}
+	case SHMDT: 
+		return sys_shmdt ((char *)ptr);
+	case SHMGET:
+		return sys_shmget (first, second, third);
+	case SHMCTL:
+		return sys_shmctl (first, second,
+				   (struct shmid_ds *) ptr);
+	default:
+		return -EINVAL;
+	}
+}
+
+int sys_uname(struct old_utsname * name)
+{
+	int err;
+	if (!name)
+		return -EFAULT;
+	down_read(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up_read(&uts_sem);
+	return err?-EFAULT:0;
+}
+
+int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+  	down_read(&uts_sem);
+	
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,
+			       __OLD_UTS_LEN);
+	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->release,&system_utsname.release,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->release+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->version,&system_utsname.version,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->version+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->machine,&system_utsname.machine,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+	
+	up_read(&uts_sem);
+	
+	error = error ? -EFAULT : 0;
+
+	return error;
+}
+
+int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
+}
+
+static inline int check_area(void *ptr, int size)
+{
+	return(verify_area(VERIFY_WRITE, ptr, size));
+}
+
+static int check_readlink(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[2], regs->regs.args[3]));
+}
+
+static int check_utime(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[2],
+			  sizeof(struct utimbuf)));
+}
+
+static int check_oldstat(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[2], 
+			  sizeof(struct __old_kernel_stat)));
+}
+
+static int check_stat(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[2], sizeof(struct stat)));
+}
+
+static int check_stat64(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[2], sizeof(struct stat64)));
+}
+
+struct bogus {
+	int kernel_ds;
+	int (*check_params)(struct pt_regs *);
+};
+
+struct bogus this_is_bogus[] = {
+	[ __NR_mknod ] = { 1, NULL },
+	[ __NR_mkdir ] = { 1, NULL },
+	[ __NR_rmdir ] = { 1, NULL },
+	[ __NR_unlink ] = { 1, NULL },
+	[ __NR_symlink ] = { 1, NULL },
+	[ __NR_link ] = { 1, NULL },
+	[ __NR_rename ] = { 1, NULL },
+	[ __NR_umount ] = { 1, NULL },
+	[ __NR_mount ] = { 1, NULL },
+	[ __NR_pivot_root ] = { 1, NULL },
+	[ __NR_chdir ] = { 1, NULL },
+	[ __NR_chroot ] = { 1, NULL },
+	[ __NR_open ] = { 1, NULL },
+	[ __NR_quotactl ] = { 1, NULL },
+	[ __NR_sysfs ] = { 1, NULL },
+	[ __NR_readlink ] = { 1, check_readlink },
+	[ __NR_acct ] = { 1, NULL },
+	[ __NR_execve ] = { 1, NULL },
+	[ __NR_uselib ] = { 1, NULL },
+	[ __NR_statfs ] = { 1, NULL },
+	[ __NR_truncate ] = { 1, NULL },
+	[ __NR_access ] = { 1, NULL },
+	[ __NR_chmod ] = { 1, NULL },
+	[ __NR_chown ] = { 1, NULL },
+	[ __NR_lchown ] = { 1, NULL },
+	[ __NR_utime ] = { 1, check_utime },
+	[ __NR_oldlstat ] = { 1, check_oldstat },
+	[ __NR_oldstat ] = { 1, check_oldstat },
+	[ __NR_stat ] = { 1, check_stat },
+	[ __NR_lstat ] = { 1, check_stat },
+	[ __NR_stat64 ] = { 1, check_stat64 },
+	[ __NR_lstat64 ] = { 1, check_stat64 },
+};
+
+/* sys_utimes */
+
+static int check_bogosity(struct pt_regs *regs)
+{
+	struct bogus *bogon = &this_is_bogus[regs->regs.syscall];
+
+	if(!bogon->kernel_ds) return(0);
+	if(bogon->check_params && (*bogon->check_params)(regs))
+		return(-EFAULT);
+	set_fs(KERNEL_DS);
+	return(0);
+}
+
+int nsyscalls = 0;
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall(void *r)
+{
+	struct pt_regs *regs = r;
+	long res;
+	int syscall;
+
+	current->thread.nsyscalls++;
+	nsyscalls++;
+	syscall = regs->regs.syscall;
+
+	if((syscall >= NR_syscalls) || (syscall < 0))
+		res = -ENOSYS;
+	else if(honeypot && check_bogosity(regs))
+		res = -EFAULT;
+	else res = EXECUTE_SYSCALL(syscall, regs);
+
+	set_fs(USER_DS);
+
+	return(res);
+}
+
+spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_syscall(void)
+{
+	spin_lock(&syscall_lock);
+}
+
+void unlock_syscall(void)
+{
+	spin_unlock(&syscall_lock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/syscall_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/syscall_user.c
--- linux/arch/um/kernel/syscall_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/syscall_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,136 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately
+ * after setting up syscall stack
+ * block SIGVTALRM in any code that's under wait_for_stop
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "frame.h"
+#include "sigcontext.h"
+#include "sysdep/ptrace.h"
+#include "ptrace_user.h"
+#include "task.h"
+
+/* XXX Bogus */
+#define ERESTARTSYS	512
+#define ERESTARTNOINTR	513
+#define ERESTARTNOHAND	514
+
+struct {
+	int syscall;
+	int pid;
+	int result;
+	struct timeval start;
+	struct timeval end;
+} syscall_record[1024];
+
+int syscall_index = 0;
+
+extern int timer_ready, timer_on;
+
+void syscall_handler(int sig, struct sigcontext sc)
+{
+	struct uml_pt_regs *regs;
+	long result;
+	int index, syscall;
+
+	unprotect_kernel_mem(1);
+	timer_ready = 1;
+
+	change_sig(SIGUSR1, 1);
+	unblock_signals();
+
+	lock_syscall();
+	if(syscall_index == 1024) syscall_index = 0;
+	index = syscall_index;
+	syscall_index++;
+	unlock_syscall();
+
+	regs = (struct uml_pt_regs *) TASK_REGS(get_current());
+	syscall = regs->syscall;
+	regs->sc = &sc;
+	sc_to_regs(regs, &sc, syscall);
+	SC_START_SYSCALL(&sc);
+
+	syscall_record[index].syscall = syscall;
+	syscall_record[index].pid = current_pid();
+	syscall_record[index].result = 0xdeadbeef;
+	gettimeofday(&syscall_record[index].start, NULL);
+	syscall_trace();
+	result = execute_syscall(regs);
+	SC_SET_SYSCALL_RETURN(&sc, result);
+	if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || 
+	   (result == -ERESTARTNOINTR))
+		do_signal(result);
+	syscall_trace();
+	syscall_record[index].result = result;
+	gettimeofday(&syscall_record[index].end, NULL);
+	ret_from_sys_call();
+
+	block_signals();
+	change_sig(SIGUSR1, 0);
+
+	timer_ready = 0;
+	set_user_mode(NULL, 1);
+	timer_on = 1;
+}
+
+int do_syscall(void *task, int pid)
+{
+	unsigned long proc_regs[FRAME_SIZE];
+	struct uml_pt_regs *regs;
+	int syscall;
+
+	if(ptrace_getregs(pid, proc_regs) < 0)
+		tracer_panic("Couldn't read registers");
+	syscall = PT_SYSCALL_NR(proc_regs);
+
+	regs = TASK_REGS(task);
+	UPT_SYSCALL_NR(regs) = syscall;
+
+	if(syscall < 1) return(0);
+
+	if((syscall != __NR_sigreturn) &&
+	   ((unsigned long *) PT_IP(proc_regs) >= &_stext) && 
+	   ((unsigned long *) PT_IP(proc_regs) <= &_etext))
+		tracer_panic("I'm tracing myself and I can't get out");
+
+	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+		  __NR_getpid) < 0)
+		tracer_panic("do_syscall : Nullifying syscall failed, "
+			     "errno = %d", errno);
+	return(1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/sysrq.c linux-2.4.19-pre5-mjc/arch/um/kernel/sysrq.c
--- linux/arch/um/kernel/sysrq.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/sysrq.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,98 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/kernel.h"
+#include "linux/module.h"
+#include "asm/page.h"
+#include "asm/processor.h"
+#include "sysrq.h"
+#include "user_util.h"
+
+ /*
+  * If the address is either in the .text section of the
+  * kernel, or in the vmalloc'ed module regions, it *may* 
+  * be the address of a calling routine
+  */
+ 
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	return (addr >= (unsigned long) &_stext &&
+		addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+void show_trace(unsigned long * stack)
+{
+        int i;
+        unsigned long addr;
+
+        if (!stack)
+                stack = (unsigned long*) &stack;
+
+        printk("Call Trace: ");
+        i = 1;
+        while (((long) stack & (THREAD_SIZE-1)) != 0) {
+                addr = *stack++;
+		if (kernel_text_address(addr)) {
+			if (i && ((i % 6) == 0))
+				printk("\n   ");
+			printk("[<%08lx>] ", addr);
+			i++;
+                }
+        }
+        printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	unsigned long esp = PT_REGS_SP(&tsk->thread.regs);
+
+	/* User space on another CPU? */
+	if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+		return;
+	show_trace((unsigned long *)esp);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/time.c linux-2.4.19-pre5-mjc/arch/um/kernel/time.c
--- linux/arch/um/kernel/time.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/time.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,120 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#define _GNU_SOURCE /* to get timeradd and timersub */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_user.h"
+
+extern struct timeval xtime;
+
+void timer_handler(int sig, struct uml_pt_regs *regs)
+{
+	timer_irq(regs);
+}
+
+void timer(void)
+{
+	gettimeofday(&xtime, NULL);
+}
+
+static struct itimerval profile_interval;
+
+void get_profile_timer(void)
+{
+	getitimer(ITIMER_PROF, &profile_interval);
+	profile_interval.it_value = profile_interval.it_interval;
+}
+
+void disable_profile_timer(void)
+{
+	struct itimerval interval = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+	setitimer(ITIMER_PROF, &interval, NULL);
+}
+
+static void set_interval(int timer_type)
+{
+	struct itimerval interval;
+
+	interval.it_interval.tv_sec = 0;
+	interval.it_interval.tv_usec = 1000000/hz();
+	interval.it_value.tv_sec = 0;
+	interval.it_value.tv_usec = 1000000/hz();
+	if(setitimer(timer_type, &interval, NULL) == -1)
+		panic("setitimer failed - errno = %d\n", errno);
+}
+
+void idle_timer(void)
+{
+	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+		panic("Couldn't unset SIGVTALRM handler");
+	set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
+		    SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_interval(ITIMER_REAL);
+}
+
+void time_init(void)
+{
+	if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+void set_timers(int set_signal)
+{
+	if(set_signal){
+		if(signal(SIGVTALRM, 
+			  (__sighandler_t) alarm_handler) == SIG_ERR)
+			panic("Couldn't set SIGVTALRM handler");
+		set_interval(ITIMER_VIRTUAL);
+	}
+	if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1)
+		panic("setitimer ITIMER_PROF failed - errno = %d\n", errno);
+}
+
+struct timeval local_offset = { 0, 0 };
+
+void do_gettimeofday(struct timeval *tv)
+{
+	gettimeofday(tv, NULL);
+	timeradd(tv, &local_offset, tv);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
+	timersub(tv, &now, &local_offset);
+}
+
+void idle_sleep(int secs)
+{
+	struct timespec ts;
+
+	ts.tv_sec = secs;
+	ts.tv_nsec = 0;
+	nanosleep(&ts, &ts);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/time_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/time_kern.c
--- linux/arch/um/kernel/time_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/time_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,141 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/unistd.h"
+#include "linux/stddef.h"
+#include "linux/spinlock.h"
+#include "linux/sched.h"
+#include "linux/interrupt.h"
+#include "linux/init.h"
+#include "linux/delay.h"
+#include "asm/param.h"
+#include "asm/current.h"
+#include "kern_util.h"
+#include "user_util.h"
+
+extern rwlock_t xtime_lock;
+
+int hz(void)
+{
+	return(HZ);
+}
+
+int timer_irq_inited = 0;
+
+/* timer_on and missed_ticks are modified after kernel memory has been 
+ * write-protected, so this puts it in a section which will be left 
+ * write-enabled.
+ */
+int __attribute__ ((__section__ (".unprotected"))) timer_on = 0;
+int __attribute__ ((__section__ (".unprotected"))) missed_ticks = 0;
+
+int timer_ready = 0;
+
+void timer_irq(struct uml_pt_regs *regs)
+{
+	int ticks = missed_ticks;
+
+        if(!timer_irq_inited) return;
+	missed_ticks = 0;
+	while(ticks--) do_IRQ(TIMER_IRQ, regs);
+}
+
+void boot_timer_handler(int sig)
+{
+	struct pt_regs regs;
+
+	regs.regs.is_user = 0;
+	do_timer(&regs);
+}
+
+void um_timer(int irq, void *dev, struct pt_regs *regs)
+{
+	do_timer(regs);
+	write_lock(&xtime_lock);
+	timer();
+	write_unlock(&xtime_lock);
+}
+
+long um_time(int * tloc)
+{
+	struct timeval now;
+
+	do_gettimeofday(&now);
+	if (tloc) {
+ 		if (put_user(now.tv_sec,tloc))
+			now.tv_sec = -EFAULT;
+	}
+	return now.tv_sec;
+}
+
+long um_stime(int * tptr)
+{
+	int value;
+	struct timeval new;
+
+	if (get_user(value, tptr))
+                return -EFAULT;
+	new.tv_sec = value;
+	new.tv_usec = 0;
+	do_settimeofday(&new);
+	return 0;
+}
+
+void __delay(um_udelay_t time)
+{
+	/* Stolen from the i386 __loop_delay */
+	int d0;
+	__asm__ __volatile__(
+		"\tjmp 1f\n"
+		".align 16\n"
+		"1:\tjmp 2f\n"
+		".align 16\n"
+		"2:\tdecl %0\n\tjns 2b"
+		:"=&a" (d0)
+		:"0" (time));
+}
+
+void __udelay(um_udelay_t usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / 1000000;
+	for(i=0;i<n;i++) ;
+}
+
+void __const_udelay(um_udelay_t usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / 1000000;
+	for(i=0;i<n;i++) ;
+}
+
+int __init timer_init(void)
+{
+	int err;
+
+	if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", 
+			      NULL)) != 0)
+		printk(KERN_ERR "timer_init : request_irq failed - "
+		       "errno = %d\n", -err);
+	timer_irq_inited = 1;
+	return(0);
+}
+
+__initcall(timer_init);
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/tlb.c linux-2.4.19-pre5-mjc/arch/um/kernel/tlb.c
--- linux/arch/um/kernel/tlb.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/tlb.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,247 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/bootmem.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/a.out.h"
+#include "asm/processor.h"
+#include "asm/mmu_context.h"
+#include "asm/uaccess.h"
+#include "asm/atomic.h"
+#include "mem_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "tlb.h"
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
+		      unsigned long end_addr, int force)
+{
+	pgd_t *npgd;
+	pmd_t *npmd;
+	pte_t *npte;
+	unsigned long addr;
+	int r, w, x, err;
+
+	if((current->thread.extern_pid != -1) && 
+	   (current->thread.extern_pid != getpid()))
+		panic("fix_range fixing wrong address space, current = 0x%p",
+		      current);
+	if(mm == NULL) return;
+	for(addr=start_addr;addr<end_addr;){
+		if(addr == TASK_SIZE){
+			/* Skip over kernel text, kernel data, and physical
+			 * memory, which don't have ptes, plus kernel virtual
+			 * memory, which is flushed separately, and remap
+			 * the process stack.  The only way to get here is
+			 * if (end_addr == STACK_TOP) > TASK_SIZE, which is
+			 * only true in the honeypot case.
+			 */
+			addr = STACK_TOP - ABOVE_KMEM;
+			continue;
+		}
+		npgd = pgd_offset(mm, addr);
+		npmd = pmd_offset(npgd, addr);
+		if(pmd_present(*npmd)){
+			npte = pte_offset(npmd, addr);
+			r = pte_read(*npte);
+			w = pte_write(*npte);
+			x = pte_exec(*npte);
+			if(!pte_dirty(*npte)) w = 0;
+			if(!pte_young(*npte)){
+				r = 0;
+				w = 0;
+			}
+			if(force || pte_newpage(*npte)){
+				err = unmap((void *) addr, PAGE_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+				if(pte_present(*npte))
+					map(addr, pte_address(*npte),
+					    PAGE_SIZE, r, w, x);
+			}
+			else if(pte_newprot(*npte))
+				protect(addr, PAGE_SIZE, r, w, x, 1);
+			*npte = pte_mkuptodate(*npte);
+			addr += PAGE_SIZE;
+		}
+		else {
+			if(force || pmd_newpage(*npmd)){
+				err = unmap((void *) addr, PMD_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+			}
+			addr += PMD_SIZE;
+		}
+	}
+}
+
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
+static void flush_kernel_vm_range(unsigned long start, unsigned long end,
+				  int update_seq)
+{
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	int updated = 0, err;
+
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pmd = pmd_offset(pgd, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset(pmd, addr);
+			if(!pte_present(*pte) || pte_newpage(*pte)){
+				updated = 1;
+				err = unmap((void *) addr, PAGE_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+				if(pte_present(*pte))
+					map(addr, pte_address(*pte),
+					    PAGE_SIZE, 1, 1, 1);
+			}
+			else if(pte_newprot(*pte)){
+				updated = 1;
+				protect(addr, PAGE_SIZE, 1, 1, 1, 1);
+			}
+			addr += PAGE_SIZE;
+
+		}
+		else {
+			if(pmd_newpage(*pmd)){
+				updated = 1;
+				err = unmap((void *) addr, PMD_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+			}
+			addr += PMD_SIZE;
+		}
+	}
+	if(updated && update_seq) atomic_inc(&vmchange_seq);
+}
+
+static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+{
+	int err;
+
+	err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed);
+	if(err == 0) return;
+	else if(err == -EFAULT){
+		flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1);
+		protect_vm_page(addr, w, 1);
+	}
+	else panic("protect_vm_page : protect failed, errno = %d\n", err);
+}
+
+void mprotect_kernel_vm(int w)
+{
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pmd = pmd_offset(pgd, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset(pmd, addr);
+			if(pte_present(*pte)) protect_vm_page(addr, w, 0);
+			addr += PAGE_SIZE;
+		}
+		else addr += PMD_SIZE;
+	}
+}
+
+void flush_tlb_kernel_vm(void)
+{
+	flush_kernel_vm_range(start_vm, end_vm, 1);
+}
+
+void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
+		     unsigned long end)
+{
+	if(mm != current->mm) return;
+
+	/* Assumes that the range start ... end is entirely within
+	 * either process memory or kernel vm
+	 */
+	if((start >= start_vm) && (start < end_vm)) 
+		flush_kernel_vm_range(start, end, 1);
+	else fix_range(mm, start, end, 0);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	unsigned long seq;
+
+	if(mm != current->mm) return;
+
+	fix_range(mm, 0, STACK_TOP, 0);
+
+	seq = atomic_read(&vmchange_seq);
+	if(current->thread.vm_seq == seq) return;
+	current->thread.vm_seq = seq;
+	flush_kernel_vm_range(start_vm, end_vm, 0);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+	address &= PAGE_MASK;
+	flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+	flush_tlb_mm(current->mm);
+}
+
+void force_flush_all(void)
+{
+	fix_range(current->mm, 0, STACK_TOP, 1);
+	flush_kernel_vm_range(start_vm, end_vm, 0);
+}
+
+pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
+{
+	return(pgd_offset(mm, address));
+}
+
+pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address)
+{
+	return(pmd_offset(pgd, address));
+}
+
+pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
+{
+	return(pte_offset(pmd, address));
+}
+
+pte_t *addr_pte(struct task_struct *task, unsigned long addr)
+{
+	return(pte_offset(pmd_offset(pgd_offset(task->mm, addr), addr), addr));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/trap_kern.c linux-2.4.19-pre5-mjc/arch/um/kernel/trap_kern.c
--- linux/arch/um/kernel/trap_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/trap_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,389 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/spinlock.h"
+#include "linux/config.h"
+#include "linux/init.h"
+#include "asm/semaphore.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/a.out.h"
+#include "asm/current.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "chan_kern.h"
+#include "debug.h"
+#include "mconsole_kern.h"
+#include "2_5compat.h"
+
+extern int nsyscalls;
+
+unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
+		   int is_user)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	struct siginfo si;
+	void *catcher;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long page;
+
+	if((address >= start_vm) && (address < end_vm)){
+		flush_tlb_kernel_vm();
+		return(0);
+	}
+	if(mm == NULL) panic("Segfault with no mm");
+	catcher = current->thread.fault_catcher;
+	si.si_code = SEGV_MAPERR;
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, address);
+	if(!vma) goto bad;
+	else if(vma->vm_start <= address) goto good_area;
+	else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad;
+	else if(expand_stack(vma, address)) goto bad;
+
+ good_area:
+	si.si_code = SEGV_ACCERR;
+	if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad;
+	page = address & PAGE_MASK;
+	if(page == (unsigned long) current + PAGE_SIZE)
+		panic("Kernel stack overflow");
+	pgd = pgd_offset(mm, page);
+	pmd = pmd_offset(pgd, page);
+	do {
+	survive:
+		switch (handle_mm_fault(mm, vma, address, is_write)) {
+		case 1:
+			current->min_flt++;
+			break;
+		case 2:
+			current->maj_flt++;
+			break;
+		default:
+			if (current->pid == 1) {
+				up_read(&mm->mmap_sem);
+				yield();
+				down_read(&mm->mmap_sem);
+				goto survive;
+			}
+			/* Fall through to bad area case */
+		case 0:
+			goto bad;
+		}
+		pte = pte_offset(pmd, page);
+	} while(!pte_present(*pte));
+	*pte = pte_mkyoung(*pte);
+	if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
+	flush_tlb_page(vma, page);
+	up_read(&mm->mmap_sem);
+	return(0);
+ bad:
+	if(catcher != NULL){
+		current->thread.fault_addr = (void *) address;
+		up_read(&mm->mmap_sem);
+		do_longjmp(catcher);
+	} 
+	else if(current->thread.fault_addr != NULL){
+		panic("fault_addr set but no fault catcher");
+	}
+	if(!is_user) 
+		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
+		      address, ip);
+	si.si_signo = SIGSEGV;
+	si.si_addr = (void *) address;
+	current->thread.cr2 = address;
+	current->thread.err = is_write;
+	force_sig_info(SIGSEGV, &si, current);
+	up_read(&mm->mmap_sem);
+	return(0);
+}
+
+void bad_segv(unsigned long address, unsigned long ip, int is_write)
+{
+	struct siginfo si;
+
+	printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
+	       "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
+	si.si_signo = SIGSEGV;
+	si.si_code = SEGV_ACCERR;
+	si.si_addr = (void *) address;
+	current->thread.cr2 = address;
+	current->thread.err = is_write;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+void relay_signal(int sig, struct uml_pt_regs *regs)
+{
+	if(arch_handle_signal(sig, regs)) return;
+	if(!regs->is_user) panic("Kernel mode signal %d", sig);
+	force_sig(sig, current);
+}
+
+void bus_handler(int sig, struct uml_pt_regs *regs)
+{
+	if(current->thread.fault_catcher != NULL)
+		do_longjmp(current->thread.fault_catcher);
+	else relay_signal(sig, regs);
+}
+
+void trap_init(void)
+{
+}
+
+spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_trap(void)
+{
+	spin_lock(&trap_lock);
+}
+
+void unlock_trap(void)
+{
+	spin_unlock(&trap_lock);
+}
+
+extern int debugger_pid;
+extern int debugger_fd;
+
+#ifdef CONFIG_PT_PROXY
+
+int debugger_signal(int status, pid_t pid)
+{
+	return(debugger_proxy(status, pid));
+}
+
+void child_signal(pid_t pid, int status)
+{
+	child_proxy(pid, status);
+}
+
+static void gdb_announce(char *dev_name, int dev)
+{
+	printf("gdb assigned device '%s'\n", dev_name);
+}
+
+static struct chan_opts opts = {
+	announce : 	gdb_announce,
+	xterm_title :	"UML kernel debugger",
+	raw :		0
+};
+
+static void *xterm_data;
+static int xterm_fd;
+
+extern void *xterm_init(char *, int, struct chan_opts *);
+extern int xterm_open(int, int, int, void *);
+extern void xterm_close(int, void *);
+
+int open_gdb_chan(void)
+{
+	xterm_data = xterm_init("", 0, &opts);
+	xterm_fd = xterm_open(1, 1, 1, xterm_data);
+	return(xterm_fd);
+}
+
+static void exit_debugger_cb(void *unused)
+{
+	if(debugger_pid != -1){
+		if(gdb_pid != -1){
+			fake_child_exit();
+			gdb_pid = -1;
+		}
+		else kill_child_dead(debugger_pid);
+		debugger_pid = -1;
+	}
+	if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
+}
+
+static void exit_debugger(void)
+{
+	tracing_cb(exit_debugger_cb, NULL);
+}
+
+__uml_exitcall(exit_debugger);
+
+struct gdb_data {
+	char *str;
+	int err;
+};
+
+static void config_gdb_cb(void *arg)
+{
+	struct gdb_data *data = arg;
+	struct task_struct *task;
+	int pid;
+
+	data->err = -1;
+	if(debugger_pid != -1) exit_debugger_cb(NULL);
+	if(!strncmp(data->str, "pid,", strlen("pid,"))){
+		data->str += strlen("pid,");
+		pid = simple_strtoul(data->str, NULL, 0);
+		task = cpu_tasks[0].task;
+		debugger_pid = attach_debugger(task->thread.extern_pid,
+					       pid, 0);
+		if(debugger_pid != -1){
+			data->err = 0;
+			gdb_pid = pid;
+		}
+		return;
+	}
+	data->err = 0;
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int gdb_config(char *str)
+{
+	struct gdb_data data;
+
+	if(*str++ != '=') return(-1);
+	data.str = str;
+	tracing_cb(config_gdb_cb, &data);
+	return(data.err);
+}
+
+void remove_gdb_cb(void *unused)
+{
+	exit_debugger_cb(NULL);
+}
+
+int gdb_remove(char *unused)
+{
+	tracing_cb(remove_gdb_cb, NULL);
+	return(0);
+}
+
+#ifdef CONFIG_MCONSOLE
+
+static struct mc_device gdb_mc = {
+	name:		"gdb",
+	config:		gdb_config,
+	remove:		gdb_remove,
+};
+
+int gdb_mc_init(void)
+{
+	mconsole_register_dev(&gdb_mc);
+	return(0);
+}
+
+__initcall(gdb_mc_init);
+
+#endif
+
+void signal_usr1(int sig)
+{
+	if(debugger_pid != -1){
+		printk(KERN_ERR "The debugger is already running\n");
+		return;
+	}
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	int pid, status;
+
+	pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
+	status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT);
+ 	if(pid < 0){
+		cont(idle_pid);
+		return(-1);
+	}
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	int status = 0, err;
+
+	err = attach(pid);
+	if(err < 0){
+		printf("Failed to attach pid %d, errno = %d\n", pid, -err);
+		return(-1);
+	}
+	if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT);
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+#ifdef notdef /* Put this back in when it does something useful */
+static int __init uml_gdb_init_setup(char *line, int *add)
+{
+	gdb_init = uml_strdup(line);
+	return 0;
+}
+
+__uml_setup("gdb=", uml_gdb_init_setup, 
+"gdb=<channel description>\n\n"
+);
+#endif
+
+static int __init uml_gdb_pid_setup(char *line, int *add)
+{
+	gdb_pid = simple_strtoul(line, NULL, 0);
+	*add = 0;
+	return 0;
+}
+
+__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
+"gdb-pid=<pid>\n"
+"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
+"    an already-running gdb or a debugger-like process like strace.\n\n"
+);
+
+#else
+
+int debugger_signal(int status, pid_t pid){ return(0); }
+void child_signal(pid_t pid, int status){ }
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+	wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT);
+	cont(idle_pid);
+	return(-1);
+}
+
+void signal_usr1(int sig)
+{
+	printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
+	       "is off\n");
+	return(-1);
+}
+
+int config_gdb(char *str)
+{
+	return(-1);
+}
+
+int remove_gdb(void)
+{
+	return(-1);
+}
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/trap_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/trap_user.c
--- linux/arch/um/kernel/trap_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/trap_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,531 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "signal_user.h"
+#include "mem_user.h"
+#include "user.h"
+#include "process.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "init.h"
+#include "chan_user.h"
+#include "irq_user.h"
+#include "frame.h"
+#include "syscall_user.h"
+#include "ptrace_user.h"
+#include "task.h"
+
+static void signal_segv(int sig)
+{
+	write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n"));
+	for(;;) ;
+}
+
+int detach(int pid, int sig)
+{
+	return(ptrace(PTRACE_DETACH, pid, 0, sig));
+}
+
+int attach(int pid)
+{
+	int err;
+
+	err = ptrace(PTRACE_ATTACH, pid, 0, 0);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int cont(int pid)
+{
+	return(ptrace(PTRACE_CONT, pid, 0, 0));
+}
+
+void kill_child_dead(int pid)
+{
+	kill(pid, SIGKILL);
+	kill(pid, SIGCONT);
+	while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
+}
+
+int debug = 0;
+int debug_stop = 1;
+
+int honeypot = 0;
+
+static int signal_tramp(void *arg)
+{
+	int (*proc)(void *);
+
+	if(honeypot && munmap((void *) (host_task_size - 0x10000000),
+			      0x10000000)) 
+		panic("Unmapping stack failed");
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+		panic("ptrace PTRACE_TRACEME failed");
+	kill(getpid(), SIGSTOP);
+	signal(SIGUSR1, SIG_IGN);
+	signal(SIGSEGV, (__sighandler_t) sig_handler);
+	set_timers(0);
+	set_cmdline("(idle thread)");
+	set_init_pid(getpid());
+	proc = arg;
+	return((*proc)(NULL));
+}
+
+static void last_ditch_exit(int sig)
+{
+	signal(SIGINT, SIG_DFL);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGHUP, SIG_DFL);
+	uml_cleanup();
+	exit(1);
+}
+
+static void sleeping_process_signal(int pid, int sig)
+{
+	switch(sig){
+	/* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
+	 * right because the process must be in the kernel already.
+	 */
+	case SIGCONT:
+	case SIGTSTP:
+		if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "continue pid %d, errno = %d\n", pid,
+				     sig);
+		break;
+
+	/* This happens when the debugger (e.g. strace) is doing system call 
+	 * tracing on the kernel.  During a context switch, the current task
+	 * will be set to the incoming process and the outgoing process will
+	 * hop into write and then read.  Since it's not the current process
+	 * any more, the trace of those will land here.  So, we need to just 
+	 * PTRACE_SYSCALL it.
+	 */
+	case SIGTRAP:
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "PTRACE_SYSCALL pid %d, errno = %d\n",
+				     pid, sig);
+		break;
+	default:
+		tracer_panic("sleeping process %d got unexpected "
+			     "signal : %d\n", pid, sig);
+		break;
+	}
+}
+
+
+#ifdef CONFIG_SMP
+#error need to make these arrays
+#endif
+
+int debugger_pid = -1;
+int debugger_fd = -1;
+int gdb_pid = -1;
+
+struct {
+	unsigned long address;
+	int is_write;
+	int pid;
+	unsigned long sp;
+	int is_user;
+} segfault_record[1024];
+
+int segfault_index = 0;
+
+struct {
+	int pid;
+	int signal;
+	unsigned long addr;
+	struct timeval time;
+} signal_record[1024];
+
+int signal_index = 0;
+int nsignals = 0;
+int debug_trace = 0;
+extern int io_nsignals, io_count, intr_count;
+
+extern void signal_usr1(int sig);
+
+int tracing_pid = -1;
+
+int signals(int (*init_proc)(void *), void *sp)
+{
+	void *task = NULL;
+	unsigned long eip = 0;
+	int status, pid = 0, sig, cont_type, tracing = 0, op = 0;
+	int last_index, proc_id, n, strace = 0;
+
+	capture_signal_stack();
+	signal(SIGPIPE, SIG_IGN);
+	setup_tracer_winch();
+	tracing_pid = getpid();
+	printk("tracing thread pid = %d\n", tracing_pid);
+
+	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("waitpid on idle thread failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
+		printf("Failed to continue idle thread, errno = %d\n", errno);
+		exit(1);
+	}
+
+	signal(SIGSEGV, signal_segv);
+	signal(SIGUSR1, signal_usr1);
+	set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	if(debug){
+		if(gdb_pid != -1) 
+			debugger_pid = attach_debugger(pid, gdb_pid, 1);
+		else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
+	}
+	set_cmdline("(tracing thread)");
+	if(debug_trace){
+		printk("Tracing thread pausing to be attached\n");
+		stop();
+	}
+	while(1){
+		if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
+			if(errno != ECHILD){
+				printk("wait failed - errno = %d\n", errno);
+			}
+			continue;
+		}
+		if(pid == debugger_pid){
+			int cont = 0;
+
+			if(WIFEXITED(status) || WIFSIGNALED(status))
+				debugger_pid = -1;
+			/* XXX Figure out how to deal with gdb and SMP */
+			else cont = debugger_signal(status, cpu_tasks[0].pid);
+			if(cont == PTRACE_SYSCALL) strace = 1;
+			continue;
+		}
+		nsignals++;
+		if(WIFEXITED(status)) ;
+#ifdef notdef
+		{
+			printk("Child %d exited with status %d\n", pid, 
+			       WEXITSTATUS(status));
+		}
+#endif
+		else if(WIFSIGNALED(status)){
+			sig = WTERMSIG(status);
+			if(sig != 9){
+				printk("Child %d exited with signal %d\n", pid,
+				       sig);
+			}
+		}
+		else if(WIFSTOPPED(status)){
+			sig = WSTOPSIG(status);
+			if(signal_index == 1024){
+				signal_index = 0;
+				last_index = 1023;
+			}
+			else last_index = signal_index - 1;
+			if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
+			    (sig == SIGALRM)) &&
+			   (signal_record[last_index].signal == sig) &&
+			   (signal_record[last_index].pid == pid))
+				signal_index = last_index;
+			signal_record[signal_index].pid = pid;
+			gettimeofday(&signal_record[signal_index].time, NULL);
+			eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+			signal_record[signal_index].addr = eip;
+			signal_record[signal_index++].signal = sig;
+			
+			proc_id = pid_to_processor_id(pid);
+			if(proc_id == -1){
+				sleeping_process_signal(pid, sig);
+				continue;
+			}
+
+			task = cpu_tasks[proc_id].task;
+			tracing = is_tracing(task);
+
+			switch(sig){
+			case SIGUSR1:
+				sig = 0;
+				op = do_proc_op(task, proc_id);
+				switch(op){
+				case OP_TRACE_ON:
+					tracing = 1;
+					break;
+				case OP_REBOOT:
+				case OP_HALT:
+					kmalloc_ok = 0;
+					ptrace(PTRACE_KILL, pid, 0, 0);
+					return(op == OP_REBOOT);
+				case OP_NONE:
+					printk("Detaching pid %d\n", pid);
+					detach(pid, SIGSTOP);
+					continue;
+				default:
+					break;
+				}
+				/* OP_EXEC switches host processes on us,
+				 * we want to continue the new one.
+				 */
+				pid = cpu_tasks[proc_id].pid;
+				break;
+			case SIGTRAP:
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status);
+					continue;
+				}
+				tracing = 0;
+				if(do_syscall(task, pid)) sig = SIGUSR2;
+				break;
+			case SIGPROF:
+				if(tracing) sig = 0;
+				break;
+			case SIGCHLD:
+			case SIGHUP:
+				sig = 0;
+				break;
+			case SIGSEGV:
+			case SIGIO:
+			case SIGALRM:
+			case SIGVTALRM:
+			case SIGFPE:
+			case SIGBUS:
+			case SIGILL:
+			case SIGWINCH:
+			default:
+				tracing = 0;
+				break;
+			}
+			set_tracing(task, tracing);
+
+			if(!tracing && (debugger_pid != -1) && (sig != 0) &&
+				(sig != SIGALRM) && (sig != SIGVTALRM) &&
+				(sig != SIGSEGV) && (sig != SIGTRAP) &&
+				(sig != SIGUSR2) && (sig != SIGIO)){
+				child_signal(pid, status);
+				continue;
+			}
+
+			if(tracing){
+				if(singlestepping(task))
+					cont_type = PTRACE_SINGLESTEP;
+				else cont_type = PTRACE_SYSCALL;
+			}
+			else cont_type = PTRACE_CONT;
+
+			if((cont_type == PTRACE_CONT) && 
+			   (debugger_pid != -1) && strace)
+				cont_type = PTRACE_SYSCALL;
+
+			if(ptrace(cont_type, pid, 0, sig) != 0){
+				tracer_panic("ptrace failed to continue "
+					     "process - errno = %d\n", 
+					     errno);
+			}
+		}
+	}
+	return(0);
+}
+
+static int __init uml_debugtrace_setup(char *line, int *add)
+{
+	debug_trace = 1;
+	return 0;
+}
+__uml_setup("debugtrace=", uml_debugtrace_setup,
+"debugtrace\n"
+"    Causes the tracing thread to pause until it is attached by a\n"
+"    debugger and continued.  This is mostly for debugging crashes\n"
+"    early during boot, and should be pretty much obsoleted by\n"
+"    the debug switch.\n\n"
+);
+
+static int __init uml_honeypot_setup(char *line, int *add)
+{
+	jail_setup("", add);
+	honeypot = 1;
+	return 0;
+}
+__uml_setup("honeypot", uml_honeypot_setup, 
+"honeypot\n"
+"    This makes UML put process stacks in the same location as they are\n"
+"    on the host, allowing expoits such as stack smashes to work against\n"
+"    UML.  This implies 'jail'.\n\n"
+);
+
+int nsegfaults = 0;
+
+void segv_handler(int sig, struct uml_pt_regs *regs)
+{
+	struct sigcontext_struct *context = regs->sc;
+	int index;
+
+	if(regs->is_user && !SEGV_IS_FIXABLE(context)){
+		bad_segv(SC_FAULT_ADDR(context), SC_IP(context), 
+			 SC_FAULT_WRITE(context));
+		return;
+	}
+	lock_trap();
+	index = segfault_index++;
+	if(segfault_index == 1024) segfault_index = 0;
+	unlock_trap();
+	nsegfaults++;
+	segfault_record[index].address = SC_FAULT_ADDR(context);
+	segfault_record[index].pid = getpid();
+	segfault_record[index].is_write = SC_FAULT_WRITE(context);
+	segfault_record[index].sp = SC_SP(context);
+	segfault_record[index].is_user = regs->is_user;
+	segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context),
+	     regs->is_user);
+}
+
+extern int timer_ready, timer_on;
+
+static void (*handlers[])(int, struct uml_pt_regs *) = {
+	[ SIGTRAP ] relay_signal,
+	[ SIGFPE ] relay_signal,
+	[ SIGILL ] relay_signal,
+	[ SIGBUS ] bus_handler,
+	[ SIGSEGV] segv_handler,
+	[ SIGIO ] sigio_handler,
+	[ SIGVTALRM ] timer_handler,
+	[ SIGALRM ] timer_handler,
+};
+
+void irq_handler_common(int sig, struct sigcontext *sc)
+{
+	struct uml_pt_regs save_regs, *r;
+	int save_errno = errno, save_timer = timer_on, save_user;
+
+	unprotect_kernel_mem(0);
+	timer_on = 0;
+	r = (struct uml_pt_regs *) TASK_REGS(get_current());
+	save_regs = *r;
+	r->is_user = user_context(SC_SP(sc));
+	r->syscall = -1;
+	r->sc = sc;
+	save_user = r->is_user;
+	if(save_user) timer_ready = 1;
+	change_sig(SIGUSR1, 1);
+	(*handlers[sig])(sig, r);
+	if(save_user){
+		interrupt_end();
+		block_signals();
+		change_sig(SIGUSR1, 0);
+		set_user_mode(NULL, 0);
+	}
+	if(save_user) timer_ready = 0;
+	*r = save_regs;
+	errno = save_errno;
+	timer_on = save_timer;
+	if(save_user) protect_kernel_mem(0);
+}
+
+void irq_handler(int sig, struct sigcontext sc)
+{
+	irq_handler_common(sig, &sc);
+}
+
+void sig_handler(int sig, struct sigcontext sc)
+{
+	struct uml_pt_regs save_regs, *r;
+	int save_errno = errno, save_timer = timer_on, save_user;
+
+	unprotect_kernel_mem(0);
+	timer_on = 0;
+	r = (struct uml_pt_regs *) TASK_REGS(get_current());
+	save_regs = *r;
+	r->is_user = user_context(SC_SP(&sc));
+	r->syscall = -1;
+	r->sc = &sc;
+	save_user = r->is_user;
+	if(save_user) timer_ready = 1;
+	change_sig(SIGUSR1, 1);
+	unblock_signals();
+	(*handlers[sig])(sig, r);
+	if(save_user){
+		interrupt_end();
+		block_signals();
+		change_sig(SIGUSR1, 0);
+		set_user_mode(NULL, 0);
+	}
+	if(save_user) timer_ready = 0;
+	*r = save_regs;
+	errno = save_errno;
+	timer_on = save_timer;
+	if(save_user) protect_kernel_mem(0);
+}
+
+extern int timer_irq_inited, missed_ticks;
+
+void alarm_handler(int sig, struct sigcontext sc)
+{
+	int user;
+
+	if(!timer_irq_inited) return;
+	missed_ticks++;
+	user = user_context(SC_SP(&sc));
+	if(!user && !timer_ready) return;
+	if(!timer_on) return;
+	irq_handler_common(sig, &sc);
+	timer_ready = 1;
+}
+
+void do_longjmp(void *p)
+{
+    jmp_buf *jbuf = (jmp_buf *) p;
+
+    longjmp(*jbuf, 1);
+}
+
+static int __init uml_debug_setup(char *line, int *add)
+{
+	debug = 1;
+	if(!strcmp(line, "=go")){
+		debug_stop = 0;
+		*add = 0;
+	}
+	return 0;
+}
+
+__uml_setup("debug", uml_debug_setup,
+"debug\n"
+"    Starts up the kernel under the control of gdb. See the \n"
+"    kernel debugging tutorial and the debugging session pages\n"
+"    at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/uaccess_user.c linux-2.4.19-pre5-mjc/arch/um/kernel/uaccess_user.c
--- linux/arch/um/kernel/uaccess_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/uaccess_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,126 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <setjmp.h>
+#include <string.h>
+#include "user_util.h"
+
+static unsigned long __do_user_copy(void *to, const void *from, int n,
+				    void **fault_addr, void **fault_catcher,
+				    void (*op)(void *to, const void *from,
+					       int n), int *faulted_out)
+{
+	unsigned long *faddrp = (unsigned long *) fault_addr, ret;
+
+	jmp_buf jbuf;
+	*fault_catcher = &jbuf;
+	if(setjmp(jbuf) == 0){
+		(*op)(to, from, n);
+		ret = 0;
+		*faulted_out = 0;
+	} 
+	else {
+		ret = *faddrp;
+		*faulted_out = 1;
+	}
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+	return ret;
+}
+
+static void __do_copy(void *to, const void *from, int n)
+{
+	memcpy(to, from, n);
+}	
+
+int __do_copy_from_user(void *to, const void *from, int n,
+			void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) from));
+}
+
+
+int __do_copy_to_user(void *to, const void *from, int n,
+		      void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) to));
+}
+
+static void __do_strncpy(void *dst, const void *src, int count)
+{
+	strncpy(dst, src, count);
+}	
+
+int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
+			   void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+			       __do_strncpy, &faulted);
+	if(!faulted) return(strlen(dst));
+	else return(-1);
+}
+
+static void __do_clear(void *to, const void *from, int n)
+{
+	memset(to, 0, n);
+}	
+
+int __do_clear_user(void *mem, unsigned long len,
+		    void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+			       __do_clear, &faulted);
+	if(!faulted) return(0);
+	else return(len - (fault - (unsigned long) mem));
+}
+
+int __do_strnlen_user(const char *str, unsigned long n,
+		      void **fault_addr, void **fault_catcher)
+{
+	int ret;
+	unsigned long *faddrp = (unsigned long *)fault_addr;
+	jmp_buf jbuf;
+
+	*fault_catcher = &jbuf;
+	if(setjmp(jbuf) == 0){
+		ret = strlen(str) + 1;
+	} 
+	else {
+		ret = *faddrp - (unsigned long) str;
+	}
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+	return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/um_arch.c linux-2.4.19-pre5-mjc/arch/um/kernel/um_arch.c
--- linux/arch/um/kernel/um_arch.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/um_arch.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,377 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/types.h"
+#include "linux/tty.h"
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/spinlock.h"
+#include "linux/utsname.h"
+#include <linux/seq_file.h>
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/ptrace.h"
+#include "asm/elf.h"
+#include "asm/user.h"
+#include "asm/delay.h"
+#include "ubd_user.h"
+#include "asm/current.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mprot.h"
+#include "mem_user.h"
+#include "umid.h"
+#include "initrd.h"
+#include "init.h"
+
+#define DEFAULT_COMMAND_LINE "root=/dev/ubd0"
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+	return(0);
+}
+
+unsigned long thread_saved_pc(struct thread_struct *thread)
+{
+	panic("Someone should implement thread_saved_pc");
+	return(0);
+}
+
+/*
+ * get_cpuinfo - Get information on one CPU for use by procfs.
+ *
+ *	Prints info on the next CPU into buffer.  Beware, doesn't check for
+ *	buffer overflow.  Current implementation of procfs assumes that the
+ *	resulting data is <= 1K.
+ *
+ * Args:
+ *	buffer	-- you guessed it, the data buffer
+ *	cpu_np	-- Input: next cpu to get (start at 0).  Output: Updated.
+ *
+ *	Returns number of bytes written to buffer.
+ */
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	int index;
+
+	index = (struct cpuinfo_um *)v - cpu_data;
+#ifdef CONFIG_SMP
+	if (!(cpu_online_map & (1 << index)))
+		return 0;
+#endif
+
+	seq_printf(m, "processor\t: user-mode\n");
+	seq_printf(m, "bogomips\t: %lu.%02lu\n",
+		   loops_per_jiffy/(500000/HZ),
+		   (loops_per_jiffy/(5000/HZ)) % 100);
+	seq_printf(m, "host\t\t: %s\n", host_info);
+
+	return(0);
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
+
+pte_t * __bad_pagetable(void)
+{
+	panic("Someone should implement __bad_pagetable");
+	return(NULL);
+}
+
+extern void start_kernel(void);
+
+extern int debug;
+extern int debug_stop;
+
+static int start_kernel_proc(void *unused)
+{
+	int pid;
+
+	block_signals();
+	pid = getpid();
+
+	cpu_tasks[0].pid = pid;
+	cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ 	cpu_online_map = 1;
+#endif
+	if(debug) stop_pid(pid);
+	start_kernel();
+	return(0);
+}
+
+extern unsigned long high_physmem;
+
+#ifdef CONFIG_HOST_2G_2G
+#define START 0x60000000
+#else
+#define START 0xa0000000
+#endif
+
+unsigned long host_task_size;
+unsigned long task_size;
+
+void set_task_sizes(int arg)
+{
+	/* Round up to the nearest 4M */
+	host_task_size = ROUND_4M((unsigned long) &arg);
+	task_size = START;
+}
+
+unsigned long uml_physmem;
+
+unsigned long start_vm;
+unsigned long end_vm;
+
+int ncpus = 1;
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+static char *argv1_begin = NULL;
+static char *argv1_end = NULL;
+
+static int have_root __initdata = 0;
+long physmem_size = 32 * 1024 * 1024;
+
+void set_cmdline(char *cmd)
+{
+	if(honeypot) return;
+	strcpy(argv1_begin, "[");
+	strncat(argv1_begin, cmd, argv1_end - argv1_begin - strlen("[]"));
+	strcat(argv1_begin, "]");
+	memset(argv1_begin + strlen(argv1_begin), '\0', 
+	       argv1_end - argv1_begin - strlen(argv1_begin));  
+}
+
+static char *usage_string = 
+"User Mode Linux v%s\n"
+"	available at http://user-mode-linux.sourceforge.net/\n\n";
+
+static int __init uml_version_setup(char *line, int *add)
+{
+	printf("%s\n", system_utsname.release);
+	exit(0);
+}
+
+__uml_setup("--version", uml_version_setup,
+"--version\n"
+"    Prints the version number of the kernel.\n\n"
+);
+
+static int __init uml_root_setup(char *line, int *add)
+{
+	have_root = 1;
+	return 0;
+}
+
+__uml_setup("root=", uml_root_setup,
+"root=<file containing the root fs>\n"
+"    This is actually used by the generic kernel in exactly the same\n"
+"    way as in any other kernel. If you configure a number of block\n"
+"    devices and want to boot off something other than ubd0, you \n"
+"    would use something like:\n"
+"        root=/dev/ubd5\n\n"
+);
+
+#ifdef CONFIG_SMP
+static int __init uml_ncpus_setup(char *line, int *add)
+{
+       if (!sscanf(line, "%d", &ncpus)) {
+               printk("Couldn't parse [%s]\n", line);
+               return -1;
+       }
+
+       return 0;
+}
+
+__uml_setup("ncpus=", uml_ncpus_setup,
+"ncpus=<# of desired CPUs>\n"
+"    This tells an SMP kernel how many virtual processors to start.\n"
+"    Currently, this has no effect because SMP isn't enabled.\n\n" 
+);
+#endif
+
+static int __init Usage(char *line, int *add)
+{
+ 	const char **p;
+
+	printf(usage_string, system_utsname.release);
+ 	p = &__uml_help_start;
+ 	while (p < &__uml_help_end) {
+ 		printf("%s", *p);
+ 		p++;
+ 	}
+	exit(0);
+}
+
+__uml_setup("--help", Usage,
+"--help\n"
+"    Prints this message.\n\n"
+);
+
+static int __init uml_checksetup(char *line, int *add)
+{
+	struct uml_param *p;
+
+	p = &__uml_setup_start;
+	while(p < &__uml_setup_end) {
+		int n;
+
+		n = strlen(p->str);
+		if(!strncmp(line, p->str, n)){
+			if (p->setup_func(line + n, add)) return 1;
+		}
+		p++;
+	}
+	return 0;
+}
+
+static void __init uml_postsetup(void)
+{
+	initcall_t *p;
+
+	p = &__uml_postsetup_start;
+	while(p < &__uml_postsetup_end){
+		(*p)();
+		p++;
+	}
+	return;
+}
+
+extern int debug_trace;
+extern int jail;
+void *brk_start;
+
+int linux_main(int argc, char **argv)
+{
+	unsigned long start_pfn, end_pfn, bootmap_size;
+	unsigned long virtmem_size;
+	unsigned int i, add;
+	void *sp;
+
+	for (i = 1; i < argc; i++){
+		if((i == 1) && (argv[i][0] == ' ')) continue;
+		add = 1;
+		uml_checksetup(argv[i], &add);
+		if(add) add_arg(saved_command_line, argv[i]);
+	}
+	if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
+
+	if(!jail)
+		remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
+	remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
+	brk_start = sbrk(0);
+	remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1);
+
+	/* Start physical memory at least 4M after the current brk */
+	uml_physmem = ROUND_4M(brk_start) + (1 << 22);
+
+	setup_machinename(system_utsname.machine);
+
+	argv1_begin = argv[1];
+	argv1_end = &argv[1][strlen(argv[1])];
+  
+	/* Kernel vm starts after physical memory and is either the size
+	 * of physical memory or the remaining space left in the kernel
+	 * area of the address space, whichever is smaller.
+	 */
+	start_vm = uml_physmem + physmem_size + VMALLOC_OFFSET;
+	if(start_vm >= get_kmem_end())
+		panic("Physical memory too large to allow any kernel "
+		      "virtual memory");
+
+	virtmem_size = physmem_size;
+	if(physmem_size > get_kmem_end() - start_vm)
+		virtmem_size = get_kmem_end() - start_vm;
+	end_vm = start_vm + virtmem_size;
+
+	if(virtmem_size < physmem_size)
+		printk(KERN_INFO "Kernel virtual memory size shrunk to %ld "
+		       "bytes\n", virtmem_size);
+
+	setup_range(-1, NULL, uml_physmem, physmem_size, 
+		    physmem_size + VMALLOC_OFFSET + virtmem_size);
+	setup_memory();
+	high_physmem = uml_physmem + physmem_size;
+
+	start_pfn = PFN_UP(__pa(uml_physmem));
+	end_pfn = PFN_DOWN(__pa(high_physmem));
+	bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn);
+	free_bootmem(__pa(uml_physmem) + bootmap_size, 
+		     high_physmem - uml_physmem - bootmap_size);
+  	uml_postsetup();
+
+	init_task.thread.kernel_stack = (unsigned long) &init_task + 
+		2 * PAGE_SIZE;
+
+	task_protections((unsigned long) &init_task);
+	sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - 
+		sizeof(unsigned long);
+	return(signals(start_kernel_proc, sp));
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	paging_init();
+ 	strcpy(command_line, saved_command_line);
+ 	*cmdline_p = command_line;
+	setup_hostinfo();
+}
+
+void __init check_bugs(void)
+{
+	arch_check_bugs();
+	check_ptrace();
+	check_sigio();
+}
+
+spinlock_t pid_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_pid(void)
+{
+	spin_lock(&pid_lock);
+}
+
+void unlock_pid(void)
+{
+	spin_unlock(&pid_lock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/umid.c linux-2.4.19-pre5-mjc/arch/um/kernel/umid.c
--- linux/arch/um/kernel/umid.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/umid.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,291 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include "user.h"
+#include "umid.h"
+#include "init.h"
+
+#define UMID_LEN 64
+#define UML_DIR "~/.uml/"
+
+static char umid[UMID_LEN] = { 0 };
+static char *uml_dir = UML_DIR;
+
+static int umid_inited = 0;
+
+static int make_umid(void);
+
+static int __init set_umid(char *name, int *add)
+{
+	if(umid_inited){
+		printk("Unique machine name can't be set twice\n");
+		return(-1);
+	}
+
+	if(strlen(name) > UMID_LEN - 1)
+		printk("Unique machine name is being truncated to %s "
+		       "characters\n", UMID_LEN);
+	strncpy(umid, name, UMID_LEN - 1);
+	umid[UMID_LEN - 1] = '\0';
+
+	umid_inited = 1;
+	return 0;
+}
+
+__uml_setup("umid=", set_umid,
+"umid=<name>\n"
+"    This is used to assign a unique identity to this UML machine and\n"
+"    is used for naming the pid file and management console socket.\n\n"
+);
+
+int __init umid_file_name(char *name, char *buf, int len)
+{
+	int n;
+
+	if(!umid_inited && make_umid()) return(-1);
+
+	n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
+	if(n > len){
+		printk("umid_file_name : buffer too short\n");
+		return(-1);
+	}
+
+	sprintf(buf, "%s%s/%s", uml_dir, umid, name);
+	return(0);
+}
+
+extern int tracing_pid;
+
+static int __init create_pid_file(void)
+{
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+	char pid[sizeof("nnnnn\0")];
+	int fd;
+
+	if(umid_file_name("pid", file, sizeof(file))) return 0;
+
+	if((fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0){
+		printk("Open of machine pid file \"%s\" failed - "
+		       "errno = %d\n", file, errno);
+		return 0;
+	}
+
+	sprintf(pid, "%d\n", (tracing_pid == -1) ?  getpid() : tracing_pid);
+	if(write(fd, pid, strlen(pid)) != strlen(pid))
+		printk("Write of pid file failed - errno = %d\n", errno);
+	close(fd);
+	return 0;
+}
+
+static int actually_do_remove(char *dir)
+{
+	DIR *directory;
+	struct dirent *ent;
+	int len;
+	char file[256];
+
+	if((directory = opendir(dir)) == NULL){
+		printk("actually_do_remove : couldn't open directory '%s', "
+		       "errno = %d\n", dir, errno);
+		return(1);
+	}
+	while((ent = readdir(directory)) != NULL){
+		if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
+			continue;
+		len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
+		if(len > sizeof(file)){
+			printk("Not deleting '%s' from '%s' - name too long\n",
+			       ent->d_name, dir);
+			continue;
+		}
+		sprintf(file, "%s/%s", dir, ent->d_name);
+		if(unlink(file) < 0){
+			printk("actually_do_remove : couldn't remove '%s' "
+			       "from '%s', errno = %d\n", ent->d_name, dir, 
+			       errno);
+			return(1);
+		}
+	}
+	if(rmdir(dir) < 0){
+		printk("actually_do_remove : couldn't rmdir '%s', "
+		       "errno = %d\n", dir, errno);
+		return(1);
+	}
+	return(0);
+}
+
+void remove_umid_dir(void)
+{
+	char dir[strlen(uml_dir) + UMID_LEN + 1];
+	if(!umid_inited) return;
+
+	sprintf(dir, "%s%s", uml_dir, umid);
+	actually_do_remove(dir);
+}
+
+char *get_umid(void)
+{
+	return(umid);
+}
+
+int not_dead_yet(char *dir)
+{
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+	char pid[sizeof("nnnnn\0")], *end;
+	int dead, fd, p;
+
+	sprintf(file, "%s/pid", dir);
+	dead = 0;
+	if((fd = open(file, O_RDONLY)) < 0){
+		if(errno != ENOENT){
+			printk("not_dead_yet : couldn't open pid file '%s', "
+			       "errno = %d\n", file, errno);
+			return(1);
+		}
+		dead = 1;
+	}
+	if(fd > 0){
+		if(read(fd, pid, sizeof(pid)) < 0){
+			printk("not_dead_yet : couldn't read pid file '%s', "
+			       "errno = %d\n", file, errno);
+			return(1);
+		}
+		p = strtoul(pid, &end, 0);
+		if(end == pid){
+			printk("not_dead_yet : couldn't parse pid file '%s', "
+			       "errno = %d\n", file, errno);
+			dead = 1;
+		}
+		if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
+		   (p == tracing_pid)) 
+			dead = 1;
+	}
+	if(!dead) return(1);
+	return(actually_do_remove(dir));
+	return(0);
+}
+
+static int __init set_uml_dir(char *name, int *add)
+{
+	if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+		uml_dir = malloc(strlen(name) + 1);
+		if(uml_dir == NULL){
+			printk("Failed to malloc uml_dir - error = %d\n",
+			       errno);
+			uml_dir = name;
+			return(0);
+		}
+		sprintf(uml_dir, "%s/", name);
+	}
+	else uml_dir = name;
+	return 0;
+}
+
+static int __init make_uml_dir(void)
+{
+	char dir[MAXPATHLEN + 1] = { '\0' };
+	int len;
+
+	if(*uml_dir == '~'){
+		char *home = getenv("HOME");
+
+		if(home == NULL){
+			printk("make_uml_dir : no value in environment for "
+			       "$HOME\n");
+			exit(1);
+		}
+		strncpy(dir, home, sizeof(dir));
+		uml_dir++;
+	}
+	len = strlen(dir);
+	strncat(dir, uml_dir, sizeof(dir) - len);
+	len = strlen(dir);
+	if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
+		dir[len] = '/';
+		dir[len + 1] = '\0';
+	}
+
+	if((uml_dir = malloc(strlen(dir) + 1)) == NULL){
+		printf("make_uml_dir : malloc failed, errno = %d\n", errno);
+		exit(1);
+	}
+	strcpy(uml_dir, dir);
+	
+	if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+	        printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
+		return(-1);
+	}
+	return 0;
+}
+
+static int __init make_umid(void)
+{
+	int fd, err;
+	char tmp[strlen(uml_dir) + UMID_LEN + 1];
+
+	strncpy(tmp, uml_dir, sizeof(tmp) - 1);
+	tmp[sizeof(tmp) - 1] = '\0';
+
+	if(*umid == 0){
+		strcat(tmp, "XXXXXX");
+		fd = mkstemp(tmp);
+		if(fd < 0){
+			printk("set_umid - mkstemp failed, errno = %d\n",
+			       errno);
+			return(1);
+		}
+
+		close(fd);
+		/* There's a nice tiny little race between this unlink and
+		 * the mkdir below.  It'd be nice if there were a mkstemp
+		 * for directories.
+		 */
+		unlink(tmp);
+		strcpy(umid, &tmp[strlen(uml_dir)]);
+	}
+	
+	sprintf(tmp, "%s%s", uml_dir, umid);
+
+	if((err = mkdir(tmp, 0777)) < 0){
+		if(errno == EEXIST){
+			if(not_dead_yet(tmp)){
+				printk("umid '%s' is in use\n", umid);
+				return(-1);
+			}
+			err = mkdir(tmp, 0777);
+		}
+	}
+	if(err < 0){
+		printk("Failed to create %s - errno = %d\n", umid, errno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+__uml_setup("uml_dir=", set_uml_dir,
+"uml_dir=<directory>\n"
+"    The location to place the pid and umid files.\n\n"
+);
+
+__uml_postsetup(make_uml_dir);
+__uml_postsetup(make_umid);
+__uml_postsetup(create_pid_file);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/unmap.c linux-2.4.19-pre5-mjc/arch/um/kernel/unmap.c
--- linux/arch/um/kernel/unmap.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/unmap.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "user.h"
+
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+	if(munmap(to, size) < 0){
+		return(-1);
+	}
+	if(mmap(to, size, prot,	MAP_SHARED | MAP_FIXED, fd, 0) != to){
+		return(-1);
+	}
+	if(munmap(from, size) < 0){
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/kernel/user_syms.c linux-2.4.19-pre5-mjc/arch/um/kernel/user_syms.c
--- linux/arch/um/kernel/user_syms.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/user_syms.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <utime.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/ioctl.h>
+#include "user_util.h"
+#include "mem_user.h"
+
+/* XXX All the __CONFIG_* stuff is broken because this file can't include
+ * config.h
+ */
+
+/* Had to steal this from linux/module.h because that file can't be included
+ * since this includes various user-level headers.
+ */
+
+struct module_symbol
+{
+	unsigned long value;
+	const char *name;
+};
+
+/* Indirect stringification.  */
+
+#define __MODULE_STRING_1(x)	#x
+#define __MODULE_STRING(x)	__MODULE_STRING_1(x)
+
+#if !defined(__AUTOCONF_INCLUDED__)
+
+#define __EXPORT_SYMBOL(sym,str)   error config_must_be_included_before_module
+#define EXPORT_SYMBOL(var)	   error config_must_be_included_before_module
+#define EXPORT_SYMBOL_NOVERS(var)  error config_must_be_included_before_module
+
+#elif !defined(__CONFIG_MODULES__)
+
+#define __EXPORT_SYMBOL(sym,str)
+#define EXPORT_SYMBOL(var)
+#define EXPORT_SYMBOL_NOVERS(var)
+
+#else
+
+#define __EXPORT_SYMBOL(sym, str)			\
+const char __kstrtab_##sym[]				\
+__attribute__((section(".kstrtab"))) = str;		\
+const struct module_symbol __ksymtab_##sym 		\
+__attribute__((section("__ksymtab"))) =			\
+{ (unsigned long)&sym, __kstrtab_##sym }
+
+#if defined(__MODVERSIONS__) || !defined(__CONFIG_MODVERSIONS__)
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+#else
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
+#endif
+
+#define EXPORT_SYMBOL_NOVERS(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+
+#endif
+
+EXPORT_SYMBOL(__errno_location);
+
+EXPORT_SYMBOL(access);
+EXPORT_SYMBOL(open);
+EXPORT_SYMBOL(open64);
+EXPORT_SYMBOL(close);
+EXPORT_SYMBOL(read);
+EXPORT_SYMBOL(write);
+EXPORT_SYMBOL(__xstat);
+EXPORT_SYMBOL(__lxstat);
+EXPORT_SYMBOL(__lxstat64);
+EXPORT_SYMBOL(lseek);
+EXPORT_SYMBOL(lseek64);
+EXPORT_SYMBOL(chown);
+EXPORT_SYMBOL(truncate);
+EXPORT_SYMBOL(utime);
+EXPORT_SYMBOL(chmod);
+EXPORT_SYMBOL(rename);
+EXPORT_SYMBOL(__xmknod);
+
+EXPORT_SYMBOL(symlink);
+EXPORT_SYMBOL(link);
+EXPORT_SYMBOL(unlink);
+EXPORT_SYMBOL(readlink);
+
+EXPORT_SYMBOL(mkdir);
+EXPORT_SYMBOL(rmdir);
+EXPORT_SYMBOL(opendir);
+EXPORT_SYMBOL(readdir);
+EXPORT_SYMBOL(closedir);
+EXPORT_SYMBOL(seekdir);
+EXPORT_SYMBOL(telldir);
+
+EXPORT_SYMBOL(ioctl);
+
+extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
+			__off64_t __offset);
+extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n,
+			 __off64_t __offset);
+EXPORT_SYMBOL(pread64);
+EXPORT_SYMBOL(pwrite64);
+
+EXPORT_SYMBOL(statfs);
+EXPORT_SYMBOL(statfs64);
+
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(getuid);
+
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(find_iomem);
diff -Nru linux/arch/um/kernel/user_util.c linux-2.4.19-pre5-mjc/arch/um/kernel/user_util.c
--- linux/arch/um/kernel/user_util.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/kernel/user_util.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,336 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/mman.h> 
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+#include <sys/mount.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include "asm/types.h"
+#include <ctype.h>
+#include <signal.h>
+#include <wait.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sched.h>
+#include <termios.h>
+#include <string.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "mem_user.h"
+#include "init.h"
+
+#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
+
+char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
+char command_line[COMMAND_LINE_SIZE] = { 0 };
+
+void add_arg(char *cmd_line, char *arg)
+{
+	if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
+		printf("add_arg: Too much command line!\n");
+		exit(1);
+	}
+	if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
+	strcat(cmd_line, arg);
+}
+
+void remap_data(void *segment_start, void *segment_end, int w)
+{
+	void *addr;
+	unsigned long size;
+	int data, prot;
+
+	if(w) prot = PROT_WRITE;
+	else prot = 0;
+	prot |= PROT_READ | PROT_EXEC;
+	size = (unsigned long) segment_end - 
+		(unsigned long) segment_start;
+	data = create_mem_file(size);
+	if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, 
+			MAP_SHARED, data, 0)) < 0){
+		perror("mapping new data segment");
+		exit(1);
+	}
+	memcpy(addr, segment_start, size);
+	if(switcheroo(data, prot, addr, segment_start, 
+		      size) < 0){
+		printf("switcheroo failed\n");
+		exit(1);
+	}
+}
+
+__s64 file_size(char *file)
+{
+	struct stat64 buf;
+
+	if(stat64(file, &buf) == -1){
+		printk("Couldn't stat \"%s\" : errno = %d\n", file, errno);
+		return(-errno);
+	}
+	if(S_ISBLK(buf.st_mode)){
+		long long size;
+		int fd;
+
+		if((fd = open64(file, O_RDONLY)) < 0){
+			printk("Couldn't open \"%s\", errno = %d\n", file,
+			       errno);
+			return(-errno);
+		}
+		if(ioctl(fd, BLKGETSIZE, &size) < 0){
+			printk("Couldn't get the block size of \"%s\", "
+			       "errno = %d\n", file, errno);
+			close(fd);
+			return(-errno);
+		}
+		size *= 512;
+		close(fd);
+		return(size);
+	}
+	return(buf.st_size);
+}
+
+void stop(void)
+{
+	while(1) sleep(1000000);
+}
+
+void stack_protections(unsigned long address)
+{
+	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+        if(mprotect((void *) address, page_size(), prot) < 0)
+		panic("protecting stack failed, errno = %d", errno);
+}
+
+void task_protections(unsigned long address)
+{
+	unsigned long guard = address + page_size();
+	unsigned long stack = guard + page_size();
+	int prot = 0;
+
+	if(mprotect((void *) stack, page_size(), prot) < 0)
+		panic("protecting guard page failed, errno = %d", errno);
+	prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	if(mprotect((void *) stack, 2 * page_size(), prot) < 0)
+		panic("protecting stack failed, errno = %d", errno);
+}
+
+int wait_for_stop(int pid, int sig, int cont_type)
+{
+	int status, ret;
+
+	while(1){
+		if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) ||
+		   !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
+			if(ret < 0){
+				if(errno == EINTR) continue;
+				printk("wait failed, errno = %d\n",
+				       errno);
+			}
+			else if(WIFEXITED(status)) 
+				printk("process exited with status %d\n", 
+				       WEXITSTATUS(status));
+			else if(WIFSIGNALED(status))
+				printk("process exited with signal %d\n", 
+				       WTERMSIG(status));
+			else if((WSTOPSIG(status) == SIGVTALRM) ||
+				(WSTOPSIG(status) == SIGALRM) ||
+				(WSTOPSIG(status) == SIGIO) ||
+				(WSTOPSIG(status) == SIGPROF) ||
+				(WSTOPSIG(status) == SIGCHLD) ||
+				(WSTOPSIG(status) == SIGWINCH) ||
+				(WSTOPSIG(status) == SIGINT)){
+				ptrace(cont_type, pid, 0, WSTOPSIG(status));
+				continue;
+			}
+			else printk("process stopped with signal %d\n", 
+				    WSTOPSIG(status));
+			panic("wait_for_stop failed to wait for %d to stop "
+			      "with %d\n", pid, sig);
+		}
+		return(status);
+	}
+}
+
+int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
+{
+	int pid;
+
+	pid = clone(fn, sp, flags, arg);
+ 	if(pid < 0) return(-1);
+	wait_for_stop(pid, SIGSTOP, PTRACE_CONT);
+	ptrace(PTRACE_CONT, pid, 0, 0);
+	return(pid);
+}
+
+struct grantpt_info {
+	int fd;
+	int res;
+	int err;
+};
+
+static void grantpt_cb(void *arg)
+{
+	struct grantpt_info *info = arg;
+
+	info->res = grantpt(info->fd);
+	info->err = errno;
+}
+
+int get_pty(void)
+{
+	struct grantpt_info info;
+	int fd;
+
+	if((fd = open("/dev/ptmx", O_RDWR)) < 0){
+		printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n",
+		       errno);
+		return(-1);
+	}
+	info.fd = fd;
+	tracing_cb(grantpt_cb, &info);
+	if(info.res < 0){
+		printk("get_pty : Couldn't grant pty - errno = %d\n", 
+		       info.err);
+		return(-1);
+	}
+	if(unlockpt(fd) < 0){
+		printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
+		return(-1);
+	}
+	return(fd);
+}
+
+int raw(int fd, int complain)
+{
+	struct termios tt;
+	int err;
+
+	tcgetattr(fd, &tt);
+	cfmakeraw(&tt);
+	err = tcsetattr(fd, TCSANOW, &tt);
+	if((err < 0) && complain){
+		printk("tcsetattr failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	return(0);
+}
+
+void setup_machinename(char *machine_out)
+{
+	struct utsname host;
+
+	uname(&host);
+	strcpy(machine_out, host.machine);
+}
+
+char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
+
+void setup_hostinfo(void)
+{
+	struct utsname host;
+
+	uname(&host);
+	sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
+		host.release, host.version, host.machine);
+}
+
+void close_fd(int fd)
+{
+	close(fd);
+}
+
+char *tempdir = NULL;
+
+static void __init find_tempdir(void)
+{
+	char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+	int i;
+	char *dir = NULL;
+
+	if(tempdir != NULL) return;	/* We've already been called */
+	for(i = 0; dirs[i]; i++){
+		dir = getenv(dirs[i]);
+		if(dir != NULL) break;
+	}
+	if(dir == NULL) dir = "/tmp";
+	else if(*dir == '\0') dir = NULL;
+	if(dir != NULL) {
+		tempdir = malloc(strlen(dir) + 2);
+		if(tempdir == NULL){
+			fprintf(stderr, "Failed to malloc tempdir, "
+				"errno = %d\n", errno);
+			return;
+		}
+		strcpy(tempdir, dir);
+		strcat(tempdir, "/");
+	}
+}
+
+int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+{
+	char tempname[MAXPATHLEN];
+	int fd;
+
+	find_tempdir();
+	if (*template != '/')
+		strcpy(tempname, tempdir);
+	else
+		*tempname = 0;
+	strcat(tempname, template);
+	if((fd = mkstemp(tempname)) < 0){
+		fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
+			strerror(errno));
+		return -1;
+	}
+	if(do_unlink && (unlink(tempname) < 0)){
+		perror("unlink");
+		return -1;
+	}
+	if(out_tempname){
+		if((*out_tempname = strdup(tempname)) == NULL){
+			perror("strdup");
+			return -1;
+		}
+	}
+	return(fd);
+}
+
+int user_read(int fd, char *buf, int len)
+{
+	int err;
+
+	err = read(fd, buf, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int user_write(int fd, char *buf, int len)
+{
+	int err;
+
+	err = write(fd, buf, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/link.ld.in linux-2.4.19-pre5-mjc/arch/um/link.ld.in
--- linux/arch/um/link.ld.in	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/link.ld.in	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,133 @@
+OUTPUT_FORMAT("elf32-ELF_SUBARCH")
+OUTPUT_ARCH(ELF_SUBARCH)
+ENTRY(_start)
+
+SECTIONS
+{
+  . = START() + SIZEOF_HEADERS;
+
+  . = ALIGN(4096);
+  .thread_private : {
+    __start_thread_private = .;
+    errno = .;
+    . += 4;
+    arch/um/kernel/unmap_fin.o (.data)
+    __end_thread_private = .;
+  }
+  . = ALIGN(4096);
+  .remap : { arch/um/kernel/unmap_fin.o (.text) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  . = ALIGN(4096);
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  .fini      : { *(.fini)    } =0x9090
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  _etext = .;
+  PROVIDE (etext = .);
+
+  . = ALIGN(4096);
+  PROVIDE (_sdata = .);
+
+  .unprotected : { *(.unprotected) }
+  . = ALIGN(4096);
+  PROVIDE (_unprotected_end = .);
+
+  . = ALIGN(4096);
+  __uml_setup_start = .;
+  .uml.setup.init : { *(.uml.setup.init) }
+  __uml_setup_end = .;
+  __uml_help_start = .;
+  .uml.help.init : { *(.uml.help.init) }
+  __uml_help_end = .;
+  __uml_postsetup_start = .;
+  .uml.postsetup.init : { *(.uml.postsetup.init) }
+  __uml_postsetup_end = .;
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  __uml_initcall_start = .;
+  .uml.initcall.init : { *(.uml.initcall.init) }
+  __uml_initcall_end = .;
+  __init_end = .;
+  __exitcall_begin = .;
+  .exitcall : { *(.exitcall.exit) }
+  __exitcall_end = .;
+  __uml_exitcall_begin = .;
+  .uml.exitcall : { *(.uml.exitcall.exit) }
+  __uml_exitcall_end = .;
+
+  .data.init : { *(.data.init) }
+  .data    :
+  {
+    . = ALIGN(16384);		/* init_task */
+    *(.data.init_task)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  . = ALIGN(0x1000);
+  .sbss      : 
+  {
+   __bss_start = .;
+   PROVIDE(_bss_start = .);
+   *(.sbss) 
+   *(.scommon) 
+  }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -Nru linux/arch/um/main.c linux-2.4.19-pre5-mjc/arch/um/main.c
--- linux/arch/um/main.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/main.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,215 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h> 
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <asm/page.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "user.h"
+#include "init.h"
+
+unsigned long stacksizelim;
+
+char *linux_prog;
+
+#define PGD_BOUND (4 * 1024 * 1024)
+#define STACKSIZE (8 * 1024 * 1024)
+#define THREAD_NAME_LEN (256)
+
+char padding[THREAD_NAME_LEN] = { [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' };
+
+static void set_stklim(void)
+{
+	struct rlimit lim;
+
+	if(getrlimit(RLIMIT_STACK, &lim) < 0){
+		perror("getrlimit");
+		exit(1);
+	}
+	if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
+		lim.rlim_cur = STACKSIZE;
+		if(setrlimit(RLIMIT_STACK, &lim) < 0){
+			perror("setrlimit");
+			exit(1);
+		}
+	}
+	stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
+}
+
+static __init void do_uml_initcalls(void)
+{
+	initcall_t *call;
+
+	call = &__uml_initcall_start;
+	while (call < &__uml_initcall_end){;
+		(*call)();
+		call++;
+	}
+}
+
+int main(int argc, char **argv, char **envp)
+{
+	sigset_t mask;
+	int ret, i;
+	char **new_argv;
+
+	/* Enable all signals - in some environments, we can enter with
+	 * some signals blocked
+	 */
+
+	sigemptyset(&mask);
+	if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
+		perror("sigprocmask");
+		exit(1);
+	}
+
+	/* Allocate memory for thread command lines */
+	if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
+		new_argv = malloc((argc + 2) * sizeof(char*));
+		if(!new_argv) {
+			perror("Allocating extended argv");
+			exit(1);
+		}	
+		
+		new_argv[0] = argv[0];
+		new_argv[1] = padding;
+		
+		for(i = 2; i <= argc; i++)
+			new_argv[i] = argv[i - 1];
+		new_argv[argc + 1] = NULL;
+		
+#ifdef PROFILING
+		disable_profile_timer();
+#endif
+		execvp(new_argv[0], new_argv);
+		perror("execing with extended args");
+		exit(1);
+	}	
+
+	linux_prog = argv[0];
+
+	set_stklim();
+	set_task_sizes(0);
+
+	if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
+		perror("Mallocing argv");
+		exit(1);
+	}
+	for(i=0;i<argc;i++){
+		if((new_argv[i] = strdup(argv[i])) == NULL){
+			perror("Mallocing an arg");
+			exit(1);
+		}
+	}
+	new_argv[argc] = NULL;
+
+	do_uml_initcalls();
+	ret = linux_main(argc, argv);
+	
+	/* Reboot */
+	if(ret){
+		printf("\n");
+		execvp(new_argv[0], new_argv);
+		perror("Failed to exec kernel");
+		ret = 1;
+	}
+	printf("\n");
+	return(ret);
+}
+
+int allocating_monbuf = 0;
+
+#ifdef PROFILING
+extern void __real___monstartup (unsigned long, unsigned long);
+
+void __wrap___monstartup (unsigned long lowpc, unsigned long highpc)
+{
+	allocating_monbuf = 1;
+	__real___monstartup(lowpc, highpc);
+	allocating_monbuf = 0;
+	get_profile_timer();
+}
+#endif
+
+extern void *__real_malloc(int);
+extern unsigned long host_task_size;
+
+static void *gmon_buf = NULL;
+
+void *__wrap_malloc(int size)
+{
+	if(allocating_monbuf){
+		unsigned long start, end;
+		int fd;
+
+		/* Turn this off now in case create_mem_file tries allocating
+		 * memory
+		 */
+		allocating_monbuf = 0;
+		fd = create_mem_file(size);
+
+		/* Calculate this here because linux_main hasn't run yet
+		 * and host_task_size figures in STACK_TOP, which figures
+		 * in kmem_end.
+		 */
+		set_task_sizes(0);
+
+		/* Same with stacksizelim */
+		set_stklim();
+
+		end = get_kmem_end();
+		start = (end - size) & PAGE_MASK;
+		gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE,
+			    MAP_SHARED | MAP_FIXED, fd, 0);
+		if(gmon_buf != (void *) start){
+			perror("Creating gprof buffer");
+			exit(1);
+		}
+		set_kmem_end(start);
+		return(gmon_buf);
+	}
+	if(kmalloc_ok) return(um_kmalloc(size));
+	else return(__real_malloc(size));
+}
+
+void *__wrap_calloc(int n, int size)
+{
+	void *ptr = __wrap_malloc(n * size);
+
+	if(ptr == NULL) return(NULL);
+	memset(ptr, 0, n * size);
+	return(ptr);
+}
+
+extern void __real_free(void *);
+
+void __wrap_free(void *ptr)
+{
+	/* Could maybe unmap the gmon buffer, but we're just about to
+	 * exit anyway
+	 */
+	if(ptr == gmon_buf) return;
+	if(kmalloc_ok) kfree(ptr);
+	else __real_free(ptr);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/Makefile linux-2.4.19-pre5-mjc/arch/um/ptproxy/Makefile
--- linux/arch/um/ptproxy/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+LIB = ptproxy.a
+
+OBJS = proxy.o ptrace.o sysdep.o wait.o
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+	rm -f $@
+	ar cr $@ $^
+
+proxy.o: proxy.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+ptrace.o: ptrace.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+sysdep.o: sysdep.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+wait.o: wait.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f *.o core child ptproxy
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/ptproxy/proxy.c linux-2.4.19-pre5-mjc/arch/um/ptproxy/proxy.c
--- linux/arch/um/ptproxy/proxy.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/proxy.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,277 @@
+/**********************************************************************
+proxy.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+Jeff Dike (jdike@karaya.com) : Modified for integration into uml
+**********************************************************************/
+
+/* XXX This file shouldn't refer to CONFIG_* */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/ioctl.h>
+#include <asm/unistd.h>
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+
+#include "user_util.h"
+#include "user.h"
+
+/*
+ * Handle debugger trap, i.e. syscall.
+ */
+
+int debugger_syscall (debugger_state *debugger, pid_t child)
+{
+	long arg1, arg2, arg3, arg4, arg5, result;
+	int syscall, ret = 0;
+
+	syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, 
+			      &arg5);
+
+	switch(syscall){
+	case __NR_execve:
+		/* execve never returns */
+		debugger->handle_trace = debugger_syscall; 
+		break;
+
+	case __NR_ptrace:
+		if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
+		result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
+				      &ret);
+		syscall_cancel(debugger->pid, result);
+		debugger->handle_trace = debugger_syscall;
+		return(ret);
+
+	case __NR_waitpid:
+	case __NR_wait4:
+		debugger->wait_status_ptr = (int *) arg2;
+		debugger->wait_options = arg3;
+		if(debugger->debugee->event){
+			syscall_continue(debugger->pid);
+			wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL);
+			proxy_wait_return(debugger, -1);
+			return(0);
+		}
+		else if(debugger->wait_options & WNOHANG){
+			syscall_cancel(debugger->pid, 0);
+			debugger->handle_trace = debugger_syscall;
+			return(0);
+		}
+		else {
+			syscall_pause(debugger->pid);
+			debugger->handle_trace = proxy_wait_return;
+			debugger->waiting = 1;
+		}
+		break;
+
+	case __NR_kill:
+		if(arg1 == debugger->debugee->pid){
+			result = kill(child, arg2);
+			syscall_cancel(debugger->pid, result);
+			debugger->handle_trace = debugger_syscall;
+			return(0);
+		}
+		else debugger->handle_trace = debugger_normal_return;
+		break;
+
+	default:
+		debugger->handle_trace = debugger_normal_return;
+	}
+
+	syscall_continue (debugger->pid);
+	return(ret);
+}
+
+int debugger_normal_return(debugger_state *debugger, pid_t unused)
+{
+	debugger->handle_trace = debugger_syscall;
+	syscall_continue(debugger->pid);
+	return(0);
+}
+
+void debugger_cancelled_return(debugger_state *debugger, int result)
+{
+	debugger->handle_trace = debugger_syscall;
+	syscall_set_result(debugger->pid, result);
+	syscall_continue(debugger->pid);
+}
+
+#ifdef CONFIG_SMP
+#error need to make these arrays
+#endif
+
+static debugger_state debugger;
+static debugee_state debugee;
+
+void init_proxy (pid_t debugger_pid, int stopped, int status)
+{
+	debugger.pid = debugger_pid;
+	debugger.handle_trace = debugger_syscall;
+	debugger.debugee = &debugee;
+	debugger.waiting = 0;
+
+	debugee.pid = 0;
+	debugee.traced = 0;
+	debugee.stopped = stopped;
+	debugee.event = 0;
+	debugee.zombie = 0;
+	debugee.died = 0;
+	debugee.wait_status = status;
+}
+
+int debugger_proxy(int status, int pid)
+{
+	int ret = 0;
+
+	if(WIFSTOPPED(status)){
+		if (WSTOPSIG (status) == SIGTRAP)
+			ret = (*debugger.handle_trace)(&debugger, pid);
+		else ptrace(PTRACE_SYSCALL, debugger.pid, 0, WSTOPSIG(status));
+	}
+	else if(WIFEXITED(status)){
+		tracer_panic("debugger (pid %d) exited with status %d", 
+			     debugger.pid, WEXITSTATUS(status));
+	}
+	else if(WIFSIGNALED(status)){
+		tracer_panic("debugger (pid %d) exited with signal %d", 
+			     debugger.pid, WTERMSIG(status));
+	}
+	else {
+		tracer_panic("proxy got unknown status (0x%x) on debugger "
+			     "(pid %d)", status, debugger.pid);
+	}
+	return(ret);
+}
+
+void child_proxy(pid_t pid, int status)
+{
+	debugee.event = 1;
+	debugee.wait_status = status;
+
+	if(WIFSTOPPED(status)){
+		debugee.stopped = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else if(WIFEXITED(status) || WIFSIGNALED(status)){
+		debugee.zombie = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else panic("proxy got unknown status (0x%x) on child (pid %d)", 
+		   status, pid);
+}
+
+void fake_child_exit(void)
+{
+	int status, pid;
+
+	child_proxy(1, W_EXITCODE(0, 0));
+	while(debugger.waiting == 1){
+		pid = waitpid(debugger.pid, &status, WUNTRACED);
+		if(pid != debugger.pid){
+			printk("fake_child_exit - waitpid failed, "
+			       "errno = %d\n", errno);
+			return;
+		}
+		debugger_proxy(status, debugger.pid);
+	}
+	pid = waitpid(debugger.pid, &status, WUNTRACED);
+	if(pid != debugger.pid){
+		printk("fake_child_exit - waitpid failed, "
+		       "errno = %d\n", errno);
+		return;
+	}
+	if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
+		printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
+		       errno);
+}
+
+char gdb_init_string[] = 
+"att 1
+b panic
+b stop
+handle SIGWINCH nostop noprint pass
+";
+
+int start_debugger(char *prog, int startup, int stop, int *fd_out)
+{
+	int slave, child;
+
+	slave = open_gdb_chan();
+	if((child = fork()) == 0){
+		char *tempname = NULL;
+		int fd;
+
+	        if(setsid() < 0) perror("setsid");
+		if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || 
+		   (dup2(slave, 2) < 0)){
+			printk("start_debugger : dup2 failed, errno = %d\n",
+			       errno);
+			exit(1);
+		}
+		if(ioctl(0, TIOCSCTTY, 0) < 0){
+			printk("start_debugger : TIOCSCTTY failed, "
+			       "errno = %d\n", errno);
+			exit(1);
+		}
+		if(tcsetpgrp (1, getpid()) < 0){
+			printk("start_debugger : tcsetpgrp failed, "
+			       "errno = %d\n", errno);
+#ifdef notdef
+			exit(1);
+#endif
+		}
+		if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
+			printk("start_debugger : make_tempfile failed, errno = %d\n",
+			       errno);
+			exit(1);
+		}
+		write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+		if(startup){
+			if(stop){
+				write(fd, "b start_kernel\n",
+				      strlen("b start_kernel\n"));
+			}
+			write(fd, "c\n", strlen("c\n"));
+		}
+		if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+			printk("start_debugger :  PTRACE_TRACEME failed, "
+			       "errno = %d\n", errno);
+			exit(1);
+		}
+		execlp("gdb", "gdb", "--command", tempname, prog, NULL);
+		printk("start_debugger : exec of gdb failed, errno = %d\n",
+		       errno);
+	}
+	if(child < 0){
+		printk("start_debugger : fork for gdb failed, errno = %d\n",
+		       errno);
+		return(-1);
+	}
+	*fd_out = slave;
+	return(child);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/ptproxy.h linux-2.4.19-pre5-mjc/arch/um/ptproxy/ptproxy.h
--- linux/arch/um/ptproxy/ptproxy.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/ptproxy.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,58 @@
+/**********************************************************************
+ptproxy.h
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#ifndef __PTPROXY_H
+#define __PTPROXY_H
+
+#include <sys/types.h>
+
+typedef struct debugger debugger_state;
+typedef struct debugee debugee_state;
+
+struct debugger
+{
+	pid_t pid;
+	int wait_options;
+	int *wait_status_ptr;
+	unsigned int waiting : 1;
+	int (*handle_trace) (debugger_state *, pid_t);
+
+	debugee_state *debugee;
+};
+
+struct debugee
+{
+	pid_t pid;
+	int wait_status;
+	unsigned died : 1;
+	unsigned event : 1;
+	unsigned stopped : 1;
+	unsigned trace_singlestep : 1;
+	unsigned trace_syscall : 1;
+	unsigned traced : 1;
+	unsigned zombie : 1;
+};
+
+extern int debugger_syscall(debugger_state *debugger, pid_t pid);
+extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
+
+extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
+			  int *strace_out);
+extern void debugger_cancelled_return(debugger_state *debugger, int result);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/ptrace.c linux-2.4.19-pre5-mjc/arch/um/ptproxy/ptrace.c
--- linux/arch/um/ptproxy/ptrace.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/ptrace.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,213 @@
+/**********************************************************************
+ptrace.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+Jeff Dike (jdike@karaya.com) : Modified for integration into uml
+**********************************************************************/
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <asm/ptrace.h>
+
+#include "ptproxy.h"
+#include "debug.h"
+#include "user_util.h"
+#include "ptrace_user.h"
+
+long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
+		  long arg3, long arg4, pid_t child, int *ret)
+{
+	long result;
+	int status;
+
+	*ret = 0;
+	if(debugger->debugee->died) return(-ESRCH);
+
+	switch(arg1){
+	case PTRACE_ATTACH:
+		if(debugger->debugee->traced) return(-EPERM);
+
+		debugger->debugee->pid = arg2;
+		debugger->debugee->traced = 1;
+		if(debugger->debugee->stopped) 
+			child_proxy(child, W_STOPCODE(SIGSTOP));
+		else kill(child, SIGSTOP);
+		return(0);
+
+	case PTRACE_CONT:
+		*ret = PTRACE_CONT;
+		return(ptrace(PTRACE_CONT, child, arg3, arg4));
+
+	case PTRACE_DETACH:
+		if(!debugger->debugee->traced) return(-EPERM);
+		
+		debugger->debugee->traced = 0;
+		kill(child, SIGCONT);
+		return(0);
+
+#ifdef UM_HAVE_GETFPREGS
+	case PTRACE_GETFPREGS:
+	{
+		long regs[FP_FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+		
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
+			       regs[i]);
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_GETFPXREGS
+	case PTRACE_GETFPXREGS:
+	{
+		long regs[FPX_FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+		
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
+			       regs[i]);
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_GETREGS
+	case PTRACE_GETREGS:
+	{
+		long regs[FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace (PTRACE_POKEDATA, debugger->pid,
+				arg4 + 4 * i, regs[i]);
+		return(result);
+	}
+	break;
+#endif
+
+	case PTRACE_KILL:
+		result = ptrace(PTRACE_KILL, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		return(result);
+
+	case PTRACE_PEEKDATA:
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKUSER:
+		/* The value being read out could be -1, so we have to 
+		 * check errno to see if there's an error, and zero it
+		 * beforehand so we're not faked out by an old error
+		 */
+
+		errno = 0;
+		result = ptrace(arg1, child, arg3, 0);
+		if((result == -1) && (errno != 0)) return(-errno);
+
+		result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
+		if(result == -1) return(-errno);
+			
+		return(result);
+
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEUSER:
+		result = ptrace(arg1, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		return(result);
+
+#ifdef UM_HAVE_SETFPREGS
+	case PTRACE_SETFPREGS:
+	{
+		long regs[FP_FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
+					  arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_SETFPXREGS
+	case PTRACE_SETFPXREGS:
+	{
+		long regs[FPX_FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
+					  arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_SETREGS
+	case PTRACE_SETREGS:
+	{
+		long regs[FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
+					 arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+	case PTRACE_SINGLESTEP:
+		result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
+		if(result == -1) return(-errno);
+		
+		status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP);
+		child_proxy(child, status);
+		return(result);
+
+	case PTRACE_SYSCALL:
+		result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		*ret = PTRACE_SYSCALL;
+		return(result);
+
+	case PTRACE_TRACEME:
+	default:
+		return(-EINVAL);
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/sysdep.c linux-2.4.19-pre5-mjc/arch/um/ptproxy/sysdep.c
--- linux/arch/um/ptproxy/sysdep.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/sysdep.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,71 @@
+/**********************************************************************
+sysdep.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <linux/unistd.h>
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "user.h"
+
+int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, 
+		long *arg5)
+{
+	*arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0);
+	*arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0);
+	*arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0);
+	*arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0);
+	*arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0);
+	return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0));
+}
+
+void syscall_cancel(pid_t pid, int result)
+{
+	if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+		   __NR_getpid) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
+	   (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL) < 0) ||
+	   (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
+		printk("ptproxy: couldn't cancel syscall: errno = %d\n", 
+		       errno);
+}
+
+void syscall_set_result(pid_t pid, long result)
+{
+	ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result);
+}
+
+void syscall_continue(pid_t pid)
+{
+	ptrace(PTRACE_SYSCALL, pid, 0, 0);
+}
+
+int syscall_pause(pid_t pid) 
+{
+	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
+		printk("syscall_change - ptrace failed, errno = %d\n", errno);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/sysdep.h linux-2.4.19-pre5-mjc/arch/um/ptproxy/sysdep.h
--- linux/arch/um/ptproxy/sysdep.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/sysdep.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,25 @@
+/**********************************************************************
+sysdep.h
+
+Copyright (C) 1999 Lars Brinkhoff.
+Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+See the file COPYING for licensing terms and conditions.
+**********************************************************************/
+
+extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, 
+		       long *arg4, long *arg5);
+extern void syscall_cancel (pid_t pid, long result);
+extern void syscall_set_result (pid_t pid, long result);
+extern void syscall_continue (pid_t pid);
+extern int syscall_pause(pid_t pid);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/wait.c linux-2.4.19-pre5-mjc/arch/um/ptproxy/wait.c
--- linux/arch/um/ptproxy/wait.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/wait.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,57 @@
+/**********************************************************************
+wait.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+**********************************************************************/
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+
+#include <asm/ptrace.h>
+#include "sysdep/ptrace.h"
+
+int proxy_wait_return (struct debugger *debugger, pid_t unused)
+{
+	debugger->waiting = 0;
+
+	if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
+		debugger_cancelled_return(debugger, -ECHILD);
+		return(0);
+	}
+
+	if(debugger->debugee->zombie && debugger->debugee->event)
+		debugger->debugee->died = 1;
+
+	if(debugger->debugee->event){
+		debugger->debugee->event = 0;
+		ptrace(PTRACE_POKEDATA, debugger->pid,
+		       debugger->wait_status_ptr, 
+		       debugger->debugee->wait_status);
+		/* if (wait4)
+		   ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
+		debugger_cancelled_return(debugger, debugger->debugee->pid);
+		return(0);
+	}
+
+	/* pause will return -EINTR, which happens to be right for wait */
+	debugger_normal_return(debugger, -1);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/ptproxy/wait.h linux-2.4.19-pre5-mjc/arch/um/ptproxy/wait.h
--- linux/arch/um/ptproxy/wait.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/ptproxy/wait.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,8 @@
+/**********************************************************************
+wait.h
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+extern int proxy_wait_return (struct debugger *debugger, pid_t unused);
diff -Nru linux/arch/um/sys-i386/Makefile linux-2.4.19-pre5-mjc/arch/um/sys-i386/Makefile
--- linux/arch/um/sys-i386/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,45 @@
+OBJ = sys.o
+
+OBJS = bugs.o checksum.o ldt.o old-checksum.o ptrace.o ptrace_user.o \
+	semaphore.o sigcontext.o sigcontext_kern.o syscalls.o sysrq.o
+export-objs = ksyms.o
+
+USER_OBJS = bugs.o ldt.o ptrace_user.o sigcontext.o 
+
+SYMLINKS = semaphore.c old-checksum.c checksum.S
+
+all: $(OBJ)
+
+$(OBJ): $(OBJS) $(export-objs)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+checksum.S old-checksum.c: 
+	-rm -f $@
+	-ln -s $(TOPDIR)/arch/i386/lib/$@ $@
+
+semaphore.c:
+	-rm -f $@
+	-ln -s $(TOPDIR)/arch/i386/kernel/$@ $@
+
+clean:
+	rm -f $(OBJS) $(export-objs)
+
+fastdep:
+
+archmrproper:
+	rm -f $(SYMLINKS)
+
+archclean:
+	rm -f link.ld
+	@$(MAKEBOOT) clean
+
+archdep:
+	@$(MAKEBOOT) dep
+
+modules:
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/sys-i386/bugs.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/bugs.c
--- linux/arch/um/sys-i386/bugs.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/bugs.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,142 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/signal.h>
+#include "kern_util.h"
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "task.h"
+
+#define MAXTOKEN 64
+
+int have_cmov = -1;
+
+static char token(int fd, char *buf, int len, char stop)
+{
+	int n;
+	char *ptr, *end, c;
+
+	ptr = buf;
+	end = &buf[len];
+	do {
+		n = read(fd, ptr, sizeof(*ptr));
+		c = *ptr++;
+		if(n != sizeof(*ptr)){
+			printk("Reading /proc/cpuinfo failed, "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+	} while((c != '\n') && (c != stop) && (ptr < end));
+
+	if(ptr == end){
+		printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
+		return(-1);
+	}
+	*(ptr - 1) = '\0';
+	return(c);
+}
+
+void arch_check_bugs(void)
+{
+	char buf[MAXTOKEN], c;
+	int fd, len = sizeof(buf)/sizeof(buf[0]), n;
+
+	printk("Checking for host processor cmov support...");
+
+	fd = open("/proc/cpuinfo", O_RDONLY);
+	if(fd < 0){
+		printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno);
+		return;
+	}
+
+	buf[len - 1] = '\0';
+	while(1){
+		c = token(fd, buf, len - 1, ':');
+		if(c < 0) goto out;
+		else if(c != ':'){
+			printk("Failed to find ':' in /proc/cpuinfo\n");
+			goto out;
+		}
+
+		if(!strncmp(buf, "flags", strlen("flags"))) break;
+
+		do {
+			n = read(fd, &c, sizeof(c));
+			if(n != sizeof(c)){
+				printk("Failed to find newline in "
+				       "/proc/cpuinfo, n = %d, errno = %d\n",
+				       n, errno);
+				goto out;
+			}
+		} while(c != '\n');
+	}
+
+	c = token(fd, buf, len - 1, ' ');
+	if(c < 0) goto out;
+	else if(c != ' '){
+		printk("Failed to find ':' in /proc/cpuinfo\n");
+		goto out;
+	}
+
+	while(1){
+		c = token(fd, buf, len - 1, ' ');
+		if(c < 0) goto out;
+		else if(c == '\n') break;
+
+		if(!strcmp(buf, "cmov")){
+			have_cmov = 1;
+			goto out;
+		}
+	}
+	have_cmov = 0;
+ out:
+	if(have_cmov == 0) printk("No\n");
+	else if(have_cmov == 1) printk("Yes\n");
+	close(fd);
+	return;
+}
+
+int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+{
+	unsigned long ip;
+
+	/* This is testing for a cmov (0x0f 0x4x) instruction causing a
+	 * SIGILL in init.
+	 */
+	if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
+
+	ip = UPT_IP(regs);
+	if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
+		return(0);
+
+	if(have_cmov == 0)
+		panic("SIGILL caused by cmov, which this processor doesn't "
+		      "implement, boot a filesystem compiled for older "
+		      "processors");
+	else if(have_cmov == 1)
+		panic("SIGILL caused by cmov, which this processor claims to "
+		      "implement");
+	else if(have_cmov == -1)
+		panic("SIGILL caused by cmov, couldn't tell if this processor "
+		      "implements it, boot a filesystem compiled for older "
+		      "processors");
+	else panic("Bad value for have_cmov (%d)", have_cmov);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/ksyms.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/ksyms.c
--- linux/arch/um/sys-i386/ksyms.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/ksyms.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,16 @@
+#include "linux/module.h"
+#include "linux/in6.h"
+#include "linux/rwsem.h"
+#include "asm/byteorder.h"
+#include "asm/semaphore.h"
+#include "asm/uaccess.h"
+#include "asm/checksum.h"
+#include "asm/errno.h"
+
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__down_failed_trylock);
+EXPORT_SYMBOL(__up_wakeup);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_generic);
diff -Nru linux/arch/um/sys-i386/ldt.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/ldt.c
--- linux/arch/um/sys-i386/ldt.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/ldt.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
+
+int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+       return modify_ldt(func, ptr, bytecount);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/ptrace.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/ptrace.c
--- linux/arch/um/sys-i386/ptrace.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/ptrace.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,78 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+#include "sysdep/sc.h"
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x00044dd5
+
+int putreg(struct task_struct *child, int regno, unsigned long value)
+{
+	regno >>= 2;
+	switch (regno) {
+	case FS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		PT_REGS_FS(&child->thread.regs) = value;
+		return 0;
+	case GS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		PT_REGS_GS(&child->thread.regs) = value;
+		return 0;
+	case DS:
+	case ES:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case SS:
+	case CS:
+		if ((value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case EFL:
+		value &= FLAG_MASK;
+		value |= PT_REGS_EFLAGS(&child->thread.regs);
+		break;
+	}
+	PT_REGS_SET(&child->thread.regs, regno, value);
+	return 0;
+}
+
+unsigned long getreg(struct task_struct *child, int regno)
+{
+	unsigned long retval = ~0UL;
+
+	regno >>= 2;
+	switch (regno) {
+	case FS:
+	case GS:
+	case DS:
+	case ES:
+	case SS:
+	case CS:
+		retval = 0xffff;
+		/* fall through */
+	default:
+		retval &= PT_REG(&child->thread.regs, regno);
+	}
+	return retval;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/ptrace_user.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/ptrace_user.c
--- linux/arch/um/sys-i386/ptrace_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/ptrace_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,23 @@
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+int ptrace_getregs(long pid, unsigned long *regs_out)
+{
+	return(ptrace(PTRACE_GETREGS, pid, 0, regs_out));
+}
+
+int ptrace_setregs(long pid, unsigned long *regs)
+{
+	return(ptrace(PTRACE_SETREGS, pid, 0, regs));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/sigcontext.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/sigcontext.c
--- linux/arch/um/sys-i386/sigcontext.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/sigcontext.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,82 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "kern_util.h"
+#include "frame.h"
+
+int sc_size(void *data)
+{
+	struct arch_frame_data *arch = data;
+
+	return(sizeof(struct sigcontext) + arch->fpstate_size);
+}
+
+int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data)
+{
+	struct arch_frame_data *arch = data;
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	struct _fpstate *to_fp, *from_fp;
+	int err;
+
+	to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
+	from_fp = from->fpstate;
+	err = copy_to_user_proc(to, from, sizeof(*to));
+	if(from_fp != NULL){
+		err |= copy_to_user_proc(&to->fpstate, &to_fp,
+					 sizeof(to->fpstate));
+		err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
+	}
+	return(err);
+}
+
+int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data)
+{
+	struct arch_frame_data *arch = data;
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	struct _fpstate *to_fp, *from_fp;
+	unsigned long sigs;
+	int err;
+
+	to_fp = to->fpstate;
+	from_fp = from->fpstate;
+	sigs = to->oldmask;
+	err = copy_from_user_proc(to, from, sizeof(*to));
+	to->oldmask = sigs;
+	if(to_fp != NULL)
+		err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
+	return(err);
+}
+
+void sc_to_sc(void *to_ptr, void *from_ptr)
+{
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	int size = sizeof(*to) + signal_frame_sc.arch.fpstate_size;
+
+	memcpy(to, from, size);
+	if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1);
+}
+
+unsigned long *sc_sigmask(void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+
+	return(&sc->oldmask);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/sigcontext_kern.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/sigcontext_kern.c
--- linux/arch/um/sys-i386/sigcontext_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/sigcontext_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,45 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/uaccess.h"
+#include "asm/signal.h"
+#include "sigcontext.h"
+
+int copy_sigmask_from_user(sigset_t *mask, void *sc, 
+			   struct arch_signal_context *arch)
+{
+	int err = 0;
+
+	err |= copy_from_user(&mask->sig[0], arch->extrasigs, 
+			      sizeof(arch->extrasigs));
+	if(sc != NULL)
+		err |= copy_from_user(&mask->sig[0], sc_sigmask(sc), 
+				      sizeof(mask->sig[0]));
+	return(err);
+}
+
+int copy_sigmask_to_user(sigset_t *mask, void *sc, 
+			 struct arch_signal_context *arch)
+{
+	int err = 0;
+
+	if(sc != NULL)
+		err |= copy_to_user(sc_sigmask(sc), &mask->sig[0], 
+				    sizeof(mask->sig[0]));
+	err |= copy_to_user(arch->extrasigs, &mask->sig[0], 
+			    sizeof(arch->extrasigs));
+	return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/syscalls.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/syscalls.c
--- linux/arch/um/sys-i386/syscalls.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/syscalls.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,68 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+extern int old_mmap(unsigned long addr, unsigned long len,
+		    unsigned long prot, unsigned long flags,
+		    unsigned long fd, unsigned long offset);
+
+int old_mmap_i386(struct mmap_arg_struct *arg)
+{
+	struct mmap_arg_struct a;
+	int err = -EFAULT;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		goto out;
+
+	err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+ out:
+	return err;
+}
+
+struct sel_arg_struct {
+	unsigned long n;
+	fd_set *inp, *outp, *exp;
+	struct timeval *tvp;
+};
+
+int old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	/* sys_select() does the appropriate kernel locking */
+	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-i386/sysrq.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/sysrq.c
--- linux/arch/um/sys-i386/sysrq.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/sysrq.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,30 @@
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs *regs)
+{
+        printk("\n");
+        printk("EIP: %04lx:[<%08lx>] CPU: %d %s", 
+	       0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
+	       smp_processor_id(), print_tainted());
+        if (PT_REGS_CS(regs) & 3)
+                printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
+		       PT_REGS_SP(regs));
+        printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
+	       print_tainted());
+        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
+	       PT_REGS_ECX(regs), 
+	       PT_REGS_EDX(regs));
+        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+	       PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
+	       PT_REGS_EBP(regs));
+        printk(" DS: %04lx ES: %04lx\n",
+	       0xffff & PT_REGS_DS(regs), 
+	       0xffff & PT_REGS_ES(regs));
+
+        show_trace((unsigned long *) PT_REGS_SP(regs));
+}
diff -Nru linux/arch/um/sys-i386/util/Makefile linux-2.4.19-pre5-mjc/arch/um/sys-i386/util/Makefile
--- linux/arch/um/sys-i386/util/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/util/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,6 @@
+all : mk_sc
+
+mk_sc : mk_sc.c
+
+clean :
+	$(RM) mk_sc
diff -Nru linux/arch/um/sys-i386/util/mk_sc.c linux-2.4.19-pre5-mjc/arch/um/sys-i386/util/mk_sc.c
--- linux/arch/um/sys-i386/util/mk_sc.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-i386/util/mk_sc.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <signal.h>
+#include <linux/stddef.h>
+
+#define OFFSET(name, field) \
+  printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
+	 offsetof(struct sigcontext, field))
+
+int main(int argc, char **argv)
+{
+  OFFSET("SC_IP", eip);
+  OFFSET("SC_SP", esp);
+  OFFSET("SC_FS", fs);
+  OFFSET("SC_GS", gs);
+  OFFSET("SC_DS", ds);
+  OFFSET("SC_ES", es);
+  OFFSET("SC_SS", ss);
+  OFFSET("SC_CS", cs);
+  OFFSET("SC_EFLAGS", eflags);
+  OFFSET("SC_EAX", eax);
+  OFFSET("SC_EBX", ebx);
+  OFFSET("SC_ECX", ecx);
+  OFFSET("SC_EDX", edx);
+  OFFSET("SC_EDI", edi);
+  OFFSET("SC_ESI", esi);
+  OFFSET("SC_EBP", ebp);
+  OFFSET("SC_TRAPNO", trapno);
+  OFFSET("SC_ERR", err);
+  OFFSET("SC_CR2", cr2);
+  return(0);
+}
diff -Nru linux/arch/um/sys-ia64/Makefile linux-2.4.19-pre5-mjc/arch/um/sys-ia64/Makefile
--- linux/arch/um/sys-ia64/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ia64/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,26 @@
+OBJ = sys.o
+
+OBJS =
+
+all: $(OBJ)
+
+$(OBJ): $(OBJS)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+clean:
+	rm -f $(OBJS)
+
+fastdep:
+
+archmrproper:
+
+archclean:
+	rm -f link.ld
+	@$(MAKEBOOT) clean
+
+archdep:
+	@$(MAKEBOOT) dep
+
+modules:
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/sys-ppc/Makefile linux-2.4.19-pre5-mjc/arch/um/sys-ppc/Makefile
--- linux/arch/um/sys-ppc/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,78 @@
+OBJ = sys.o
+
+.S.o:
+	$(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+
+OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
+	ptrace_user.o sysrq.o
+
+EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel
+
+all: $(OBJ)
+
+$(OBJ): $(OBJS)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+
+ptrace_user.o: ptrace_user.c
+	$(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+sigcontext.o: sigcontext.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+semaphore.c:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+checksum.S:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
+
+mk_defs.c:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+ppc_defs.head:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+ppc_defs.h: mk_defs.c ppc_defs.head \
+		$(TOPDIR)/include/asm-ppc/mmu.h \
+		$(TOPDIR)/include/asm-ppc/processor.h \
+		$(TOPDIR)/include/asm-ppc/pgtable.h \
+		$(TOPDIR)/include/asm-ppc/ptrace.h
+#	$(CC) $(CFLAGS) -S mk_defs.c
+	cp ppc_defs.head ppc_defs.h
+# for bk, this way we can write to the file even if it's not checked out
+	echo '#define THREAD 608' >> ppc_defs.h
+	echo '#define PT_REGS 8' >> ppc_defs.h
+	echo '#define CLONE_VM 256' >> ppc_defs.h
+#	chmod u+w ppc_defs.h
+#	grep '^#define' mk_defs.s >> ppc_defs.h
+#	rm mk_defs.s
+
+# the asm link is horrible, and breaks the other targets.  This is also
+# not going to work with parallel makes.
+
+checksum.o: checksum.S
+	rm -f asm
+	ln -s $(TOPDIR)/include/asm-ppc asm
+	$(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+	rm -f asm
+
+misc.o: misc.S ppc_defs.h
+	rm -f asm
+	ln -s $(TOPDIR)/include/asm-ppc asm
+	$(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+	rm -f asm
+
+clean:
+	rm -f $(OBJS)
+	rm -f ppc_defs.h
+	rm -f checksum.S semaphore.c mk_defs.c
+
+fastdep:
+
+modules:
+
+include $(TOPDIR)/Rules.make
diff -Nru linux/arch/um/sys-ppc/misc.S linux-2.4.19-pre5-mjc/arch/um/sys-ppc/misc.S
--- linux/arch/um/sys-ppc/misc.S	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/misc.S	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,116 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * A couple of functions stolen from arch/ppc/kernel/misc.S for UML
+ * by Chris Emerson.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include "ppc_asm.h"
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
+#define CACHE_LINE_SIZE		16
+#define LG_CACHE_LINE_SIZE	4
+#define MAX_COPY_PREFETCH	1
+#elif !defined(CONFIG_PPC64BRIDGE)
+#define CACHE_LINE_SIZE		32
+#define LG_CACHE_LINE_SIZE	5
+#define MAX_COPY_PREFETCH	4
+#else
+#define CACHE_LINE_SIZE		128
+#define LG_CACHE_LINE_SIZE	7
+#define MAX_COPY_PREFETCH	1
+#endif /* CONFIG_4xx || CONFIG_8xx */
+
+	.text
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced).  This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+#ifdef CONFIG_8xx
+	li	r4, 0
+1:	stw	r4, 0(r3)
+	stw	r4, 4(r3)
+	stw	r4, 8(r3)
+	stw	r4, 12(r3)
+#else
+1:	dcbz	0,r3
+#endif
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	blr
+
+/*
+ * Copy a whole page.  We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache).  This requires that the destination
+ * is cacheable.
+ */
+#define COPY_16_BYTES		\
+	lwz	r6,4(r4);	\
+	lwz	r7,8(r4);	\
+	lwz	r8,12(r4);	\
+	lwzu	r9,16(r4);	\
+	stw	r6,4(r3);	\
+	stw	r7,8(r3);	\
+	stw	r8,12(r3);	\
+	stwu	r9,16(r3)
+
+_GLOBAL(copy_page)
+	addi	r3,r3,-4
+	addi	r4,r4,-4
+	li	r5,4
+
+#ifndef CONFIG_8xx
+#if MAX_COPY_PREFETCH > 1
+	li	r0,MAX_COPY_PREFETCH
+	li	r11,4
+	mtctr	r0
+11:	dcbt	r11,r4
+	addi	r11,r11,CACHE_LINE_SIZE
+	bdnz	11b
+#else /* MAX_COPY_PREFETCH == 1 */
+	dcbt	r5,r4
+	li	r11,CACHE_LINE_SIZE+4
+#endif /* MAX_COPY_PREFETCH */
+#endif /* CONFIG_8xx */
+
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+1:
+#ifndef CONFIG_8xx
+	dcbt	r11,r4
+	dcbz	r5,r3
+#endif
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 32
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 64
+	COPY_16_BYTES
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 128
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+#endif
+#endif
+#endif
+	bdnz	1b
+	blr
diff -Nru linux/arch/um/sys-ppc/miscthings.c linux-2.4.19-pre5-mjc/arch/um/sys-ppc/miscthings.c
--- linux/arch/um/sys-ppc/miscthings.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/miscthings.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,56 @@
+#include "linux/threads.h"
+#include "linux/stddef.h"  // for NULL
+#include "linux/elf.h"  // for AT_NULL
+
+/* unsigned int local_bh_count[NR_CPUS]; */
+unsigned long isa_io_base = 0;
+
+/* The following function nicked from arch/ppc/kernel/process.c and
+ * adapted slightly */
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+void shove_aux_table(unsigned long sp)
+{
+	int argc;
+	char *p;
+	unsigned long e;
+	unsigned long aux_start, offset;
+
+	argc = *(int *)sp;
+	sp += sizeof(int) + (argc + 1) * sizeof(char *);
+	/* skip over the environment pointers */
+	do {
+		p = *(char **)sp;
+		sp += sizeof(char *);
+	} while (p != NULL);
+	aux_start = sp;
+	/* skip to the end of the auxiliary table */
+	do {
+		e = *(unsigned long *)sp;
+		sp += 2 * sizeof(unsigned long);
+	} while (e != AT_NULL);
+	offset = ((aux_start + 15) & ~15) - aux_start;
+	if (offset != 0) {
+		do {
+			sp -= sizeof(unsigned long);
+			e = *(unsigned long *)sp;
+			*(unsigned long *)(sp + offset) = e;
+		} while (sp > aux_start);
+	}
+}
+/* END stuff taken from arch/ppc/kernel/process.c */
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-ppc/ptrace.c linux-2.4.19-pre5-mjc/arch/um/sys-ppc/ptrace.c
--- linux/arch/um/sys-ppc/ptrace.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/ptrace.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,28 @@
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+
+int putreg(struct task_struct *child, unsigned long regno, 
+		  unsigned long value)
+{
+	child->thread.process_regs.regs[regno >> 2] = value;
+	return 0;
+}
+
+unsigned long getreg(struct task_struct *child, unsigned long regno)
+{
+	unsigned long retval = ~0UL;
+
+	retval &= child->thread.process_regs.regs[regno >> 2];
+	return retval;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-ppc/ptrace_user.c linux-2.4.19-pre5-mjc/arch/um/sys-ppc/ptrace_user.c
--- linux/arch/um/sys-ppc/ptrace_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/ptrace_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,40 @@
+#include <sys/ptrace.h>
+#include <errno.h>
+#include <asm/ptrace.h>
+#include "sysdep/ptrace.h"
+
+int ptrace_getregs(long pid, unsigned long *regs_out)
+{
+    int i;
+    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
+	errno = 0;
+	regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0);
+	if (errno) {
+	    return -errno;
+	}
+    }
+    return 0;
+}
+
+int ptrace_setregs(long pid, unsigned long *regs_in)
+{
+    int i;
+    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
+	if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
+	    if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) {
+		return -errno;
+	    }
+	}
+    }
+    return 0;
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-ppc/sigcontext.c linux-2.4.19-pre5-mjc/arch/um/sys-ppc/sigcontext.c
--- linux/arch/um/sys-ppc/sigcontext.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/sigcontext.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,15 @@
+#include "asm/ptrace.h"
+#include "asm/sigcontext.h"
+#include "sysdep/ptrace.h"
+#include "user_util.h"
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/sys-ppc/sysrq.c linux-2.4.19-pre5-mjc/arch/um/sys-ppc/sysrq.c
--- linux/arch/um/sys-ppc/sysrq.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/sys-ppc/sysrq.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "asm/ptrace.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs_subarch *regs)
+{
+	printk("\n");
+	printk("show_regs(): insert regs here.\n");
+#if 0
+        printk("\n");
+        printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip,
+	       smp_processor_id());
+        if (regs->xcs & 3)
+                printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp);
+        printk(" EFLAGS: %08lx\n", regs->eflags);
+        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+                regs->eax, regs->ebx, regs->ecx, regs->edx);
+        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+                regs->esi, regs->edi, regs->ebp);
+        printk(" DS: %04x ES: %04x\n",
+                0xffff & regs->xds, 0xffff & regs->xes);
+#endif
+
+        show_trace(&regs->gpr[1]);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/arch/um/util/Makefile linux-2.4.19-pre5-mjc/arch/um/util/Makefile
--- linux/arch/um/util/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/util/Makefile	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,13 @@
+all : mk_task
+
+mk_task : mk_task_user.o mk_task_kern.o
+	$(CC) -o mk_task mk_task_user.o mk_task_kern.o
+
+mk_task_user.o : mk_task_user.c
+	$(CC) -c $< 
+
+mk_task_kern.o : mk_task_kern.c
+	$(CC) $(CFLAGS) -c $< 
+
+clean :
+	$(RM) mk_task *.o *~
diff -Nru linux/arch/um/util/mk_task_kern.c linux-2.4.19-pre5-mjc/arch/um/util/mk_task_kern.c
--- linux/arch/um/util/mk_task_kern.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/util/mk_task_kern.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,17 @@
+#include "linux/sched.h"
+#include "linux/stddef.h"
+
+extern void print(char *name, char *type, int offset);
+extern void print_ptr(char *name, char *type, int offset);
+extern void print_head(void);
+extern void print_tail(void);
+
+int main(int argc, char **argv)
+{
+  print_head();
+  print_ptr("TASK_REGS", "struct uml_pt_regs", 
+	    offsetof(struct task_struct, thread.regs));
+  print("TASK_PID", "int", offsetof(struct task_struct, pid));
+  print_tail();
+  return(0);
+}
diff -Nru linux/arch/um/util/mk_task_user.c linux-2.4.19-pre5-mjc/arch/um/util/mk_task_user.c
--- linux/arch/um/util/mk_task_user.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/arch/um/util/mk_task_user.c	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+void print(char *name, char *type, int offset)
+{
+  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+void print_ptr(char *name, char *type, int offset)
+{
+  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+void print_head(void)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_task\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __TASK_H\n");
+  printf("#define __TASK_H\n");
+  printf("\n");
+}
+
+void print_tail(void)
+{
+  printf("\n");
+  printf("#endif\n");
+}
diff -Nru linux/drivers/char/Makefile linux-2.4.19-pre5-mjc/drivers/char/Makefile
--- linux/drivers/char/Makefile	Sat Apr  6 15:26:34 2002
+++ linux-2.4.19-pre5-mjc/drivers/char/Makefile	Sat Apr  6 16:07:15 2002
@@ -81,6 +81,12 @@
   endif
 endif
 
+ifeq ($(ARCH),um)
+  KEYMAP   =
+  KEYBD    =
+  CONSOLE  =
+endif
+
 ifeq ($(ARCH),sh)
   KEYMAP   =
   KEYBD    =
diff -Nru linux/fs/fcntl.c linux-2.4.19-pre5-mjc/fs/fcntl.c
--- linux/fs/fcntl.c	Sat Apr  6 15:26:44 2002
+++ linux-2.4.19-pre5-mjc/fs/fcntl.c	Sat Apr  6 16:07:15 2002
@@ -250,6 +250,8 @@
 	return 0;
 }
 
+static rwlock_t fasync_lock = RW_LOCK_UNLOCKED;
+
 static long do_fcntl(unsigned int fd, unsigned int cmd,
 		     unsigned long arg, struct file * filp)
 {
@@ -295,14 +297,14 @@
 			err = filp->f_owner.pid;
 			break;
 		case F_SETOWN:
-			lock_kernel();
+		        write_lock_irq(&fasync_lock);
 			filp->f_owner.pid = arg;
 			filp->f_owner.uid = current->uid;
 			filp->f_owner.euid = current->euid;
 			err = 0;
 			if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
 				err = sock_fcntl (filp, F_SETOWN, arg);
-			unlock_kernel();
+			write_unlock_irq(&fasync_lock);
 			break;
 		case F_GETSIG:
 			err = filp->f_owner.signum;
@@ -454,7 +456,6 @@
 	read_unlock(&tasklist_lock);
 }
 
-static rwlock_t fasync_lock = RW_LOCK_UNLOCKED;
 static kmem_cache_t *fasync_cache;
 
 /*
diff -Nru linux/include/asm-i386/hardirq.h linux-2.4.19-pre5-mjc/include/asm-i386/hardirq.h
--- linux/include/asm-i386/hardirq.h	Sat Apr  6 15:31:20 2002
+++ linux-2.4.19-pre5-mjc/include/asm-i386/hardirq.h	Sat Apr  6 16:07:15 2002
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/irq.h>
+#include <asm/processor.h>		/* for cpu_relax */
 
 /* assembly code in softirq.h is sensitive to the offsets of these fields */
 typedef struct {
diff -Nru linux/include/asm-um/a.out.h linux-2.4.19-pre5-mjc/include/asm-um/a.out.h
--- linux/include/asm-um/a.out.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/a.out.h	Sat Apr  6 16:07:15 2002
@@ -0,0 +1,18 @@
+#ifndef __UM_A_OUT_H
+#define __UM_A_OUT_H
+
+#include "asm/arch/a.out.h"
+
+#undef STACK_TOP
+
+extern unsigned long stacksizelim;
+
+extern unsigned long host_task_size;
+
+extern int honeypot;
+
+#define STACK_ROOM (stacksizelim)
+
+#define STACK_TOP (honeypot ? host_task_size : task_size)
+
+#endif
diff -Nru linux/include/asm-um/arch-signal-i386.h linux-2.4.19-pre5-mjc/include/asm-um/arch-signal-i386.h
--- linux/include/asm-um/arch-signal-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/arch-signal-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ARCH_SIGNAL_I386_H
+#define __UM_ARCH_SIGNAL_I386_H
+
+struct arch_signal_context {
+	unsigned long extrasigs[_NSIG_WORDS];
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/archparam-i386.h linux-2.4.19-pre5-mjc/include/asm-um/archparam-i386.h
--- linux/include/asm-um/archparam-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/archparam-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,81 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ARCHPARAM_I386_H
+#define __UM_ARCHPARAM_I386_H
+
+/********* Bits for asm-um/elf.h ************/
+
+#include "user.h"
+
+#define ELF_PLATFORM "i586"
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef int elf_fpregset_t;
+
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define ELF_PLAT_INIT(regs) do { \
+	PT_REGS_EBX(regs) = 0; \
+	PT_REGS_ECX(regs) = 0; \
+	PT_REGS_EDX(regs) = 0; \
+	PT_REGS_ESI(regs) = 0; \
+	PT_REGS_EDI(regs) = 0; \
+	PT_REGS_EBP(regs) = 0; \
+	PT_REGS_EAX(regs) = 0; \
+} while(0)
+
+/* Shamelessly stolen from include/asm-i386/elf.h */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do {	\
+	pr_reg[0] = PT_REGS_EBX(regs);		\
+	pr_reg[1] = PT_REGS_ECX(regs);		\
+	pr_reg[2] = PT_REGS_EDX(regs);		\
+	pr_reg[3] = PT_REGS_ESI(regs);		\
+	pr_reg[4] = PT_REGS_EDI(regs);		\
+	pr_reg[5] = PT_REGS_EBP(regs);		\
+	pr_reg[6] = PT_REGS_EAX(regs);		\
+	pr_reg[7] = PT_REGS_DS(regs);		\
+	pr_reg[8] = PT_REGS_ES(regs);		\
+	/* fake once used fs and gs selectors? */	\
+	pr_reg[9] = PT_REGS_DS(regs);		\
+	pr_reg[10] = PT_REGS_DS(regs);		\
+	pr_reg[11] = regs->regs.syscall;	\
+	pr_reg[12] = PT_REGS_IP(regs);		\
+	pr_reg[13] = PT_REGS_CS(regs);		\
+	pr_reg[14] = PT_REGS_EFLAGS(regs);	\
+	pr_reg[15] = PT_REGS_SP(regs);		\
+	pr_reg[16] = PT_REGS_SS(regs);		\
+} while(0);
+
+/********* Bits for asm-um/delay.h **********/
+
+typedef unsigned long um_udelay_t;
+
+/********* Nothing for asm-um/hardirq.h **********/
+
+/********* Nothing for asm-um/hw_irq.h **********/
+
+/********* Nothing for asm-um/string.h **********/
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/archparam-ppc.h linux-2.4.19-pre5-mjc/include/asm-um/archparam-ppc.h
--- linux/include/asm-um/archparam-ppc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/archparam-ppc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,41 @@
+#ifndef __UM_ARCHPARAM_PPC_H
+#define __UM_ARCHPARAM_PPC_H
+
+/********* Bits for asm-um/elf.h ************/
+
+#define ELF_PLATFORM (0)
+
+#define ELF_ET_DYN_BASE (0x08000000)
+
+/* the following stolen from asm-ppc/elf.h */
+#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
+#define ELF_NFPREG	33	/* includes fpscr */
+/* General registers */
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Floating point registers */
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_DATA        ELFDATA2MSB
+#define ELF_ARCH	EM_PPC
+
+/********* Bits for asm-um/delay.h **********/
+
+typedef unsigned int um_udelay_t;
+
+/********* Bits for asm-um/hw_irq.h **********/
+
+struct hw_interrupt_type;
+
+/********* Bits for asm-um/hardirq.h **********/
+
+#define irq_enter(cpu, irq) hardirq_enter(cpu)
+#define irq_exit(cpu, irq) hardirq_exit(cpu)
+
+/********* Bits for asm-um/string.h **********/
+
+#define __HAVE_ARCH_STRRCHR
+
+#endif
diff -Nru linux/include/asm-um/atomic.h linux-2.4.19-pre5-mjc/include/asm-um/atomic.h
--- linux/include/asm-um/atomic.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/atomic.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_ATOMIC_H
+#define __UM_ATOMIC_H
+
+#include "asm/arch/atomic.h"
+
+#endif
diff -Nru linux/include/asm-um/bitops.h linux-2.4.19-pre5-mjc/include/asm-um/bitops.h
--- linux/include/asm-um/bitops.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/bitops.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BITOPS_H
+#define __UM_BITOPS_H
+
+#include "asm/arch/bitops.h"
+
+#endif
diff -Nru linux/include/asm-um/boot.h linux-2.4.19-pre5-mjc/include/asm-um/boot.h
--- linux/include/asm-um/boot.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/boot.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BOOT_H
+#define __UM_BOOT_H
+
+#include "asm/arch/boot.h"
+
+#endif
diff -Nru linux/include/asm-um/bugs.h linux-2.4.19-pre5-mjc/include/asm-um/bugs.h
--- linux/include/asm-um/bugs.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/bugs.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BUGS_H
+#define __UM_BUGS_H
+
+void check_bugs(void);
+
+#endif
diff -Nru linux/include/asm-um/byteorder.h linux-2.4.19-pre5-mjc/include/asm-um/byteorder.h
--- linux/include/asm-um/byteorder.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/byteorder.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BYTEORDER_H
+#define __UM_BYTEORDER_H
+
+#include "asm/arch/byteorder.h"
+
+#endif
diff -Nru linux/include/asm-um/cache.h linux-2.4.19-pre5-mjc/include/asm-um/cache.h
--- linux/include/asm-um/cache.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/cache.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_CACHE_H
+#define __UM_CACHE_H
+
+#define        L1_CACHE_BYTES  32
+
+#endif
diff -Nru linux/include/asm-um/checksum.h linux-2.4.19-pre5-mjc/include/asm-um/checksum.h
--- linux/include/asm-um/checksum.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/checksum.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_CHECKSUM_H
+#define __UM_CHECKSUM_H
+
+#include "asm/arch/checksum.h"
+
+#endif
diff -Nru linux/include/asm-um/cobalt.h linux-2.4.19-pre5-mjc/include/asm-um/cobalt.h
--- linux/include/asm-um/cobalt.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/cobalt.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_COBALT_H
+#define __UM_COBALT_H
+
+#include "asm/arch/cobalt.h"
+
+#endif
diff -Nru linux/include/asm-um/current.h linux-2.4.19-pre5-mjc/include/asm-um/current.h
--- linux/include/asm-um/current.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/current.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,33 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_CURRENT_H
+#define __UM_CURRENT_H
+
+#ifndef __ASSEMBLY__
+
+#include "linux/config.h"
+#include "asm/page.h"
+
+struct task_struct;
+
+#define CURRENT_TASK(dummy) (((unsigned long) &dummy) & (PAGE_MASK << 2))
+
+#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); })
+
+#endif /* __ASSEMBLY__ */
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/delay.h linux-2.4.19-pre5-mjc/include/asm-um/delay.h
--- linux/include/asm-um/delay.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/delay.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,7 @@
+#ifndef __UM_DELAY_H
+#define __UM_DELAY_H
+
+#include "asm/arch/delay.h"
+#include "asm/archparam.h"
+
+#endif
diff -Nru linux/include/asm-um/desc.h linux-2.4.19-pre5-mjc/include/asm-um/desc.h
--- linux/include/asm-um/desc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/desc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_DESC_H
+#define __UM_DESC_H
+
+#include "asm/arch/desc.h"
+
+#endif
diff -Nru linux/include/asm-um/div64.h linux-2.4.19-pre5-mjc/include/asm-um/div64.h
--- linux/include/asm-um/div64.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/div64.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef _UM_DIV64_H
+#define _UM_DIV64_H
+
+#include "asm/arch/div64.h"
+
+#endif
diff -Nru linux/include/asm-um/dma.h linux-2.4.19-pre5-mjc/include/asm-um/dma.h
--- linux/include/asm-um/dma.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/dma.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_DMA_H
+#define __UM_DMA_H
+
+#include "asm/arch/dma.h"
+
+#undef MAX_DMA_ADDRESS
+
+#define MAX_DMA_ADDRESS (uml_physmem)
+
+#endif
diff -Nru linux/include/asm-um/elf.h linux-2.4.19-pre5-mjc/include/asm-um/elf.h
--- linux/include/asm-um/elf.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/elf.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,18 @@
+#ifndef __UM_ELF_H
+#define __UM_ELF_H
+
+#include "asm/archparam.h"
+
+#define ELF_HWCAP (0)
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+#define ELF_EXEC_PAGESIZE 4096
+
+#define elf_check_arch(x) (1)
+
+#define ELF_CLASS ELFCLASS32
+
+#define USE_ELF_CORE_DUMP
+
+#endif
diff -Nru linux/include/asm-um/errno.h linux-2.4.19-pre5-mjc/include/asm-um/errno.h
--- linux/include/asm-um/errno.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/errno.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_ERRNO_H
+#define __UM_ERRNO_H
+
+#include "asm/arch/errno.h"
+
+#endif
diff -Nru linux/include/asm-um/fcntl.h linux-2.4.19-pre5-mjc/include/asm-um/fcntl.h
--- linux/include/asm-um/fcntl.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/fcntl.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_FCNTL_H
+#define __UM_FCNTL_H
+
+#include "asm/arch/fcntl.h"
+
+#endif
diff -Nru linux/include/asm-um/fixmap.h linux-2.4.19-pre5-mjc/include/asm-um/fixmap.h
--- linux/include/asm-um/fixmap.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/fixmap.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_FIXMAP_H
+#define __UM_FIXMAP_H
+
+#define FIXADDR_START (0xffff0000)
+
+#endif
diff -Nru linux/include/asm-um/floppy.h linux-2.4.19-pre5-mjc/include/asm-um/floppy.h
--- linux/include/asm-um/floppy.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/floppy.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_FLOPPY_H
+#define __UM_FLOPPY_H
+
+#include "asm/arch/floppy.h"
+
+#endif
diff -Nru linux/include/asm-um/hardirq.h linux-2.4.19-pre5-mjc/include/asm-um/hardirq.h
--- linux/include/asm-um/hardirq.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/hardirq.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HARDIRQ_H
+#define __UM_HARDIRQ_H
+
+#include "asm/arch/hardirq.h"
+
+#endif
diff -Nru linux/include/asm-um/hdreg.h linux-2.4.19-pre5-mjc/include/asm-um/hdreg.h
--- linux/include/asm-um/hdreg.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/hdreg.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HDREG_H
+#define __UM_HDREG_H
+
+#include "asm/arch/hdreg.h"
+
+#endif
diff -Nru linux/include/asm-um/highmem.h linux-2.4.19-pre5-mjc/include/asm-um/highmem.h
--- linux/include/asm-um/highmem.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/highmem.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HIGHMEM_H
+#define __UM_HIGHMEM_H
+
+#include "asm/arch/highmem.h"
+
+#endif
diff -Nru linux/include/asm-um/hw_irq.h linux-2.4.19-pre5-mjc/include/asm-um/hw_irq.h
--- linux/include/asm-um/hw_irq.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/hw_irq.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,10 @@
+#ifndef _ASM_UM_HW_IRQ_H
+#define _ASM_UM_HW_IRQ_H
+
+#include "asm/irq.h"
+#include "asm/archparam.h"
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+{}
+
+#endif
diff -Nru linux/include/asm-um/ide.h linux-2.4.19-pre5-mjc/include/asm-um/ide.h
--- linux/include/asm-um/ide.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ide.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IDE_H
+#define __UM_IDE_H
+
+#include "asm/arch/ide.h"
+
+#endif
diff -Nru linux/include/asm-um/init.h linux-2.4.19-pre5-mjc/include/asm-um/init.h
--- linux/include/asm-um/init.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/init.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,11 @@
+#ifndef _UM_INIT_H
+#define _UM_INIT_H
+
+#ifdef notdef
+#define __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+#define __cacheline_aligned 
+#endif
+
+#endif
diff -Nru linux/include/asm-um/io.h linux-2.4.19-pre5-mjc/include/asm-um/io.h
--- linux/include/asm-um/io.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/io.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IO_H
+#define __UM_IO_H
+
+#include "asm/arch/io.h"
+
+#endif
diff -Nru linux/include/asm-um/ioctl.h linux-2.4.19-pre5-mjc/include/asm-um/ioctl.h
--- linux/include/asm-um/ioctl.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ioctl.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IOCTL_H
+#define __UM_IOCTL_H
+
+#include "asm/arch/ioctl.h"
+
+#endif
diff -Nru linux/include/asm-um/ioctls.h linux-2.4.19-pre5-mjc/include/asm-um/ioctls.h
--- linux/include/asm-um/ioctls.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ioctls.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IOCTLS_H
+#define __UM_IOCTLS_H
+
+#include "asm/arch/ioctls.h"
+
+#endif
diff -Nru linux/include/asm-um/ipc.h linux-2.4.19-pre5-mjc/include/asm-um/ipc.h
--- linux/include/asm-um/ipc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ipc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IPC_H
+#define __UM_IPC_H
+
+#include "asm/arch/ipc.h"
+
+#endif
diff -Nru linux/include/asm-um/ipcbuf.h linux-2.4.19-pre5-mjc/include/asm-um/ipcbuf.h
--- linux/include/asm-um/ipcbuf.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ipcbuf.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IPCBUF_H
+#define __UM_IPCBUF_H
+
+#include "asm/arch/ipcbuf.h"
+
+#endif
diff -Nru linux/include/asm-um/irq.h linux-2.4.19-pre5-mjc/include/asm-um/irq.h
--- linux/include/asm-um/irq.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/irq.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,34 @@
+#ifndef __UM_IRQ_H
+#define __UM_IRQ_H
+
+/* The i386 irq.h has a struct task_struct in a prototype without including
+ * sched.h.  This forward declaration kills the resulting warning.
+ */
+struct task_struct;
+
+#include "asm/arch/irq.h"
+#include "asm/ptrace.h"
+
+#undef NR_IRQS
+
+#define TIMER_IRQ		0
+#define UMN_IRQ			1
+#define CONSOLE_IRQ		2
+#define CONSOLE_WRITE_IRQ	3
+#define UBD_IRQ			4
+#define UM_ETH_IRQ		5
+#define SSL_IRQ			6
+#define SSL_WRITE_IRQ		7
+#define ACCEPT_IRQ		8
+#define MCONSOLE_IRQ		9
+#define WINCH_IRQ		10
+#define SIGIO_WRITE_IRQ 	11
+
+#define LAST_IRQ SIGIO_WRITE_IRQ
+#define NR_IRQS (LAST_IRQ + 1)
+
+extern int um_request_irq(unsigned int irq, int fd, int type,
+			  void (*handler)(int, void *, struct pt_regs *),
+			  unsigned long irqflags,  const char * devname,
+			  void *dev_id);
+#endif
diff -Nru linux/include/asm-um/keyboard.h linux-2.4.19-pre5-mjc/include/asm-um/keyboard.h
--- linux/include/asm-um/keyboard.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/keyboard.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_KEYBOARD_H
+#define __UM_KEYBOARD_H
+
+#include "asm/arch/keyboard.h"
+
+#endif
diff -Nru linux/include/asm-um/linux_logo.h linux-2.4.19-pre5-mjc/include/asm-um/linux_logo.h
--- linux/include/asm-um/linux_logo.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/linux_logo.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_LINUX_LOGO_H
+#define __UM_LINUX_LOGO_H
+
+#include "asm/arch/linux_logo.h"
+
+#endif
diff -Nru linux/include/asm-um/locks.h linux-2.4.19-pre5-mjc/include/asm-um/locks.h
--- linux/include/asm-um/locks.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/locks.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_LOCKS_H
+#define __UM_LOCKS_H
+
+#include "asm/arch/locks.h"
+
+#endif
diff -Nru linux/include/asm-um/mca_dma.h linux-2.4.19-pre5-mjc/include/asm-um/mca_dma.h
--- linux/include/asm-um/mca_dma.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/mca_dma.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef mca___UM_DMA_H
+#define mca___UM_DMA_H
+
+#include "asm/arch/mca_dma.h"
+
+#endif
diff -Nru linux/include/asm-um/mman.h linux-2.4.19-pre5-mjc/include/asm-um/mman.h
--- linux/include/asm-um/mman.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/mman.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MMAN_H
+#define __UM_MMAN_H
+
+#include "asm/arch/mman.h"
+
+#endif
diff -Nru linux/include/asm-um/mmu.h linux-2.4.19-pre5-mjc/include/asm-um/mmu.h
--- linux/include/asm-um/mmu.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/mmu.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __MMU_H
+#define __MMU_H
+
+#include "asm/arch/mmu.h"
+
+#endif
diff -Nru linux/include/asm-um/mmu_context.h linux-2.4.19-pre5-mjc/include/asm-um/mmu_context.h
--- linux/include/asm-um/mmu_context.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/mmu_context.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,25 @@
+#ifndef __UM_MMU_CONTEXT_H
+#define __UM_MMU_CONTEXT_H
+
+#include "linux/sched.h"
+
+#define init_new_context(task, mm) (0)
+#define get_mmu_context(task) do ; while(0)
+#define activate_context(tsk) do ; while(0)
+#define destroy_context(mm) do ; while(0)
+
+static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+			     struct task_struct *tsk, unsigned cpu)
+{
+}
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, 
+				  struct task_struct *tsk, unsigned cpu)
+{
+}
+
+#endif
diff -Nru linux/include/asm-um/module.h linux-2.4.19-pre5-mjc/include/asm-um/module.h
--- linux/include/asm-um/module.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/module.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MODULE_H
+#define __UM_MODULE_H
+
+#include "asm/arch/module.h"
+
+#endif
diff -Nru linux/include/asm-um/msgbuf.h linux-2.4.19-pre5-mjc/include/asm-um/msgbuf.h
--- linux/include/asm-um/msgbuf.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/msgbuf.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MSGBUF_H
+#define __UM_MSGBUF_H
+
+#include "asm/arch/msgbuf.h"
+
+#endif
diff -Nru linux/include/asm-um/mtrr.h linux-2.4.19-pre5-mjc/include/asm-um/mtrr.h
--- linux/include/asm-um/mtrr.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/mtrr.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MTRR_H
+#define __UM_MTRR_H
+
+#include "asm/arch/mtrr.h"
+
+#endif
diff -Nru linux/include/asm-um/namei.h linux-2.4.19-pre5-mjc/include/asm-um/namei.h
--- linux/include/asm-um/namei.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/namei.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_NAMEI_H
+#define __UM_NAMEI_H
+
+#include "asm/arch/namei.h"
+
+#endif
diff -Nru linux/include/asm-um/page.h linux-2.4.19-pre5-mjc/include/asm-um/page.h
--- linux/include/asm-um/page.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/page.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,48 @@
+#ifndef __UM_PAGE_H
+#define __UM_PAGE_H
+
+struct page;
+
+#include "asm/arch/page.h"
+
+#undef BUG
+#undef PAGE_BUG
+#undef __pa
+#undef __va
+#undef virt_to_page
+#undef VALID_PAGE
+#undef PAGE_OFFSET
+#undef KERNELBASE
+
+#define PAGE_OFFSET (uml_physmem)
+#define KERNELBASE PAGE_OFFSET
+
+#ifndef __ASSEMBLY__
+
+extern void stop(void);
+
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	stop(); \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+	BUG(); \
+} while (0)
+
+#endif /* __ASSEMBLY__ */
+
+extern unsigned long uml_physmem;
+
+#define __va_space (8*1024*1024)
+
+#define __pa(x)	((unsigned long) (x) - (uml_physmem))
+#define __va(x)	((void *) ((unsigned long) (x) + (uml_physmem)))
+
+#define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
+#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+
+extern struct page *arch_validate(struct page *page, int mask, int order);
+#define HAVE_ARCH_VALIDATE
+
+#endif
diff -Nru linux/include/asm-um/page_offset.h linux-2.4.19-pre5-mjc/include/asm-um/page_offset.h
--- linux/include/asm-um/page_offset.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/page_offset.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1 @@
+#define PAGE_OFFSET_RAW (uml_physmem)
diff -Nru linux/include/asm-um/param.h linux-2.4.19-pre5-mjc/include/asm-um/param.h
--- linux/include/asm-um/param.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/param.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,24 @@
+#ifndef _UM_PARAM_H
+#define _UM_PARAM_H
+
+#ifndef HZ
+#define HZ 52
+#endif
+
+#define EXEC_PAGESIZE   4096
+
+#ifndef NGROUPS
+#define NGROUPS         32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP         (-1)
+#endif
+
+#define MAXHOSTNAMELEN  64      /* max length of hostname */
+
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC 100    /* frequency at which times() counts */
+#endif
+
+#endif
diff -Nru linux/include/asm-um/pci.h linux-2.4.19-pre5-mjc/include/asm-um/pci.h
--- linux/include/asm-um/pci.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/pci.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_PCI_H
+#define __UM_PCI_H
+
+#include "asm/arch/pci.h"
+
+#endif
diff -Nru linux/include/asm-um/pgalloc.h linux-2.4.19-pre5-mjc/include/asm-um/pgalloc.h
--- linux/include/asm-um/pgalloc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/pgalloc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,144 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PGALLOC_H
+#define __UM_PGALLOC_H
+
+#include "linux/mm.h"
+
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist (current_cpu_data.pmd_quick)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+#define pmd_populate(mm, pmd, pte) \
+		set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) (pte)))
+
+/*
+ * Allocate and free page tables.
+ */
+
+static inline pgd_t *get_pgd_slow(void)
+{
+	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+	if (pgd) {
+		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	}
+	return pgd;
+}
+
+static inline pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if ((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+static inline void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+static inline void free_pgd_slow(pgd_t *pgd)
+{
+	free_page((unsigned long)pgd);
+}
+
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	return pte;
+}
+
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+{
+	unsigned long *ret;
+
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
+static inline void pte_free_pte_fast(pte_t *pte)
+{
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
+}
+
+static inline void pte_free_slow(pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+#define pte_free(pte)           pte_free_slow(pte)
+#define pgd_free(pgd)           free_pgd_slow(pgd)
+#define pgd_alloc(mm)           get_pgd_fast()
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+
+#define pmd_alloc_one_fast(mm, addr)	({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, addr)		({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(x)		do { } while (0)
+#define pmd_free_fast(x)		do { } while (0)
+#define pmd_free(x)			do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_kernel_vm() flushes the kernel vm area
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
+			    unsigned long end);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_kernel_vm(void);
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/pgtable.h linux-2.4.19-pre5-mjc/include/asm-um/pgtable.h
--- linux/include/asm-um/pgtable.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/pgtable.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,388 @@
+#ifndef __UM_PGTABLE_H
+#define __UM_PGTABLE_H
+
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/page.h"
+#include "asm/fixmap.h"
+
+extern pgd_t swapper_pg_dir[1024];
+
+#define flush_cache_all() do ; while (0)
+#define flush_cache_mm(mm) do ; while (0)
+#define flush_cache_range(mm, start, end) do ; while (0)
+#define flush_cache_page(vma, vmaddr) do ; while (0)
+#define flush_page_to_ram(page) do ; while (0)
+#define flush_dcache_page(page)	do ; while (0)
+#define flush_icache_range(from, to) do ; while (0)
+#define flush_icache_page(vma,pg) do ; while (0)
+
+extern void pte_free(pte_t *pte);
+
+extern void pgd_free(pgd_t *pgd);
+
+extern int do_check_pgt_cache(int, int);
+
+/* zero page used for uninitialized stuff */
+extern unsigned long *empty_zero_page;
+
+#define pgtable_cache_init() do ; while (0)
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT	22
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	22
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the i386 is two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE	1024
+#define PTRS_PER_PMD	1
+#define PTRS_PER_PGD	1024
+#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_PGD_NR       0
+
+#define pte_ERROR(e) \
+        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+        printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * pgd entries used up by user/kernel:
+ */
+
+#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#ifndef __ASSEMBLY__
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+extern unsigned long high_physmem;
+
+#define VMALLOC_OFFSET	(__va_space)
+#define VMALLOC_START	(((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END	(FIXADDR_START)
+
+/*
+ * The 4MB page is guessing..  Detailed in the infamous "Chapter H"
+ * of the Pentium details, but assuming intel did the straightforward
+ * thing, this bit set in the page directory entry just means that
+ * the page directory entry points directly to a 4MB-aligned block of
+ * memory. 
+ */
+#define _PAGE_PRESENT	0x001
+#define _PAGE_NEWPAGE	0x002
+#define _PAGE_PROTNONE	0x004	/* If not present */
+#define _PAGE_RW	0x008
+#define _PAGE_USER	0x010
+#define _PAGE_PCD       0x020
+#define _PAGE_ACCESSED	0x040
+#define _PAGE_DIRTY	0x080
+#define _PAGE_NEWPROT   0x100
+
+
+#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+/*
+ * The i386 can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+/*
+ * Define this if things work differently on an i386 and an i486:
+ * it will (on an i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef TEST_VERIFY_AREA
+
+/* page table for 0-4MB for everybody */
+extern unsigned long pg0[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR			(8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK			(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* 64-bit machines, beware!  SRB. */
+#define SIZEOF_PTR_LOG2			2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+#define pte_none(x)	!(pte_val(x) & ~_PAGE_NEWPAGE)
+#define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+
+#define pte_clear(xp)	do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
+
+#define pmd_none(x)	(!(pmd_val(x) & ~_PAGE_NEWPAGE))
+#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+#define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)	do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
+
+#define pmd_newpage(x)  (pmd_val(x) & _PAGE_NEWPAGE)
+#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE)
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static inline int pgd_none(pgd_t pgd)		{ return 0; }
+static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+static inline int pgd_present(pgd_t pgd)	{ return 1; }
+static inline void pgd_clear(pgd_t * pgdp)	{ }
+
+
+/*
+ * Permanent address of a page. Obviously must never be
+ * called on a highmem page.
+ */
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define __page_address(page) ({ PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); })
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+#define pte_page(x) \
+    (mem_map+((unsigned long)((__pa(pte_val(x)) >> PAGE_SHIFT))))
+#define pte_address(x) ((void *) ((unsigned long) pte_val(x) & PAGE_MASK))
+
+static inline pte_t pte_mknewprot(pte_t pte)
+{
+ 	pte_val(pte) |= _PAGE_NEWPROT;
+	return(pte);
+}
+
+static inline pte_t pte_mknewpage(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_NEWPAGE;
+	return(pte);
+}
+
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	/* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
+	 * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
+	 * mapped pages.
+	 */
+	*pteptr = pte_mknewpage(pteval);
+	if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
+}
+
+/*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_exec(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_dirty(pte_t pte)	{ return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)	{ return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte)	{ return pte_val(pte) & _PAGE_RW; }
+static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
+static inline int pte_newprot(pte_t pte) { return pte_val(pte) & _PAGE_NEWPROT; }
+
+static inline pte_t pte_rdprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_USER; 
+	return(pte_mknewprot(pte));
+}
+
+static inline pte_t pte_exprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_USER;
+	return(pte_mknewprot(pte));
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+	pte_val(pte) &= ~_PAGE_DIRTY; 
+	return(pte);
+}
+
+static inline pte_t pte_mkold(pte_t pte)	
+{ 
+	pte_val(pte) &= ~_PAGE_ACCESSED; 
+	return(pte);
+}
+
+static inline pte_t pte_wrprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_RW; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkread(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_USER; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkexec(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_USER; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_DIRTY; 
+	return(pte);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_ACCESSED; 
+	return(pte);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)	
+{
+	pte_val(pte) |= _PAGE_RW; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkuptodate(pte_t pte)	
+{
+	pte_val(pte) &= ~(_PAGE_NEWPROT | _PAGE_NEWPAGE);
+	return(pte); 
+}
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+#define mk_pte(page, pgprot) \
+({					\
+	pte_t __pte;                    \
+                                        \
+	pte_val(__pte) = ((unsigned long) __va((page-mem_map)*(unsigned long)PAGE_SIZE + pgprot_val(pgprot)));         \
+	if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \
+	__pte;                          \
+})
+
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte));
+	return pte; 
+}
+
+#define pmd_page(pmd) \
+(pmd_val(pmd) & PAGE_MASK)
+
+/* to find an entry in a page-table-directory. */
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, address) \
+((mm)->pgd + ((address) >> PGDIR_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* Find an entry in the second-level page table.. */
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+#define pte_offset(pmd, address) \
+((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
+
+#define update_mmu_cache(vma,address,pte) do ; while (0)
+
+/* Encode and de-code a swap entry */
+#define SWP_TYPE(x)			(((x).val >> 3) & 0x7f)
+#define SWP_OFFSET(x)			((x).val >> 10)
+
+#define SWP_ENTRY(type, offset) \
+	((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
+#define pte_to_swp_entry(pte) \
+	((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
+#define swp_entry_to_pte(x)		((pte_t) { (x).val })
+
+#define PageSkip(x) (0)
+#define kern_addr_valid(addr) (1)
+
+#include <asm-generic/pgtable.h>
+
+#endif
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/poll.h linux-2.4.19-pre5-mjc/include/asm-um/poll.h
--- linux/include/asm-um/poll.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/poll.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_POLL_H
+#define __UM_POLL_H
+
+#include "asm/arch/poll.h"
+
+#endif
diff -Nru linux/include/asm-um/posix_types.h linux-2.4.19-pre5-mjc/include/asm-um/posix_types.h
--- linux/include/asm-um/posix_types.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/posix_types.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_POSIX_TYPES_H
+#define __UM_POSIX_TYPES_H
+
+#include "asm/arch/posix_types.h"
+
+#endif
diff -Nru linux/include/asm-um/processor-generic.h linux-2.4.19-pre5-mjc/include/asm-um/processor-generic.h
--- linux/include/asm-um/processor-generic.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/processor-generic.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,169 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PROCESSOR_GENERIC_H
+#define __UM_PROCESSOR_GENERIC_H
+
+struct pt_regs;
+
+struct task_struct;
+
+#include "linux/config.h"
+#include "linux/signal.h"
+#include "asm/segment.h"
+#include "asm/ptrace.h"
+#include "asm/siginfo.h"
+
+struct mm_struct;
+
+#define current_text_addr() ((void *) 0)
+
+#define cpu_relax()	do ; while (0)
+
+#define SIGNAL_NONE 0
+#define SIGNAL_PENDING 1
+
+struct thread_struct {
+	int extern_pid;
+	int tracing;
+	int forking;
+	unsigned long kernel_stack;
+	struct signal_context *signal_context;
+	int nsyscalls;
+	struct pt_regs regs;
+	unsigned long cr2;
+	int err;
+	void *fault_addr;
+	void *fault_catcher;
+	int vm_seq;
+	struct task_struct *prev_sched;
+	unsigned long temp_stack;
+	int switch_pipe[2];
+	void *jmp;
+	struct {
+		int op;
+		union {
+			struct {
+				int pid;
+			} fork, exec;
+			struct {
+				int (*proc)(void *);
+				void *arg;
+			} thread;
+			struct {
+				void (*proc)(void *);
+				void *arg;
+			} cb;
+		} u;
+	} request;
+};
+
+#define INIT_THREAD \
+{ \
+	extern_pid:		-1, \
+	tracing:		0, \
+	forking:		0, \
+	kernel_stack:		0, \
+	signal_context:		NULL, \
+	nsyscalls:		0, \
+        regs:		   	EMPTY_REGS, \
+	cr2:			0, \
+	err:			0, \
+	fault_addr:		NULL, \
+	vm_seq:			0, \
+	prev_sched:		NULL, \
+	temp_stack:		0, \
+	switch_pipe:		{ -1, -1 }, \
+	jmp:			NULL, \
+	request:		{ 0 } \
+}
+
+#define THREAD_SIZE (2*PAGE_SIZE)
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *task);
+
+#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+
+extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+static inline void release_segments(struct mm_struct *mm)
+{
+}
+
+static inline void copy_segments(struct task_struct *p, 
+				 struct mm_struct *new_mm)
+{
+}
+
+#define forget_segments() do ; while(0)
+
+extern unsigned long thread_saved_pc(struct thread_struct *t);
+
+/*
+extern unsigned long init_task_ptr;
+
+#define init_task_u (*((union task_union *) init_task_ptr))
+*/
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
+
+/*
+ * User space process size: 3GB (default).
+ */
+extern unsigned long task_size;
+
+#define TASK_SIZE	(task_size)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE	(0x40000000)
+
+extern void start_thread(struct pt_regs *regs, unsigned long entry, 
+			 unsigned long stack);
+
+struct cpuinfo_um {
+	unsigned long loops_per_jiffy;
+	unsigned long *pgd_quick;
+	unsigned long *pmd_quick;
+	unsigned long *pte_quick;
+	unsigned long pgtable_cache_sz;  
+	int ipi_pipe[2];
+};
+
+extern struct cpuinfo_um boot_cpu_data;
+
+#define my_cpu_data		cpu_data[smp_processor_id()]
+
+#ifdef CONFIG_SMP
+extern struct cpuinfo_um cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+#endif
+
+#define KSTK_EIP(tsk) (0)
+#define KSTK_ESP(tsk) (0)
+#define get_wchan(p) (0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/processor-i386.h linux-2.4.19-pre5-mjc/include/asm-um/processor-i386.h
--- linux/include/asm-um/processor-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/processor-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_PROCESSOR_I386_H
+#define __UM_PROCESSOR_I386_H
+
+#include "asm/processor-generic.h"
+
+#endif
diff -Nru linux/include/asm-um/processor-ppc.h linux-2.4.19-pre5-mjc/include/asm-um/processor-ppc.h
--- linux/include/asm-um/processor-ppc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/processor-ppc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,15 @@
+#ifndef __UM_PROCESSOR_PPC_H
+#define __UM_PROCESSOR_PPC_H
+
+#if defined(__ASSEMBLY__)
+
+#define CONFIG_ALL_PPC
+#include "arch/processor.h"
+
+#else
+
+#include "asm/processor-generic.h"
+
+#endif
+
+#endif
diff -Nru linux/include/asm-um/ptrace-generic.h linux-2.4.19-pre5-mjc/include/asm-um/ptrace-generic.h
--- linux/include/asm-um/ptrace-generic.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ptrace-generic.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,65 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PTRACE_GENERIC_H
+#define __UM_PTRACE_GENERIC_H
+
+#ifndef __ASSEMBLY__
+
+#include "asm/current.h"
+
+#define pt_regs pt_regs_subarch
+#define show_regs show_regs_subarch
+
+#include "asm/arch/ptrace.h"
+
+#undef pt_regs
+#undef show_regs
+#undef user_mode
+#undef instruction_pointer
+
+#include "sysdep/ptrace.h"
+
+struct pt_regs {
+	struct uml_pt_regs regs;
+};
+
+#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
+
+#define PT_REGS_IP(r) UPT_IP(&(r)->regs)
+#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
+
+#define PT_REG(r, reg) UPT_REG(&(r)->regs, reg)
+#define PT_REGS_SET(r, reg, val) UPT_SET(&(r)->regs, reg, val)
+
+#define PT_REGS_SET_SYSCALL_RETURN(r, res) \
+	UPT_SET_SYSCALL_RETURN(&(r)->regs, res)
+#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs)
+
+#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs)
+
+
+struct task_struct;
+
+extern int putreg(struct task_struct *child, int regno, unsigned long value);
+extern unsigned long getreg(struct task_struct *child, int regno);
+extern void show_regs(struct pt_regs *regs);
+
+#define INIT_TASK_SIZE (4 * PAGE_SIZE)
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/ptrace-i386.h linux-2.4.19-pre5-mjc/include/asm-um/ptrace-i386.h
--- linux/include/asm-um/ptrace-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/ptrace-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,45 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PTRACE_I386_H
+#define __UM_PTRACE_I386_H
+
+#include "asm/ptrace-generic.h"
+
+#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
+#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
+#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
+#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
+#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
+#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
+#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
+
+#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
+#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
+#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
+#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
+#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
+#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
+
+#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define user_mode(r) ((r)->regs.is_user)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/resource.h linux-2.4.19-pre5-mjc/include/asm-um/resource.h
--- linux/include/asm-um/resource.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/resource.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_RESOURCE_H
+#define __UM_RESOURCE_H
+
+#include "asm/arch/resource.h"
+
+#endif
diff -Nru linux/include/asm-um/rwlock.h linux-2.4.19-pre5-mjc/include/asm-um/rwlock.h
--- linux/include/asm-um/rwlock.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/rwlock.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_RWLOCK_H
+#define __UM_RWLOCK_H
+
+#include "asm/arch/rwlock.h"
+
+#endif
diff -Nru linux/include/asm-um/rwsem.h linux-2.4.19-pre5-mjc/include/asm-um/rwsem.h
--- linux/include/asm-um/rwsem.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/rwsem.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_RWSEM_H__
+#define __UM_RWSEM_H__
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(exp,c) (exp)
+#endif
+
+#include "asm/arch/rwsem.h"
+
+#endif
diff -Nru linux/include/asm-um/scatterlist.h linux-2.4.19-pre5-mjc/include/asm-um/scatterlist.h
--- linux/include/asm-um/scatterlist.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/scatterlist.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SCATTERLIST_H
+#define __UM_SCATTERLIST_H
+
+#include "asm/arch/scatterlist.h"
+
+#endif
diff -Nru linux/include/asm-um/segment.h linux-2.4.19-pre5-mjc/include/asm-um/segment.h
--- linux/include/asm-um/segment.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/segment.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,4 @@
+#ifndef __UM_SEGMENT_H
+#define __UM_SEGMENT_H
+
+#endif
diff -Nru linux/include/asm-um/semaphore.h linux-2.4.19-pre5-mjc/include/asm-um/semaphore.h
--- linux/include/asm-um/semaphore.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/semaphore.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SEMAPHORE_H
+#define __UM_SEMAPHORE_H
+
+#include "asm/arch/semaphore.h"
+
+#endif
diff -Nru linux/include/asm-um/sembuf.h linux-2.4.19-pre5-mjc/include/asm-um/sembuf.h
--- linux/include/asm-um/sembuf.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/sembuf.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SEMBUF_H
+#define __UM_SEMBUF_H
+
+#include "asm/arch/sembuf.h"
+
+#endif
diff -Nru linux/include/asm-um/serial.h linux-2.4.19-pre5-mjc/include/asm-um/serial.h
--- linux/include/asm-um/serial.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/serial.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SERIAL_H
+#define __UM_SERIAL_H
+
+#include "asm/arch/serial.h"
+
+#endif
diff -Nru linux/include/asm-um/shmbuf.h linux-2.4.19-pre5-mjc/include/asm-um/shmbuf.h
--- linux/include/asm-um/shmbuf.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/shmbuf.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SHMBUF_H
+#define __UM_SHMBUF_H
+
+#include "asm/arch/shmbuf.h"
+
+#endif
diff -Nru linux/include/asm-um/shmparam.h linux-2.4.19-pre5-mjc/include/asm-um/shmparam.h
--- linux/include/asm-um/shmparam.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/shmparam.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SHMPARAM_H
+#define __UM_SHMPARAM_H
+
+#include "asm/arch/shmparam.h"
+
+#endif
diff -Nru linux/include/asm-um/sigcontext-generic.h linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-generic.h
--- linux/include/asm-um/sigcontext-generic.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-generic.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGCONTEXT_GENERIC_H
+#define __UM_SIGCONTEXT_GENERIC_H
+
+#include "asm/arch/sigcontext.h"
+
+#endif
diff -Nru linux/include/asm-um/sigcontext-i386.h linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-i386.h
--- linux/include/asm-um/sigcontext-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGCONTEXT_I386_H
+#define __UM_SIGCONTEXT_I386_H
+
+#include "asm/sigcontext-generic.h"
+
+#endif
diff -Nru linux/include/asm-um/sigcontext-ppc.h linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-ppc.h
--- linux/include/asm-um/sigcontext-ppc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/sigcontext-ppc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_SIGCONTEXT_PPC_H
+#define __UM_SIGCONTEXT_PPC_H
+
+#define pt_regs sys_pt_regs
+
+#include "asm/sigcontext-generic.h"
+
+#undef pt_regs
+
+#endif
diff -Nru linux/include/asm-um/siginfo.h linux-2.4.19-pre5-mjc/include/asm-um/siginfo.h
--- linux/include/asm-um/siginfo.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/siginfo.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGINFO_H
+#define __UM_SIGINFO_H
+
+#include "asm/arch/siginfo.h"
+
+#endif
diff -Nru linux/include/asm-um/signal.h linux-2.4.19-pre5-mjc/include/asm-um/signal.h
--- linux/include/asm-um/signal.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/signal.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,30 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_SIGNAL_H
+#define __UM_SIGNAL_H
+
+#include "sysdep/ptrace.h"
+#include "asm/arch/signal.h"
+#include "asm/arch-signal.h"
+
+struct signal_context {
+	void *sc;
+	struct signal_context *prev;
+	struct arch_signal_context arch;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/smp.h linux-2.4.19-pre5-mjc/include/asm-um/smp.h
--- linux/include/asm-um/smp.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/smp.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,19 @@
+#ifndef __UM_SMP_H
+#define __UM_SMP_H
+
+#ifdef CONFIG_SMP
+
+#include "linux/config.h"
+#include "asm/current.h"
+
+#define smp_processor_id() (current->processor)
+#define cpu_logical_map(n) (n)
+#define cpu_number_map(n) (n)
+#define PROC_CHANGE_PENALTY	15 /* Pick a number, any number */
+extern int hard_smp_processor_id(void);
+extern unsigned long cpu_online_map;
+#define NO_PROC_ID -1
+
+#endif
+
+#endif
diff -Nru linux/include/asm-um/smplock.h linux-2.4.19-pre5-mjc/include/asm-um/smplock.h
--- linux/include/asm-um/smplock.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/smplock.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SMPLOCK_H
+#define __UM_SMPLOCK_H
+
+#include "asm/arch/smplock.h"
+
+#endif
diff -Nru linux/include/asm-um/socket.h linux-2.4.19-pre5-mjc/include/asm-um/socket.h
--- linux/include/asm-um/socket.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/socket.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SOCKET_H
+#define __UM_SOCKET_H
+
+#include "asm/arch/socket.h"
+
+#endif
diff -Nru linux/include/asm-um/sockios.h linux-2.4.19-pre5-mjc/include/asm-um/sockios.h
--- linux/include/asm-um/sockios.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/sockios.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SOCKIOS_H
+#define __UM_SOCKIOS_H
+
+#include "asm/arch/sockios.h"
+
+#endif
diff -Nru linux/include/asm-um/softirq.h linux-2.4.19-pre5-mjc/include/asm-um/softirq.h
--- linux/include/asm-um/softirq.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/softirq.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,13 @@
+#ifndef __UM_SOFTIRQ_H
+#define __UM_SOFTIRQ_H
+
+#include "linux/smp.h"
+#include "asm/system.h"
+#include "asm/processor.h"
+
+/* A gratuitous name change */
+#define i386_bh_lock um_bh_lock
+#include "asm/arch/softirq.h"
+#undef i386_bh_lock
+
+#endif
diff -Nru linux/include/asm-um/spinlock.h linux-2.4.19-pre5-mjc/include/asm-um/spinlock.h
--- linux/include/asm-um/spinlock.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/spinlock.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_SPINLOCK_H
+#define __UM_SPINLOCK_H
+
+#include "linux/config.h"
+
+#ifdef CONFIG_SMP
+#include "asm/arch/spinlock.h"
+#endif
+
+#endif
diff -Nru linux/include/asm-um/stat.h linux-2.4.19-pre5-mjc/include/asm-um/stat.h
--- linux/include/asm-um/stat.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/stat.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_STAT_H
+#define __UM_STAT_H
+
+#include "asm/arch/stat.h"
+
+#endif
diff -Nru linux/include/asm-um/statfs.h linux-2.4.19-pre5-mjc/include/asm-um/statfs.h
--- linux/include/asm-um/statfs.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/statfs.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef _UM_STATFS_H
+#define _UM_STATFS_H
+
+#include "asm/arch/statfs.h"
+
+#endif
diff -Nru linux/include/asm-um/string.h linux-2.4.19-pre5-mjc/include/asm-um/string.h
--- linux/include/asm-um/string.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/string.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,7 @@
+#ifndef __UM_STRING_H
+#define __UM_STRING_H
+
+#include "asm/arch/string.h"
+#include "asm/archparam.h"
+
+#endif
diff -Nru linux/include/asm-um/system-generic.h linux-2.4.19-pre5-mjc/include/asm-um/system-generic.h
--- linux/include/asm-um/system-generic.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/system-generic.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,49 @@
+#ifndef __UM_SYSTEM_GENERIC_H
+#define __UM_SYSTEM_GENERIC_H
+
+#include "asm/arch/system.h"
+
+#undef prepare_to_switch
+#undef switch_to
+#undef __save_flags
+#undef save_flags
+#undef __restore_flags
+#undef restore_flags
+#undef __cli
+#undef __sti
+#undef cli
+#undef sti
+#undef local_irq_save
+#undef local_irq_restore
+#undef local_irq_disable
+#undef local_irq_enable
+
+#define prepare_to_switch() do ; while(0)
+
+void *_switch_to(void *prev, void *next);
+
+#define switch_to(prev, next, last) prev = _switch_to(prev, next)
+
+extern int set_signals(int enable);
+extern void block_signals(void);
+extern void unblock_signals(void);
+
+#define local_irq_save(flags) do { (flags) = set_signals(0); } while(0)
+
+#define local_irq_restore(flags) do { set_signals(flags); } while(0)
+
+#define local_irq_enable() unblock_signals()
+#define local_irq_disable() block_signals()
+
+#define __sti() unblock_signals()
+#define sti() unblock_signals()
+#define __cli() block_signals()
+#define cli() block_signals()
+
+#define __save_flags(x) local_irq_save(x)
+#define save_flags(x) __save_flags(x)
+
+#define __restore_flags(x) local_irq_restore(x)
+#define restore_flags(x) __restore_flags(x)
+
+#endif
diff -Nru linux/include/asm-um/system-i386.h linux-2.4.19-pre5-mjc/include/asm-um/system-i386.h
--- linux/include/asm-um/system-i386.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/system-i386.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SYSTEM_I386_H
+#define __UM_SYSTEM_I386_H
+
+#include "asm/system-generic.h"
+
+#endif
diff -Nru linux/include/asm-um/system-ppc.h linux-2.4.19-pre5-mjc/include/asm-um/system-ppc.h
--- linux/include/asm-um/system-ppc.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/system-ppc.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,12 @@
+#ifndef __UM_SYSTEM_PPC_H
+#define __UM_SYSTEM_PPC_H
+
+#define _switch_to _ppc_switch_to
+
+#include "asm/arch/system.h"
+
+#undef _switch_to
+ 
+#include "asm/system-generic.h"
+
+#endif
diff -Nru linux/include/asm-um/termbits.h linux-2.4.19-pre5-mjc/include/asm-um/termbits.h
--- linux/include/asm-um/termbits.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/termbits.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TERMBITS_H
+#define __UM_TERMBITS_H
+
+#include "asm/arch/termbits.h"
+
+#endif
diff -Nru linux/include/asm-um/termios.h linux-2.4.19-pre5-mjc/include/asm-um/termios.h
--- linux/include/asm-um/termios.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/termios.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TERMIOS_H
+#define __UM_TERMIOS_H
+
+#include "asm/arch/termios.h"
+
+#endif
diff -Nru linux/include/asm-um/timex.h linux-2.4.19-pre5-mjc/include/asm-um/timex.h
--- linux/include/asm-um/timex.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/timex.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,15 @@
+#ifndef __UM_TIMEX_H
+#define __UM_TIMEX_H
+
+#include "linux/time.h"
+
+typedef unsigned long cycles_t;
+
+#define cacheflush_time (0)
+
+static inline cycles_t get_cycles (void)
+{
+	return 0;
+}
+
+#endif
diff -Nru linux/include/asm-um/tlb.h linux-2.4.19-pre5-mjc/include/asm-um/tlb.h
--- linux/include/asm-um/tlb.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/tlb.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -Nru linux/include/asm-um/types.h linux-2.4.19-pre5-mjc/include/asm-um/types.h
--- linux/include/asm-um/types.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/types.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TYPES_H
+#define __UM_TYPES_H
+
+#include "asm/arch/types.h"
+
+#endif
diff -Nru linux/include/asm-um/uaccess.h linux-2.4.19-pre5-mjc/include/asm-um/uaccess.h
--- linux/include/asm-um/uaccess.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/uaccess.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,192 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_UACCESS_H
+#define __UM_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
+#define USER_DS		MAKE_MM_SEG(TASK_SIZE)
+
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current->addr_limit)
+#define set_fs(x)	(current->addr_limit = (x))
+
+extern unsigned long end_vm;
+extern unsigned long uml_physmem;
+
+#define under_task_size(addr, size) \
+	(((unsigned long) (addr) < TASK_SIZE) && \
+         (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define is_stack(addr, size) \
+	(((unsigned long) (addr) < STACK_TOP) && \
+	 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
+	 (((unsigned long) (addr) + (size)) <= STACK_TOP))
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#define access_ok(type, addr, size) \
+	((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
+         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
+          (under_task_size(addr, size) || is_stack(addr, size))))
+
+static inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return(access_ok(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern unsigned long get_fault_addr(void);
+
+extern int __do_copy_from_user(void *to, const void *from, int n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int copy_from_user(void *to, const void *from, int n)
+{
+	return(access_ok(VERIFY_READ, from, n) ?
+	       __do_copy_from_user(to, from, n, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher) : n);
+}
+
+#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
+
+extern int __do_copy_to_user(void *to, const void *from, int n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int copy_to_user(void *to, const void *from, int n)
+{
+	return(access_ok(VERIFY_WRITE, to, n) ?
+	       __do_copy_from_user(to, from, n, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher) : n);
+}
+
+#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
+
+#define __get_user(x, ptr) \
+({ \
+        const __typeof__(ptr) __private_ptr = ptr; \
+        __typeof__(*(__private_ptr)) __private_val; \
+        int __private_ret = -EFAULT; \
+        (x) = 0; \
+	if (__copy_from_user(&__private_val, (__private_ptr), \
+	    sizeof(*(__private_ptr))) == 0) {\
+        	(x) = (__typeof__(*(__private_ptr))) __private_val; \
+		__private_ret = 0; \
+	} \
+        __private_ret; \
+}) 
+
+#define get_user(x, ptr) \
+({ \
+        const __typeof__((*ptr)) *private_ptr = (ptr); \
+        (access_ok(VERIFY_READ, private_ptr, sizeof(x)) ? \
+	 __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
+})
+
+#define __put_user(x, ptr) \
+({ \
+        __typeof__(ptr) __private_ptr = ptr; \
+        __typeof__(*(__private_ptr)) __private_val; \
+        int __private_ret = -EFAULT; \
+        __private_val = (__typeof__(*(__private_ptr))) (x); \
+        if (__copy_to_user((__private_ptr), &__private_val, \
+			   sizeof(*(__private_ptr))) == 0) { \
+		__private_ret = 0; \
+	} \
+        __private_ret; \
+})
+
+#define put_user(x, ptr) \
+({ \
+        __typeof__(*(ptr)) *private_ptr = (ptr); \
+        (access_ok(VERIFY_WRITE, private_ptr, sizeof(x)) ? \
+	 __put_user(x, private_ptr) : -EFAULT); \
+})
+
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int strncpy_from_user(char *dst, const char *src, int count)
+{
+	int n;
+
+	if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT);
+	n = __do_strncpy_from_user(dst, src, count, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher);
+	if(n < 0) return(-EFAULT);
+	return(n);
+}
+
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+			   void **fault_catcher);
+
+static inline int __clear_user(void *mem, int len)
+{
+	return(__do_clear_user(mem, len,
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+static inline int clear_user(void *mem, int len)
+{
+	return(access_ok(VERIFY_WRITE, mem, len) ? 
+	       __do_clear_user(mem, len, 
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher) : len);
+}
+
+extern int __do_strnlen_user(const char *str, unsigned long n,
+			     void **fault_addr, void **fault_catcher);
+
+static inline int strnlen_user(void *str, int len)
+{
+	return(__do_strnlen_user(str, len,
+				 &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
+struct exception_table_entry
+{
+        unsigned long unused;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/unaligned.h linux-2.4.19-pre5-mjc/include/asm-um/unaligned.h
--- linux/include/asm-um/unaligned.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/unaligned.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_UNALIGNED_H
+#define __UM_UNALIGNED_H
+
+#include "asm/arch/unaligned.h"
+
+#endif
diff -Nru linux/include/asm-um/unistd.h linux-2.4.19-pre5-mjc/include/asm-um/unistd.h
--- linux/include/asm-um/unistd.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/unistd.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (C) 2000, 2001  Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef _UM_UNISTD_H_
+#define _UM_UNISTD_H_
+
+#include "linux/resource.h"
+#include "asm/uaccess.h"
+
+extern long sys_open(const char *filename, int flags, int mode);
+extern long sys_dup(unsigned int fildes);
+extern long sys_close(unsigned int fd);
+extern long lseek(unsigned int fildes, unsigned long offset, int whence);
+extern int read(unsigned int fildes, char *buf, int len);
+extern int um_execve(const char *file, char *const argv[], char *const env[]);
+extern long sys_setsid(void);
+extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
+extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, 
+		      struct rusage *ru);
+extern long sys_mount(char *dev_name, char *dir_name, char *type, 
+		      unsigned long flags, void *data);
+extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, 
+		       struct timeval *tvp);
+
+#ifdef __KERNEL_SYSCALLS__
+
+#define KERNEL_CALL(ret_t, sys, args...)	\
+	mm_segment_t fs = get_fs();		\
+	ret_t ret;				\
+	set_fs(KERNEL_DS);			\
+	ret = sys(args);			\
+	set_fs(fs);				\
+	return ret;
+
+static inline long open(const char *pathname, int flags, int mode) 
+{
+	KERNEL_CALL(int, sys_open, pathname, flags, mode)
+}
+
+static inline long dup(unsigned int fd)
+{
+	KERNEL_CALL(int, sys_dup, fd);
+}
+
+static inline long close(unsigned int fd)
+{
+	KERNEL_CALL(int, sys_close, fd);
+}
+
+static inline int execve(const char *filename, char *const argv[], 
+			 char *const envp[])
+{
+	KERNEL_CALL(int, um_execve, filename, argv, envp);
+}
+
+static inline long waitpid(pid_t pid, unsigned int *status, int options)
+{
+	KERNEL_CALL(pid_t, sys_wait4, pid, status, options, NULL)
+}
+
+static inline pid_t wait(int *status)
+{
+	KERNEL_CALL(pid_t, sys_wait4, -1, status, 0, NULL)
+}
+
+static inline pid_t setsid(void)
+{
+	KERNEL_CALL(pid_t, sys_setsid)
+}
+
+#endif
+
+/* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying
+ * arch's unistd.h for the system call numbers, and restore the old 
+ * __KERNEL_SYSCALLS__.
+ */
+
+#ifdef __KERNEL_SYSCALLS__
+#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__
+#endif
+
+#undef __KERNEL_SYSCALLS__
+#include "asm/arch/unistd.h"
+
+#ifdef __KERNEL_SYSCALLS__
+#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/asm-um/user.h linux-2.4.19-pre5-mjc/include/asm-um/user.h
--- linux/include/asm-um/user.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/user.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_USER_H
+#define __UM_USER_H
+
+#include "asm/arch/user.h"
+
+#endif
diff -Nru linux/include/asm-um/vga.h linux-2.4.19-pre5-mjc/include/asm-um/vga.h
--- linux/include/asm-um/vga.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/asm-um/vga.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_VGA_H
+#define __UM_VGA_H
+
+#include "asm/arch/vga.h"
+
+#endif
diff -Nru linux/include/linux/blk.h linux-2.4.19-pre5-mjc/include/linux/blk.h
--- linux/include/linux/blk.h	Sat Apr  6 15:32:10 2002
+++ linux-2.4.19-pre5-mjc/include/linux/blk.h	Sat Apr  6 16:07:16 2002
@@ -323,6 +323,15 @@
 #define DEVICE_REQUEST do_ida_request
 #define DEVICE_NR(device) (MINOR(device) >> 4)
 
+#elif (MAJOR_NR == UBD_MAJOR)
+
+#define DEVICE_NAME "User-mode block device"
+#define DEVICE_INTR do_ubd
+#define DEVICE_REQUEST do_ubd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #endif /* MAJOR_NR == whatever */
 
 /* provide DEVICE_xxx defaults, if not explicitly defined
diff -Nru linux/include/linux/fs.h linux-2.4.19-pre5-mjc/include/linux/fs.h
--- linux/include/linux/fs.h	Sat Apr  6 15:31:20 2002
+++ linux-2.4.19-pre5-mjc/include/linux/fs.h	Sat Apr  6 16:07:16 2002
@@ -316,6 +316,7 @@
 #include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
 #include <linux/usbdev_fs_i.h>
+#include <linux/hostfs_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
@@ -510,7 +511,8 @@
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
 		struct usbdev_inode_info        usbdev_i;
-		struct jffs2_inode_info		jffs2_i;
+	        struct hostfs_inode_info	hostfs_i;
+ 		struct jffs2_inode_info		jffs2_i;
 		void				*generic_ip;
 	} u;
 };
diff -Nru linux/include/linux/hostfs_fs_i.h linux-2.4.19-pre5-mjc/include/linux/hostfs_fs_i.h
--- linux/include/linux/hostfs_fs_i.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/include/linux/hostfs_fs_i.h	Sat Apr  6 16:07:16 2002
@@ -0,0 +1,21 @@
+#ifndef _HOSTFS_FS_I
+#define _HOSTFS_FS_I
+
+struct hostfs_inode_info {
+	char *host_filename;
+	int fd;
+	int mode;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru linux/include/linux/kernel.h linux-2.4.19-pre5-mjc/include/linux/kernel.h
--- linux/include/linux/kernel.h	Sat Apr  6 15:31:19 2002
+++ linux-2.4.19-pre5-mjc/include/linux/kernel.h	Sat Apr  6 16:07:16 2002
@@ -47,7 +47,7 @@
 # define ATTRIB_NORET  __attribute__((noreturn))
 # define NORET_AND     noreturn,
 
-#ifdef __i386__
+#if defined(__i386__) || defined(UM_FASTCALL)
 #define FASTCALL(x)	x __attribute__((regparm(3)))
 #else
 #define FASTCALL(x)	x
diff -Nru linux/include/linux/kernel_stat.h linux-2.4.19-pre5-mjc/include/linux/kernel_stat.h
--- linux/include/linux/kernel_stat.h	Sat Apr  6 15:31:20 2002
+++ linux-2.4.19-pre5-mjc/include/linux/kernel_stat.h	Sat Apr  6 16:07:16 2002
@@ -12,7 +12,7 @@
  * used by rstatd/perfmeter
  */
 
-#define DK_MAX_MAJOR 16
+#define DK_MAX_MAJOR 99
 #define DK_MAX_DISK 16
 
 struct kernel_stat {
diff -Nru linux/include/linux/mm.h linux-2.4.19-pre5-mjc/include/linux/mm.h
--- linux/include/linux/mm.h	Sat Apr  6 15:31:23 2002
+++ linux-2.4.19-pre5-mjc/include/linux/mm.h	Sat Apr  6 16:07:16 2002
@@ -443,6 +443,14 @@
 extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist));
 extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
 
+#ifndef HAVE_ARCH_VALIDATE
+static inline struct page *arch_validate(struct page *page, 
+					 unsigned int gfp_mask, int order)
+{
+        return(page);
+}
+#endif
+
 static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
 {
 	/*
@@ -450,7 +458,7 @@
 	 */
 	if (order >= MAX_ORDER)
 		return NULL;
-	return _alloc_pages(gfp_mask, order);
+	return arch_validate(_alloc_pages(gfp_mask, order), gfp_mask, order);
 }
 
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
diff -Nru linux/include/linux/tty.h linux-2.4.19-pre5-mjc/include/linux/tty.h
--- linux/include/linux/tty.h	Sat Apr  6 15:31:20 2002
+++ linux-2.4.19-pre5-mjc/include/linux/tty.h	Sat Apr  6 16:07:16 2002
@@ -366,6 +366,7 @@
 extern int specialix_init(void);
 extern int espserial_init(void);
 extern int macserial_init(void);
+extern int stdio_init(void);
 extern int a2232board_init(void);
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
@@ -420,6 +421,8 @@
 
 extern int vt_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg);
+
+extern void stdio_console_init(void);
 
 #endif /* __KERNEL__ */
 #endif
