Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
new file mode 100644
index 0000000..dc796c1
--- /dev/null
+++ b/arch/um/kernel/Makefile
@@ -0,0 +1,58 @@
+# 
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+extra-y := vmlinux.lds
+clean-files := vmlinux.lds.S config.tmp
+
+obj-y = checksum.o config.o exec_kern.o exitcode.o \
+	helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
+	physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
+	sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
+	syscall_kern.o sysrq.o sys_call_table.o tempfile.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
+
+obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
+obj-$(CONFIG_GPROF)	+= gprof_syms.o
+obj-$(CONFIG_GCOV)	+= gmon_syms.o
+obj-$(CONFIG_TTY_LOG)	+= tty_log.o
+obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
+
+obj-$(CONFIG_MODE_TT) += tt/
+obj-$(CONFIG_MODE_SKAS) += skas/
+
+# This needs be compiled with frame pointers regardless of how the rest of the
+# kernel is built.
+CFLAGS_frame.o := -fno-omit-frame-pointer
+
+user-objs-$(CONFIG_TTY_LOG) += tty_log.o
+
+USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
+	time.o tty_log.o umid.o user_util.o frame.o
+
+include arch/um/scripts/Makefile.rules
+
+targets += config.c
+
+# Be careful with the below Sed code - sed is pitfall-rich!
+# We use sed to lower build requirements, for "embedded" builders for instance.
+
+$(obj)/config.tmp: $(objtree)/.config FORCE
+	$(call if_changed,quote1)
+
+quiet_cmd_quote1 = QUOTE   $@
+      cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
+		   $< > $@
+
+$(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
+	$(call if_changed,quote2)
+
+quiet_cmd_quote2 = QUOTE   $@
+      cmd_quote2 = sed -e '/CONFIG/{'          \
+		  -e 's/"CONFIG"\;/""/'        \
+		  -e 'r $(obj)/config.tmp'     \
+		  -e 'a""\;'                   \
+		  -e '}'                       \
+		  $< > $@
diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c
new file mode 100644
index 0000000..e69b2be
--- /dev/null
+++ b/arch/um/kernel/checksum.c
@@ -0,0 +1,36 @@
+#include "asm/uaccess.h"
+#include "linux/errno.h"
+#include "linux/module.h"
+
+unsigned int arch_csum_partial(const unsigned char *buff, int len, int sum);
+
+unsigned int csum_partial(unsigned char *buff, int len, int sum)
+{
+        return arch_csum_partial(buff, len, sum);
+}
+
+EXPORT_SYMBOL(csum_partial);
+
+unsigned int csum_partial_copy_to(const unsigned char *src,
+                                  unsigned char __user *dst, int len, int sum,
+                                  int *err_ptr)
+{
+        if(copy_to_user(dst, src, len)){
+                *err_ptr = -EFAULT;
+                return(-1);
+        }
+
+        return(arch_csum_partial(src, len, sum));
+}
+
+unsigned int csum_partial_copy_from(const unsigned char __user *src,
+                                    unsigned char *dst,	int len, int sum,
+                                    int *err_ptr)
+{
+        if(copy_from_user(dst, src, len)){
+                *err_ptr = -EFAULT;
+                return(-1);
+        }
+
+        return arch_csum_partial(dst, len, sum);
+}
diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
new file mode 100644
index 0000000..c062cbf
--- /dev/null
+++ b/arch/um/kernel/config.c.in
@@ -0,0 +1,32 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "init.h"
+
+static __initdata char *config = "CONFIG";
+
+static int __init print_config(char *line, int *add)
+{
+	printf("%s", config);
+	exit(0);
+}
+
+__uml_setup("--showconfig", print_config,
+"--showconfig\n"
+"    Prints the config file that this UML binary was generated from.\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 --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
new file mode 100644
index 0000000..715b083
--- /dev/null
+++ b/arch/um/kernel/dyn.lds.S
@@ -0,0 +1,176 @@
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  PROVIDE (__executable_start = START);
+  . = START + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
+   * is remapped.*/
+  __binary_start = .;
+  . = ALIGN(4096);		/* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .init.text : {
+	_sinittext = .;
+	*(.init.text)
+	_einittext = .;
+  }
+
+  . = ALIGN(4096);
+
+  /* Read-only sections, merged into text segment: */
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           : {
+    KEEP (*(.init))
+  } =0x90909090
+  .plt            : { *(.plt) }
+  .text           : {
+    *(.text)
+    SCHED_TEXT
+    LOCK_TEXT
+    *(.fixup)
+    *(.stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           : {
+    KEEP (*(.fini))
+  } =0x90909090
+
+  .kstrtab : { *(.kstrtab) }
+
+  #include "asm/common.lds.S"
+
+  init.data : { *(.init.data) }
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  .preinit_array     : { *(.preinit_array) }
+  .init_array     : { *(.init_array) }
+  .fini_array     : { *(.fini_array) }
+  .data           : {
+    . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
+    *(.data.init_task)
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          : {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          : {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            : {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  }
+  _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) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
new file mode 100644
index 0000000..49ddabe
--- /dev/null
+++ b/arch/um/kernel/exec_kern.c
@@ -0,0 +1,91 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/slab.h"
+#include "linux/smp_lock.h"
+#include "linux/ptrace.h"
+#include "asm/ptrace.h"
+#include "asm/pgtable.h"
+#include "asm/tlbflush.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"
+#include "os.h"
+#include "time_user.h"
+#include "choose-mode.h"
+#include "mode_kern.h"
+
+void flush_thread(void)
+{
+	CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
+}
+
+void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
+{
+	CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
+}
+
+extern void log_exec(char **argv, void *tty);
+
+static long execve1(char *file, char __user * __user *argv,
+		    char *__user __user *env)
+{
+        long error;
+
+#ifdef CONFIG_TTY_LOG
+	log_exec(argv, current->tty);
+#endif
+        error = do_execve(file, argv, env, &current->thread.regs);
+        if (error == 0){
+		task_lock(current);
+                current->ptrace &= ~PT_DTRACE;
+		task_unlock(current);
+                set_cmdline(current_cmd());
+        }
+        return(error);
+}
+
+long um_execve(char *file, char __user *__user *argv, char __user *__user *env)
+{
+	long err;
+
+	err = execve1(file, argv, env);
+	if(!err)
+		do_longjmp(current->thread.exec_buf, 1);
+	return(err);
+}
+
+long sys_execve(char *file, char __user *__user *argv,
+		char __user *__user *env)
+{
+	long error;
+	char *filename;
+
+	lock_kernel();
+	filename = getname((char __user *) 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 --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
new file mode 100644
index 0000000..0ea87f2
--- /dev/null
+++ b/arch/um/kernel/exitcode.c
@@ -0,0 +1,73 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/ctype.h"
+#include "linux/proc_fs.h"
+#include "asm/uaccess.h"
+
+/* If read and write race, the read will still atomically read a valid
+ * value.
+ */
+int uml_exitcode = 0;
+
+static int read_proc_exitcode(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", uml_exitcode);
+	len -= off;
+	if(len <= off+count) *eof = 1;
+	*start = page + off;
+	if(len > count) len = count;
+	if(len < 0) len = 0;
+	return(len);
+}
+
+static int write_proc_exitcode(struct file *file, const char __user *buffer,
+			       unsigned long count, void *data)
+{
+	char *end, buf[sizeof("nnnnn\0")];
+	int tmp;
+
+	if(copy_from_user(buf, buffer, count))
+		return(-EFAULT);
+	tmp = simple_strtol(buf, &end, 0);
+	if((*end != '\0') && !isspace(*end))
+		return(-EINVAL);
+	uml_exitcode = tmp;
+	return(count);
+}
+
+static int make_proc_exitcode(void)
+{
+	struct proc_dir_entry *ent;
+
+	ent = create_proc_entry("exitcode", 0600, &proc_root);
+	if(ent == NULL){
+		printk("make_proc_exitcode : Failed to register "
+		       "/proc/exitcode\n");
+		return(0);
+	}
+
+	ent->read_proc = read_proc_exitcode;
+	ent->write_proc = write_proc_exitcode;
+	
+	return(0);
+}
+
+__initcall(make_proc_exitcode);
+
+/*
+ * 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 --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
new file mode 100644
index 0000000..2c86e7f
--- /dev/null
+++ b/arch/um/kernel/gmon_syms.c
@@ -0,0 +1,34 @@
+/* 
+ * 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);
+
+/* This is defined (and referred to in profiling stub code) only by some GCC
+ * versions in libgcov.
+ *
+ * Since SuSE backported the fix, we cannot handle it depending on GCC version.
+ * So, unconditinally export it. But also give it a weak declaration, which will
+ * be overriden by any other one.
+ */
+
+extern void __gcov_init(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_init);
+
+extern void __gcov_merge_add(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_merge_add);
+
+/*
+ * 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 --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
new file mode 100644
index 0000000..9244f01
--- /dev/null
+++ b/arch/um/kernel/gprof_syms.c
@@ -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 --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
new file mode 100644
index 0000000..13b1f5c
--- /dev/null
+++ b/arch/um/kernel/helper.c
@@ -0,0 +1,173 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+
+struct helper_data {
+	void (*pre_exec)(void*);
+	void *pre_data;
+	char **argv;
+	int fd;
+};
+
+/* Debugging aid, changed only from gdb */
+int helper_pause = 0;
+
+static void helper_hup(int sig)
+{
+}
+
+static int helper_child(void *arg)
+{
+	struct helper_data *data = arg;
+	char **argv = data->argv;
+	int errval;
+
+	if(helper_pause){
+		signal(SIGHUP, helper_hup);
+		pause();
+	}
+	if(data->pre_exec != NULL)
+		(*data->pre_exec)(data->pre_data);
+	execvp(argv[0], argv);
+	errval = errno;
+	printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
+	os_write_file(data->fd, &errval, sizeof(errval));
+	os_kill_process(os_getpid(), 0);
+	return(0);
+}
+
+/* Returns either the pid of the child process we run or -E* on failure.
+ * XXX The alloc_stack here breaks if this is called in the tracing thread */
+int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
+	       unsigned long *stack_out)
+{
+	struct helper_data data;
+	unsigned long stack, sp;
+	int pid, fds[2], ret, n;
+
+	if((stack_out != NULL) && (*stack_out != 0))
+		stack = *stack_out;
+	else stack = alloc_stack(0, um_in_interrupt());
+	if(stack == 0)
+		return(-ENOMEM);
+
+	ret = os_pipe(fds, 1, 0);
+	if(ret < 0){
+		printk("run_helper : pipe failed, ret = %d\n", -ret);
+		goto out_free;
+	}
+
+	ret = os_set_exec_close(fds[1], 1);
+	if(ret < 0){
+		printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
+		       -ret);
+		goto out_close;
+	}
+
+	sp = stack + page_size() - sizeof(void *);
+	data.pre_exec = pre_exec;
+	data.pre_data = pre_data;
+	data.argv = argv;
+	data.fd = fds[1];
+	pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
+	if(pid < 0){
+		printk("run_helper : clone failed, errno = %d\n", errno);
+		ret = -errno;
+		goto out_close;
+	}
+
+	os_close_file(fds[1]);
+	fds[1] = -1;
+
+	/*Read the errno value from the child.*/
+	n = os_read_file(fds[0], &ret, sizeof(ret));
+	if(n < 0){
+		printk("run_helper : read on pipe failed, ret = %d\n", -n);
+		ret = n;
+		os_kill_process(pid, 1);
+	}
+	else if(n != 0){
+		CATCH_EINTR(n = waitpid(pid, NULL, 0));
+		ret = -errno;
+	} else {
+		ret = pid;
+	}
+
+out_close:
+	if (fds[1] != -1)
+		os_close_file(fds[1]);
+	os_close_file(fds[0]);
+out_free:
+	if(stack_out == NULL)
+		free_stack(stack, 0);
+	else *stack_out = stack;
+	return(ret);
+}
+
+int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, 
+		      unsigned long *stack_out, int stack_order)
+{
+	unsigned long stack, sp;
+	int pid, status;
+
+	stack = alloc_stack(stack_order, um_in_interrupt());
+	if(stack == 0) return(-ENOMEM);
+
+	sp = stack + (page_size() << stack_order) - sizeof(void *);
+	pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
+	if(pid < 0){
+		printk("run_helper_thread : clone failed, errno = %d\n", 
+		       errno);
+		return(-errno);
+	}
+	if(stack_out == NULL){
+		CATCH_EINTR(pid = waitpid(pid, &status, 0));
+		if(pid < 0){
+			printk("run_helper_thread - wait failed, errno = %d\n",
+			       errno);
+			pid = -errno;
+		}
+		if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+			printk("run_helper_thread - thread returned status "
+			       "0x%x\n", status);
+		free_stack(stack, stack_order);
+	}
+	else *stack_out = stack;
+	return(pid);
+}
+
+int helper_wait(int pid, int block)
+{
+	int ret;
+
+	CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
+	if(ret < 0){
+		printk("helper_wait : waitpid failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	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 --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
new file mode 100644
index 0000000..cd7c85b
--- /dev/null
+++ b/arch/um/kernel/init_task.c
@@ -0,0 +1,61 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "linux/module.h"
+#include "linux/sched.h"
+#include "linux/init_task.h"
+#include "linux/mqueue.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;
+struct mm_struct init_mm = INIT_MM(init_mm);
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
+/*
+ * Initial thread 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 thread_union init_thread_union 
+__attribute__((__section__(".data.init_task"))) = 
+{ INIT_THREAD_INFO(init_task) };
+
+void unprotect_stack(unsigned long stack)
+{
+	protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 
+		       1, 1, 0, 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 --git a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c
new file mode 100644
index 0000000..fc568af
--- /dev/null
+++ b/arch/um/kernel/initrd_kern.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/initrd.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+
+/* Changed by uml_initrd_setup, which is a setup */
+static char *initrd __initdata = NULL;
+
+static int __init read_initrd(void)
+{
+	void *area;
+	long long size;
+	int err;
+
+	if(initrd == NULL) return 0;
+	err = os_file_size(initrd, &size);
+	if(err) 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 --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
new file mode 100644
index 0000000..cb90681
--- /dev/null
+++ b/arch/um/kernel/initrd_user.c
@@ -0,0 +1,46 @@
+/*
+ * 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 <errno.h>
+
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "initrd.h"
+#include "os.h"
+
+int load_initrd(char *filename, void *buf, int size)
+{
+	int fd, n;
+
+	fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
+	if(fd < 0){
+		printk("Opening '%s' failed - err = %d\n", filename, -fd);
+		return(-1);
+	}
+	n = os_read_file(fd, buf, size);
+	if(n != size){
+		printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+		       filename, -n);
+		return(-1);
+	}
+
+	os_close_file(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 --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
new file mode 100644
index 0000000..d71e8f0
--- /dev/null
+++ b/arch/um/kernel/irq.c
@@ -0,0 +1,178 @@
+/* 
+ * 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/module.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 "linux/profile.h"
+#include "linux/hardirq.h"
+#include "asm/irq.h"
+#include "asm/hw_irq.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"
+#include "irq_kern.h"
+
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v, j;
+	struct irqaction * action;
+	unsigned long flags;
+
+	if (i == 0) {
+		seq_printf(p, "           ");
+		for_each_online_cpu(j)
+			seq_printf(p, "CPU%d       ",j);
+		seq_putc(p, '\n');
+	}
+
+	if (i < NR_IRQS) {
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
+		action = irq_desc[i].action;
+		if (!action) 
+			goto skip;
+		seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+		for_each_online_cpu(j)
+			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+		seq_printf(p, " %14s", irq_desc[i].handler->typename);
+		seq_printf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+
+		seq_putc(p, '\n');
+skip:
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+	} else if (i == NR_IRQS) {
+		seq_putc(p, '\n');
+	}
+
+	return 0;
+}
+
+/*
+ * 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, union uml_pt_regs *regs)
+{
+       irq_enter();
+       __do_IRQ(irq, (struct pt_regs *) regs);
+       irq_exit();
+       return 1;
+}
+
+int um_request_irq(unsigned int irq, int fd, int type,
+		   irqreturn_t (*handler)(int, void *, struct pt_regs *),
+		   unsigned long irqflags, const char * devname,
+		   void *dev_id)
+{
+	int err;
+
+	err = request_irq(irq, handler, irqflags, devname, dev_id);
+	if(err)
+		return(err);
+
+	if(fd != -1)
+		err = activate_fd(irq, fd, type, dev_id);
+	return(err);
+}
+EXPORT_SYMBOL(um_request_irq);
+EXPORT_SYMBOL(reactivate_fd);
+
+static DEFINE_SPINLOCK(irq_spinlock);
+
+unsigned long irq_lock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq_spinlock, flags);
+	return(flags);
+}
+
+void irq_unlock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&irq_spinlock, flags);
+}
+
+/*  presently hw_interrupt_type must define (startup || enable) &&
+ *  disable && end */
+static void dummy(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type SIGIO_irq_type = {
+	.typename = "SIGIO",
+	.disable = dummy,
+	.enable = dummy,
+	.ack = dummy,
+	.end = dummy
+};
+
+static struct hw_interrupt_type SIGVTALRM_irq_type = {
+	.typename = "SIGVTALRM",
+	.shutdown = dummy, /* never called */
+	.disable = dummy,
+	.enable = dummy,
+	.ack = dummy,
+	.end = dummy
+};
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
+	irq_desc[TIMER_IRQ].action = NULL;
+	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 = NULL;
+		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 --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
new file mode 100644
index 0000000..6d6f948
--- /dev/null
+++ b/arch/um/kernel/irq_user.c
@@ -0,0 +1,443 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.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"
+#include "os.h"
+
+struct irq_fd {
+	struct irq_fd *next;
+	void *id;
+	int fd;
+	int type;
+	int irq;
+	int pid;
+	int events;
+	int current_events;
+	int freed;
+};
+
+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, union uml_pt_regs *regs)
+{
+	struct irq_fd *irq_fd, *next;
+	int i, n;
+
+	if(smp_sigio_handler()) return;
+	while(1){
+		n = poll(pollfds, pollfds_num, 0);
+		if(n < 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].fd = -1;
+			}
+			irq_fd = irq_fd->next;
+		}
+
+		for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
+			next = irq_fd->next;
+			if(irq_fd->current_events != 0){
+				irq_fd->current_events = 0;
+				do_IRQ(irq_fd->irq, regs);
+
+				/* This is here because the next irq may be
+				 * freed in the handler.  If a console goes
+				 * away, both the read and write irqs will be
+				 * freed.  After do_IRQ, ->next will point to
+				 * a good IRQ.
+				 * Irqs can't be freed inside their handlers,
+				 * so the next best thing is to have them
+				 * marked as needing freeing, so that they
+				 * can be freed here.
+				 */
+				next = irq_fd->next;
+				if(irq_fd->freed){
+					free_irq(irq_fd->irq, irq_fd->id);
+					free_irq_by_irq_and_dev(irq_fd->irq,
+								irq_fd->id);
+				}
+			}
+		}
+	}
+}
+
+int activate_ipi(int fd, int pid)
+{
+	return(os_set_fd_async(fd, pid));
+}
+
+static void maybe_sigio_broken(int fd, int type)
+{
+	if(isatty(fd)){
+		if((type == IRQ_WRITE) && !pty_output_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 0);
+		}
+		else if((type == IRQ_READ) && !pty_close_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 1);			
+		}
+	}
+}
+
+int activate_fd(int irq, int fd, int type, void *dev_id)
+{
+	struct pollfd *tmp_pfd;
+	struct irq_fd *new_fd, *irq_fd;
+	unsigned long flags;
+	int pid, events, err, n, size;
+
+	pid = os_getpid();
+	err = os_set_fd_async(fd, pid);
+	if(err < 0)
+		goto out;
+
+	new_fd = um_kmalloc(sizeof(*new_fd));
+	err = -ENOMEM;
+	if(new_fd == NULL)
+		goto out;
+
+	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,
+				     .freed 		= 0  } );
+
+	/* Critical section - locked by a spinlock because this stuff can
+	 * be changed from interrupt handlers.  The stuff above is done 
+	 * outside the lock because it allocates memory.
+	 */
+
+	/* Actually, it only looks like it can be called from interrupt
+	 * context.  The culprit is reactivate_fd, which calls 
+	 * maybe_sigio_broken, which calls write_sigio_workaround,
+	 * which calls activate_fd.  However, write_sigio_workaround should
+	 * only be called once, at boot time.  That would make it clear that
+	 * this is called only from process context, and can be locked with
+	 * a semaphore.
+	 */
+	flags = irq_lock();
+	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+		if((irq_fd->fd == fd) && (irq_fd->type == type)){
+			printk("Registering fd %d twice\n", fd);
+			printk("Irqs : %d, %d\n", irq_fd->irq, irq);
+			printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
+			goto out_unlock;
+		}
+	}
+
+	n = pollfds_num;
+	if(n == pollfds_size){
+		while(1){
+			/* Here we have to drop the lock in order to call 
+			 * kmalloc, which might sleep.  If something else
+			 * came in and changed the pollfds array, we free
+			 * the buffer and try again.
+			 */
+			irq_unlock(flags);
+			size = (pollfds_num + 1) * sizeof(pollfds[0]);
+			tmp_pfd = um_kmalloc(size);
+			flags = irq_lock();
+			if(tmp_pfd == NULL)
+				goto out_unlock;
+			if(n == pollfds_size)
+				break;
+			kfree(tmp_pfd);
+		}
+		if(pollfds != NULL){
+			memcpy(tmp_pfd, pollfds,
+			       sizeof(pollfds[0]) * pollfds_size);
+			kfree(pollfds);
+		}
+		pollfds = tmp_pfd;
+		pollfds_size++;
+	}
+
+	if(type == IRQ_WRITE) 
+		fd = -1;
+
+	pollfds[pollfds_num] = ((struct pollfd) { .fd 	= fd,
+						  .events 	= events,
+						  .revents 	= 0 });
+	pollfds_num++;
+
+	*last_irq_ptr = new_fd;
+	last_irq_ptr = &new_fd->next;
+
+	irq_unlock(flags);
+
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
+	maybe_sigio_broken(fd, type);
+
+	return(0);
+
+ out_unlock:
+	irq_unlock(flags);
+	kfree(new_fd);
+ out:
+	return(err);
+}
+
+static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+{
+	struct irq_fd **prev;
+	unsigned long flags;
+	int i = 0;
+
+	flags = irq_lock();
+	prev = &active_fds;
+	while(*prev != NULL){
+		if((*test)(*prev, arg)){
+			struct irq_fd *old_fd = *prev;
+			if((pollfds[i].fd != -1) && 
+			   (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);
+				goto out;
+			}
+			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++;
+	}
+ out:
+	irq_unlock(flags);
+}
+
+struct irq_and_dev {
+	int irq;
+	void *dev;
+};
+
+static int same_irq_and_dev(struct irq_fd *irq, void *d)
+{
+	struct irq_and_dev *data = d;
+
+	return((irq->irq == data->irq) && (irq->id == data->dev));
+}
+
+void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
+{
+	struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
+							  .dev  = dev });
+
+	free_irq_by_cb(same_irq_and_dev, &data);
+}
+
+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);
+		goto out;
+	}
+	if((pollfds[i].fd != -1) && (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);
+		irq = NULL;
+		goto out;
+	}
+	*index_out = i;
+ out:
+	return(irq);
+}
+
+void free_irq_later(int irq, void *dev_id)
+{
+	struct irq_fd *irq_fd;
+	unsigned long flags;
+
+	flags = irq_lock();
+	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+		if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
+			break;
+	}
+	if(irq_fd == NULL){
+		printk("free_irq_later found no irq, irq = %d, "
+		       "dev_id = 0x%p\n", irq, dev_id);
+		goto out;
+	}
+	irq_fd->freed = 1;
+ out:
+	irq_unlock(flags);
+}
+
+void reactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int i;
+
+	flags = irq_lock();
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL){
+		irq_unlock(flags);
+		return;
+	}
+
+	pollfds[i].fd = irq->fd;
+
+	irq_unlock(flags);
+
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
+	maybe_sigio_broken(fd, irq->type);
+}
+
+void deactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int i;
+
+	flags = irq_lock();
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL)
+		goto out;
+	pollfds[i].fd = -1;
+ out:
+	irq_unlock(flags);
+}
+
+int deactivate_all_fds(void)
+{
+	struct irq_fd *irq;
+	int err;
+
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		err = os_clear_fd_async(irq->fd);
+		if(err)
+			return(err);
+	}
+	/* If there is a signal already queued, after unblocking ignore it */
+	set_handler(SIGIO, SIG_IGN, 0, -1);
+
+	return(0);
+}
+
+void forward_ipi(int fd, int pid)
+{
+	int err;
+
+	err = os_set_owner(fd, pid);
+	if(err < 0)
+		printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
+		       "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
+}
+
+void forward_interrupts(int pid)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int err;
+
+	flags = irq_lock();
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		err = os_set_owner(irq->fd, pid);
+		if(err < 0){
+			/* XXX Just remove the irq rather than
+			 * print out an infinite stream of these
+			 */
+			printk("Failed to forward %d to pid %d, err = %d\n",
+			       irq->fd, pid, -err);
+		}
+
+		irq->pid = pid;
+	}
+	irq_unlock(flags);
+}
+
+void init_irq_signals(int on_sigstack)
+{
+	__sighandler_t h;
+	int flags;
+
+	flags = on_sigstack ? SA_ONSTACK : 0;
+	if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
+	else h = boot_timer_handler;
+
+	set_handler(SIGVTALRM, h, flags | SA_RESTART, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
+	set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -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 --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
new file mode 100644
index 0000000..b41d339
--- /dev/null
+++ b/arch/um/kernel/ksyms.c
@@ -0,0 +1,137 @@
+/* 
+ * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/module.h"
+#include "linux/string.h"
+#include "linux/smp_lock.h"
+#include "linux/spinlock.h"
+#include "linux/highmem.h"
+#include "asm/current.h"
+#include "asm/delay.h"
+#include "asm/processor.h"
+#include "asm/unistd.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
+#include "asm/page.h"
+#include "asm/tlbflush.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "os.h"
+#include "helper.h"
+
+EXPORT_SYMBOL(stop);
+EXPORT_SYMBOL(uml_physmem);
+EXPORT_SYMBOL(set_signals);
+EXPORT_SYMBOL(get_signals);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(sys_waitpid);
+EXPORT_SYMBOL(task_size);
+EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(host_task_size);
+EXPORT_SYMBOL(arch_validate);
+EXPORT_SYMBOL(get_kmem_end);
+
+EXPORT_SYMBOL(page_to_phys);
+EXPORT_SYMBOL(phys_to_page);
+EXPORT_SYMBOL(high_physmem);
+EXPORT_SYMBOL(empty_zero_page);
+EXPORT_SYMBOL(um_virt_to_phys);
+EXPORT_SYMBOL(__virt_to_page);
+EXPORT_SYMBOL(to_phys);
+EXPORT_SYMBOL(to_virt);
+EXPORT_SYMBOL(mode_tt);
+EXPORT_SYMBOL(handle_page_fault);
+EXPORT_SYMBOL(find_iomem);
+EXPORT_SYMBOL(end_iomem);
+
+#ifdef CONFIG_MODE_TT
+EXPORT_SYMBOL(strncpy_from_user_tt);
+EXPORT_SYMBOL(copy_from_user_tt);
+EXPORT_SYMBOL(copy_to_user_tt);
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+EXPORT_SYMBOL(strncpy_from_user_skas);
+EXPORT_SYMBOL(copy_to_user_skas);
+EXPORT_SYMBOL(copy_from_user_skas);
+#endif
+EXPORT_SYMBOL(uml_strdup);
+
+EXPORT_SYMBOL(os_stat_fd);
+EXPORT_SYMBOL(os_stat_file);
+EXPORT_SYMBOL(os_access);
+EXPORT_SYMBOL(os_print_error);
+EXPORT_SYMBOL(os_get_exec_close);
+EXPORT_SYMBOL(os_set_exec_close);
+EXPORT_SYMBOL(os_getpid);
+EXPORT_SYMBOL(os_open_file);
+EXPORT_SYMBOL(os_read_file);
+EXPORT_SYMBOL(os_write_file);
+EXPORT_SYMBOL(os_seek_file);
+EXPORT_SYMBOL(os_lock_file);
+EXPORT_SYMBOL(os_ioctl_generic);
+EXPORT_SYMBOL(os_pipe);
+EXPORT_SYMBOL(os_file_type);
+EXPORT_SYMBOL(os_file_mode);
+EXPORT_SYMBOL(os_file_size);
+EXPORT_SYMBOL(os_flush_stdout);
+EXPORT_SYMBOL(os_close_file);
+EXPORT_SYMBOL(os_set_fd_async);
+EXPORT_SYMBOL(os_set_fd_block);
+EXPORT_SYMBOL(helper_wait);
+EXPORT_SYMBOL(os_shutdown_socket);
+EXPORT_SYMBOL(os_create_unix_socket);
+EXPORT_SYMBOL(os_connect_socket);
+EXPORT_SYMBOL(os_accept_connection);
+EXPORT_SYMBOL(os_rcv_fd);
+EXPORT_SYMBOL(run_helper);
+EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(dump_thread);
+
+EXPORT_SYMBOL(do_gettimeofday);
+EXPORT_SYMBOL(do_settimeofday);
+
+/* This is here because UML expands open to sys_open, not to a system
+ * call instruction.
+ */
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_wait4);
+
+#ifdef CONFIG_SMP
+
+/* required for SMP */
+
+extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
+EXPORT_SYMBOL(__write_lock_failed);
+
+extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
+EXPORT_SYMBOL(__read_lock_failed);
+
+#endif
+
+#ifdef CONFIG_HIGHMEM
+EXPORT_SYMBOL(kmap);
+EXPORT_SYMBOL(kunmap);
+EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(kunmap_atomic);
+EXPORT_SYMBOL(kmap_atomic_to_page);
+#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 --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
new file mode 100644
index 0000000..a17c497
--- /dev/null
+++ b/arch/um/kernel/main.c
@@ -0,0 +1,271 @@
+/*
+ * 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 <errno.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 "signal_user.h"
+#include "time_user.h"
+#include "irq_user.h"
+#include "user.h"
+#include "init.h"
+#include "mode.h"
+#include "choose-mode.h"
+#include "uml-config.h"
+#include "irq_user.h"
+#include "time_user.h"
+#include "os.h"
+
+/* Set in set_stklim, which is called from main and __wrap_malloc.
+ * __wrap_malloc only calls it if main hasn't started.
+ */
+unsigned long stacksizelim;
+
+/* Set in main */
+char *linux_prog;
+
+#define PGD_BOUND (4 * 1024 * 1024)
+#define STACKSIZE (8 * 1024 * 1024)
+#define THREAD_NAME_LEN (256)
+
+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++;
+	}
+}
+
+static void last_ditch_exit(int sig)
+{
+	CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
+	signal(SIGINT, SIG_DFL);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGHUP, SIG_DFL);
+	uml_cleanup();
+	exit(1);
+}
+
+extern int uml_exitcode;
+
+extern void scan_elf_aux( char **envp);
+
+int main(int argc, char **argv, char **envp)
+{
+	char **new_argv;
+	sigset_t mask;
+	int ret, i;
+
+	/* Enable all signals except SIGIO - in some environments, we can
+	 * enter with some signals blocked
+	 */
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGIO);
+	if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
+		perror("sigprocmask");
+		exit(1);
+	}
+
+#ifdef UML_CONFIG_MODE_TT
+	/* Allocate memory for thread command lines */
+	if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
+
+		char padding[THREAD_NAME_LEN] = {
+			[ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0'
+		};
+
+		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;
+
+		execvp(new_argv[0], new_argv);
+		perror("execing with extended args");
+		exit(1);
+	}
+#endif
+
+	linux_prog = argv[0];
+
+	set_stklim();
+
+	new_argv = malloc((argc + 1) * sizeof(char *));
+	if(new_argv == NULL){
+		perror("Mallocing argv");
+		exit(1);
+	}
+	for(i=0;i<argc;i++){
+		new_argv[i] = strdup(argv[i]);
+		if(new_argv[i] == NULL){
+			perror("Mallocing an arg");
+			exit(1);
+		}
+	}
+	new_argv[argc] = NULL;
+
+	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);
+
+	scan_elf_aux( envp);
+
+	do_uml_initcalls();
+	ret = linux_main(argc, argv);
+
+	/* Disable SIGPROF - I have no idea why libc doesn't do this or turn
+	 * off the profiling time, but UML dies with a SIGPROF just before
+	 * exiting when profiling is active.
+	 */
+	change_sig(SIGPROF, 0);
+
+	/* Reboot */
+	if(ret){
+		int err;
+
+		printf("\n");
+
+		/* stop timers and set SIG*ALRM to be ignored */
+		disable_timer();
+
+		/* disable SIGIO for the fds and set SIGIO to be ignored */
+		err = deactivate_all_fds();
+		if(err)
+			printf("deactivate_all_fds failed, errno = %d\n",
+			       -err);
+
+		/* Let any pending signals fire now.  This ensures
+		 * that they won't be delivered after the exec, when
+		 * they are definitely not expected.
+		 */
+		unblock_signals();
+
+		execvp(new_argv[0], new_argv);
+		perror("Failed to exec kernel");
+		ret = 1;
+	}
+	printf("\n");
+	return(uml_exitcode);
+}
+
+#define CAN_KMALLOC() \
+	(kmalloc_ok && CHOOSE_MODE((os_getpid() != tracing_pid), 1))
+
+extern void *__real_malloc(int);
+
+void *__wrap_malloc(int size)
+{
+	void *ret;
+
+	if(!CAN_KMALLOC())
+		return(__real_malloc(size));
+	else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
+		ret = um_kmalloc(size);
+	else ret = um_vmalloc(size);
+
+	/* glibc people insist that if malloc fails, errno should be
+	 * set by malloc as well. So we do.
+	 */
+	if(ret == NULL)
+		errno = ENOMEM;
+
+	return(ret);
+}
+
+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 *);
+
+extern unsigned long high_physmem;
+
+void __wrap_free(void *ptr)
+{
+	unsigned long addr = (unsigned long) ptr;
+
+	/* We need to know how the allocation happened, so it can be correctly
+	 * freed.  This is done by seeing what region of memory the pointer is
+	 * in -
+	 * 	physical memory - kmalloc/kfree
+	 *	kernel virtual memory - vmalloc/vfree
+	 * 	anywhere else - malloc/free
+	 * If kmalloc is not yet possible, then either high_physmem and/or
+	 * end_vm are still 0 (as at startup), in which case we call free, or
+	 * we have set them, but anyway addr has not been allocated from those
+	 * areas. So, in both cases __real_free is called.
+	 *
+	 * CAN_KMALLOC is checked because it would be bad to free a buffer
+	 * with kmalloc/vmalloc after they have been turned off during
+	 * shutdown.
+	 * XXX: However, we sometimes shutdown CAN_KMALLOC temporarily, so
+	 * there is a possibility for memory leaks.
+	 */
+
+	if((addr >= uml_physmem) && (addr < high_physmem)){
+		if(CAN_KMALLOC())
+			kfree(ptr);
+	}
+	else if((addr >= start_vm) && (addr < end_vm)){
+		if(CAN_KMALLOC())
+			vfree(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 --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
new file mode 100644
index 0000000..f156661
--- /dev/null
+++ b/arch/um/kernel/mem.c
@@ -0,0 +1,359 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/mm.h"
+#include "linux/bootmem.h"
+#include "linux/swap.h"
+#include "linux/highmem.h"
+#include "linux/gfp.h"
+#include "asm/page.h"
+#include "asm/fixmap.h"
+#include "asm/pgalloc.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mem_user.h"
+#include "uml_uaccess.h"
+#include "os.h"
+
+extern char __binary_start;
+
+/* Changed during early boot */
+unsigned long *empty_zero_page = NULL;
+unsigned long *empty_bad_page = NULL;
+pgd_t swapper_pg_dir[PTRS_PER_PGD];
+unsigned long highmem;
+int kmalloc_ok = 0;
+
+static unsigned long brk_end;
+
+void unmap_physmem(void)
+{
+	os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
+}
+
+static void map_cb(void *unused)
+{
+	map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+}
+
+#ifdef CONFIG_HIGHMEM
+static void setup_highmem(unsigned long highmem_start,
+			  unsigned long highmem_len)
+{
+	struct page *page;
+	unsigned long highmem_pfn;
+	int i;
+
+	highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
+	for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
+		page = &mem_map[highmem_pfn + i];
+		ClearPageReserved(page);
+		set_bit(PG_highmem, &page->flags);
+		set_page_count(page, 1);
+		__free_page(page);
+	}
+}
+#endif
+
+void mem_init(void)
+{
+	unsigned long start;
+
+	max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT;
+
+        /* clear the zero-page */
+        memset((void *) empty_zero_page, 0, PAGE_SIZE);
+
+	/* Map in the area just after the brk now that kmalloc is about
+	 * to be turned on.
+	 */
+	brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
+	map_cb(NULL);
+	initial_thread_cb(map_cb, NULL);
+	free_bootmem(__pa(brk_end), uml_reserved - brk_end);
+	uml_reserved = brk_end;
+
+	/* Fill in any hole at the start of the binary */
+	start = (unsigned long) &__binary_start & PAGE_MASK;
+	if(uml_physmem != start){
+		map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
+			   1, 1, 0);
+	}
+
+	/* this will put all low memory onto the freelists */
+	totalram_pages = free_all_bootmem();
+	totalhigh_pages = highmem >> PAGE_SHIFT;
+	totalram_pages += totalhigh_pages;
+	num_physpages = totalram_pages;
+	max_pfn = totalram_pages;
+	printk(KERN_INFO "Memory: %luk available\n", 
+	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
+	kmalloc_ok = 1;
+
+#ifdef CONFIG_HIGHMEM
+	setup_highmem(end_iomem, highmem);
+#endif
+}
+
+static void __init fixrange_init(unsigned long start, unsigned long end, 
+				 pgd_t *pgd_base)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	int i, j;
+	unsigned long vaddr;
+
+	vaddr = start;
+	i = pgd_index(vaddr);
+	j = pmd_index(vaddr);
+	pgd = pgd_base + i;
+
+	for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
+		pmd = (pmd_t *)pgd;
+		for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+			if (pmd_none(*pmd)) {
+				pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+				set_pmd(pmd, __pmd(_KERNPG_TABLE + 
+						   (unsigned long) __pa(pte)));
+				if (pte != pte_offset_kernel(pmd, 0))
+					BUG();
+			}
+			vaddr += PMD_SIZE;
+		}
+		j = 0;
+	}
+}
+
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+#define kmap_get_fixmap_pte(vaddr)					\
+	pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
+ 			  (vaddr)), (vaddr))
+
+static void __init kmap_init(void)
+{
+	unsigned long kmap_vstart;
+
+	/* cache the first kmap pte */
+	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+
+	kmap_prot = PAGE_KERNEL;
+}
+
+static void init_highmem(void)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long vaddr;
+
+	/*
+	 * Permanent kmaps:
+	 */
+	vaddr = PKMAP_BASE;
+	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
+
+	pgd = swapper_pg_dir + pgd_index(vaddr);
+	pud = pud_offset(pgd, vaddr);
+	pmd = pmd_offset(pud, vaddr);
+	pte = pte_offset_kernel(pmd, vaddr);
+	pkmap_page_table = pte;
+
+	kmap_init();
+}
+#endif /* CONFIG_HIGHMEM */
+
+static void __init fixaddr_user_init( void)
+{
+#if CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
+	long size = FIXADDR_USER_END - FIXADDR_USER_START;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long paddr, vaddr = FIXADDR_USER_START;
+
+	if (  ! size )
+		return;
+
+	fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
+	paddr = (unsigned long)alloc_bootmem_low_pages( size);
+	memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
+	paddr = __pa(paddr);
+	for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
+		pgd = swapper_pg_dir + pgd_index(vaddr);
+		pud = pud_offset(pgd, vaddr);
+		pmd = pmd_offset(pud, vaddr);
+		pte = pte_offset_kernel(pmd, vaddr);
+		pte_set_val( (*pte), paddr, PAGE_READONLY);
+	}
+#endif
+}
+
+void paging_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES], vaddr;
+	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[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
+	zones_size[2] = highmem >> PAGE_SHIFT;
+	free_area_init(zones_size);
+
+	/*
+	 * Fixed mappings, only the page table structure has to be
+	 * created - mappings will be set by set_fixmap():
+	 */
+	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+	fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
+
+	fixaddr_user_init();
+
+#ifdef CONFIG_HIGHMEM
+	init_highmem();
+#endif
+}
+
+struct page *arch_validate(struct page *page, int mask, int order)
+{
+	unsigned long addr, zero = 0;
+	int i;
+
+ again:
+	if(page == NULL) return(page);
+	if(PageHighMem(page)) 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 __user *) 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;
+}
+
+/* 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
+
+void show_mem(void)
+{
+        int pfn, total = 0, reserved = 0;
+        int shared = 0, cached = 0;
+        int highmem = 0;
+	struct page *page;
+
+        printk("Mem-info:\n");
+        show_free_areas();
+        printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+        pfn = max_mapnr;
+        while(pfn-- > 0) {
+		page = pfn_to_page(pfn);
+                total++;
+                if(PageHighMem(page))
+                        highmem++;
+                if(PageReserved(page))
+                        reserved++;
+                else if(PageSwapCache(page))
+                        cached++;
+                else if(page_count(page))
+                        shared += page_count(page) - 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);
+}
+
+/*
+ * Allocate and free page tables.
+ */
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	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;
+}
+
+void pgd_free(pgd_t *pgd)
+{
+	free_page((unsigned long) pgd);
+}
+
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+
+	pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+	return pte;
+}
+
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	struct page *pte;
+   
+	pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+	return pte;
+}
+
+/*
+ * 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 --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
new file mode 100644
index 0000000..4a663fd
--- /dev/null
+++ b/arch/um/kernel/mem_user.c
@@ -0,0 +1,273 @@
+/*
+ * 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 <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "kern_util.h"
+#include "user.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "init.h"
+#include "os.h"
+#include "tempfile.h"
+#include "kern_constants.h"
+
+#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
+
+static int create_tmp_file(unsigned long len)
+{
+	int fd, err;
+	char zero;
+
+	fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
+	if(fd < 0) {
+		os_print_error(fd, "make_tempfile");
+		exit(1);
+	}
+
+	err = os_mode_fd(fd, 0777);
+	if(err < 0){
+		os_print_error(err, "os_mode_fd");
+		exit(1);
+	}
+	err = os_seek_file(fd, len);
+	if(err < 0){
+		os_print_error(err, "os_seek_file");
+		exit(1);
+	}
+	zero = 0;
+	err = os_write_file(fd, &zero, 1);
+	if(err != 1){
+		os_print_error(err, "os_write_file");
+		exit(1);
+	}
+
+	return(fd);
+}
+
+void check_tmpexec(void)
+{
+	void *addr;
+	int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
+
+	addr = mmap(NULL, UM_KERN_PAGE_SIZE,
+		    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
+	printf("Checking PROT_EXEC mmap in /tmp...");
+	fflush(stdout);
+	if(addr == MAP_FAILED){
+		err = errno;
+		perror("failed");
+		if(err == EPERM)
+			printf("/tmp must be not mounted noexec\n");
+		exit(1);
+	}
+	printf("OK\n");
+	munmap(addr, UM_KERN_PAGE_SIZE);
+
+	os_close_file(fd);
+}
+
+static int have_devanon = 0;
+
+void check_devanon(void)
+{
+	int fd;
+
+	printk("Checking for /dev/anon on the host...");
+	fd = open("/dev/anon", O_RDWR);
+	if(fd < 0){
+		printk("Not available (open failed with errno %d)\n", errno);
+		return;
+	}
+
+	printk("OK\n");
+	have_devanon = 1;
+}
+
+static int create_anon_file(unsigned long len)
+{
+	void *addr;
+	int fd;
+
+	fd = open("/dev/anon", O_RDWR);
+	if(fd < 0) {
+		os_print_error(fd, "opening /dev/anon");
+		exit(1);
+	}
+
+	addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	if(addr == MAP_FAILED){
+		perror("mapping physmem file");
+		exit(1);
+	}
+	munmap(addr, len);
+
+	return(fd);
+}
+
+int create_mem_file(unsigned long len)
+{
+	int err, fd;
+
+	if(have_devanon)
+		fd = create_anon_file(len);
+	else fd = create_tmp_file(len);
+
+	err = os_set_exec_close(fd, 1);
+	if(err < 0)
+		os_print_error(err, "exec_close");
+	return(fd);
+}
+
+struct iomem_region *iomem_regions = NULL;
+int iomem_size = 0;
+
+static int __init parse_iomem(char *str, int *add)
+{
+	struct iomem_region *new;
+	struct uml_stat buf;
+	char *file, *driver;
+	int fd, err, size;
+
+	driver = str;
+	file = strchr(str,',');
+	if(file == NULL){
+		printf("parse_iomem : failed to parse iomem\n");
+		goto out;
+	}
+	*file = '\0';
+	file++;
+	fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
+	if(fd < 0){
+		os_print_error(fd, "parse_iomem - Couldn't open io file");
+		goto out;
+	}
+
+	err = os_stat_fd(fd, &buf);
+	if(err < 0){
+		os_print_error(err, "parse_iomem - cannot stat_fd file");
+		goto out_close;
+	}
+
+	new = malloc(sizeof(*new));
+	if(new == NULL){
+		perror("Couldn't allocate iomem_region struct");
+		goto out_close;
+	}
+
+	size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
+
+	*new = ((struct iomem_region) { .next		= iomem_regions,
+					.driver		= driver,
+					.fd		= fd,
+					.size		= size,
+					.phys		= 0,
+					.virt		= 0 });
+	iomem_regions = new;
+	iomem_size += new->size + UM_KERN_PAGE_SIZE;
+
+	return(0);
+ out_close:
+	os_close_file(fd);
+ out:
+	return(1);
+}
+
+__uml_setup("iomem=", parse_iomem,
+"iomem=<name>,<file>\n"
+"    Configure <file> as an IO memory region named <name>.\n\n"
+);
+
+int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
+		   int must_succeed)
+{
+	int err;
+
+	err = os_protect_memory((void *) addr, len, r, w, x);
+	if(err < 0){
+                if(must_succeed)
+			panic("protect failed, err = %d", -err);
+		else return(err);
+	}
+	return(0);
+}
+
+#if 0
+/* Debugging facility for dumping stuff out to the host, avoiding the timing
+ * problems that come with printf and breakpoints.
+ * Enable in case of emergency.
+ */
+
+int logging = 1;
+int logging_fd = -1;
+
+int logging_line = 0;
+char logging_buf[512];
+
+void log(char *fmt, ...)
+{
+        va_list ap;
+        struct timeval tv;
+        struct openflags flags;
+
+        if(logging == 0) return;
+        if(logging_fd < 0){
+                flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
+                logging_fd = os_open_file("log", flags, 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
+
+/*
+ * 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 --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
new file mode 100644
index 0000000..420e6d5
--- /dev/null
+++ b/arch/um/kernel/physmem.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/rbtree.h"
+#include "linux/slab.h"
+#include "linux/vmalloc.h"
+#include "linux/bootmem.h"
+#include "linux/module.h"
+#include "asm/types.h"
+#include "asm/pgtable.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "mode_kern.h"
+#include "mem.h"
+#include "mem_user.h"
+#include "os.h"
+#include "kern.h"
+#include "init.h"
+
+struct phys_desc {
+	struct rb_node rb;
+	int fd;
+	__u64 offset;
+	void *virt;
+	unsigned long phys;
+	struct list_head list;
+};
+
+static struct rb_root phys_mappings = RB_ROOT;
+
+static struct rb_node **find_rb(void *virt)
+{
+	struct rb_node **n = &phys_mappings.rb_node;
+	struct phys_desc *d;
+
+	while(*n != NULL){
+		d = rb_entry(*n, struct phys_desc, rb);
+		if(d->virt == virt)
+			return(n);
+
+		if(d->virt > virt)
+			n = &(*n)->rb_left;
+		else
+			n = &(*n)->rb_right;
+	}
+
+	return(n);
+}
+
+static struct phys_desc *find_phys_mapping(void *virt)
+{
+	struct rb_node **n = find_rb(virt);
+
+	if(*n == NULL)
+		return(NULL);
+
+	return(rb_entry(*n, struct phys_desc, rb));
+}
+
+static void insert_phys_mapping(struct phys_desc *desc)
+{
+	struct rb_node **n = find_rb(desc->virt);
+
+	if(*n != NULL)
+		panic("Physical remapping for %p already present",
+		      desc->virt);
+
+	rb_link_node(&desc->rb, (*n)->rb_parent, n);
+	rb_insert_color(&desc->rb, &phys_mappings);
+}
+
+LIST_HEAD(descriptor_mappings);
+
+struct desc_mapping {
+	int fd;
+	struct list_head list;
+	struct list_head pages;
+};
+
+static struct desc_mapping *find_mapping(int fd)
+{
+	struct desc_mapping *desc;
+	struct list_head *ele;
+
+	list_for_each(ele, &descriptor_mappings){
+		desc = list_entry(ele, struct desc_mapping, list);
+		if(desc->fd == fd)
+			return(desc);
+	}
+
+	return(NULL);
+}
+
+static struct desc_mapping *descriptor_mapping(int fd)
+{
+	struct desc_mapping *desc;
+
+	desc = find_mapping(fd);
+	if(desc != NULL)
+		return(desc);
+
+	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+	if(desc == NULL)
+		return(NULL);
+
+	*desc = ((struct desc_mapping)
+		{ .fd =		fd,
+		  .list =	LIST_HEAD_INIT(desc->list),
+		  .pages =	LIST_HEAD_INIT(desc->pages) });
+	list_add(&desc->list, &descriptor_mappings);
+
+	return(desc);
+}
+
+int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
+{
+	struct desc_mapping *fd_maps;
+	struct phys_desc *desc;
+	unsigned long phys;
+	int err;
+
+	fd_maps = descriptor_mapping(fd);
+	if(fd_maps == NULL)
+		return(-ENOMEM);
+
+	phys = __pa(virt);
+	desc = find_phys_mapping(virt);
+  	if(desc != NULL)
+		panic("Address 0x%p is already substituted\n", virt);
+
+	err = -ENOMEM;
+	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+	if(desc == NULL)
+		goto out;
+
+	*desc = ((struct phys_desc)
+		{ .fd =			fd,
+		  .offset =		offset,
+		  .virt =		virt,
+		  .phys =		__pa(virt),
+		  .list = 		LIST_HEAD_INIT(desc->list) });
+	insert_phys_mapping(desc);
+
+	list_add(&desc->list, &fd_maps->pages);
+
+	virt = (void *) ((unsigned long) virt & PAGE_MASK);
+	err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
+	if(!err)
+		goto out;
+
+	rb_erase(&desc->rb, &phys_mappings);
+	kfree(desc);
+ out:
+	return(err);
+}
+
+static int physmem_fd = -1;
+
+static void remove_mapping(struct phys_desc *desc)
+{
+	void *virt = desc->virt;
+	int err;
+
+	rb_erase(&desc->rb, &phys_mappings);
+	list_del(&desc->list);
+	kfree(desc);
+
+	err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
+	if(err)
+		panic("Failed to unmap block device page from physical memory, "
+		      "errno = %d", -err);
+}
+
+int physmem_remove_mapping(void *virt)
+{
+	struct phys_desc *desc;
+
+	virt = (void *) ((unsigned long) virt & PAGE_MASK);
+	desc = find_phys_mapping(virt);
+	if(desc == NULL)
+		return(0);
+
+	remove_mapping(desc);
+	return(1);
+}
+
+void physmem_forget_descriptor(int fd)
+{
+	struct desc_mapping *desc;
+	struct phys_desc *page;
+	struct list_head *ele, *next;
+	__u64 offset;
+	void *addr;
+	int err;
+
+	desc = find_mapping(fd);
+	if(desc == NULL)
+		return;
+
+	list_for_each_safe(ele, next, &desc->pages){
+		page = list_entry(ele, struct phys_desc, list);
+		offset = page->offset;
+		addr = page->virt;
+		remove_mapping(page);
+		err = os_seek_file(fd, offset);
+		if(err)
+			panic("physmem_forget_descriptor - failed to seek "
+			      "to %lld in fd %d, error = %d\n",
+			      offset, fd, -err);
+		err = os_read_file(fd, addr, PAGE_SIZE);
+		if(err < 0)
+			panic("physmem_forget_descriptor - failed to read "
+			      "from fd %d to 0x%p, error = %d\n",
+			      fd, addr, -err);
+	}
+
+	list_del(&desc->list);
+	kfree(desc);
+}
+
+EXPORT_SYMBOL(physmem_forget_descriptor);
+EXPORT_SYMBOL(physmem_remove_mapping);
+EXPORT_SYMBOL(physmem_subst_mapping);
+
+void arch_free_page(struct page *page, int order)
+{
+	void *virt;
+	int i;
+
+	for(i = 0; i < (1 << order); i++){
+		virt = __va(page_to_phys(page + i));
+		physmem_remove_mapping(virt);
+	}
+}
+
+int is_remapped(void *virt)
+{
+  	struct phys_desc *desc = find_phys_mapping(virt);
+
+	return(desc != NULL);
+}
+
+/* Changed during early boot */
+unsigned long high_physmem;
+
+extern unsigned long physmem_size;
+
+void *to_virt(unsigned long phys)
+{
+	return((void *) uml_physmem + phys);
+}
+
+unsigned long to_phys(void *virt)
+{
+	return(((unsigned long) virt) - uml_physmem);
+}
+
+int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
+{
+	struct page *p, *map;
+	unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
+	unsigned long iomem_len, iomem_pages, total_len, total_pages;
+	int i;
+
+	phys_pages = physmem >> PAGE_SHIFT;
+	phys_len = phys_pages * sizeof(struct page);
+
+	iomem_pages = iomem >> PAGE_SHIFT;
+	iomem_len = iomem_pages * sizeof(struct page);
+
+	highmem_pages = highmem >> PAGE_SHIFT;
+	highmem_len = highmem_pages * sizeof(struct page);
+
+	total_pages = phys_pages + iomem_pages + highmem_pages;
+	total_len = phys_len + iomem_pages + highmem_len;
+
+	if(kmalloc_ok){
+		map = kmalloc(total_len, GFP_KERNEL);
+		if(map == NULL)
+			map = vmalloc(total_len);
+	}
+	else map = alloc_bootmem_low_pages(total_len);
+
+	if(map == NULL)
+		return(-ENOMEM);
+
+	for(i = 0; i < total_pages; i++){
+		p = &map[i];
+		set_page_count(p, 0);
+		SetPageReserved(p);
+		INIT_LIST_HEAD(&p->lru);
+	}
+
+	max_mapnr = total_pages;
+	return(0);
+}
+
+struct page *phys_to_page(const unsigned long phys)
+{
+	return(&mem_map[phys >> PAGE_SHIFT]);
+}
+
+struct page *__virt_to_page(const unsigned long virt)
+{
+	return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
+}
+
+phys_t page_to_phys(struct page *page)
+{
+	return((page - mem_map) << PAGE_SHIFT);
+}
+
+pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+	pte_t pte;
+
+	pte_set_val(pte, page_to_phys(page), pgprot);
+	if(pte_present(pte))
+		pte_mknewprot(pte_mknewpage(pte));
+	return(pte);
+}
+
+/* Changed during early boot */
+static unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+	if(kmem_top == 0)
+		kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
+	return(kmem_top);
+}
+
+void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
+		int r, int w, int x)
+{
+	__u64 offset;
+	int fd, err;
+
+	fd = phys_mapping(phys, &offset);
+	err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
+	if(err) {
+		if(err == -ENOMEM)
+			printk("try increasing the host's "
+			       "/proc/sys/vm/max_map_count to <physical "
+			       "memory size>/4096\n");
+		panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
+		      "err = %d\n", virt, fd, offset, len, r, w, x, err);
+	}
+}
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+
+void setup_physmem(unsigned long start, unsigned long reserve_end,
+		   unsigned long len, unsigned long highmem)
+{
+	unsigned long reserve = reserve_end - start;
+	int pfn = PFN_UP(__pa(reserve_end));
+	int delta = (len - reserve) >> PAGE_SHIFT;
+	int err, offset, bootmap_size;
+
+	physmem_fd = create_mem_file(len + highmem);
+
+	offset = uml_reserved - uml_physmem;
+	err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
+			    len - offset, 1, 1, 0);
+	if(err < 0){
+		os_print_error(err, "Mapping memory");
+		exit(1);
+	}
+
+	bootmap_size = init_bootmem(pfn, pfn + delta);
+	free_bootmem(__pa(reserve_end) + bootmap_size,
+		     len - bootmap_size - reserve);
+}
+
+int phys_mapping(unsigned long phys, __u64 *offset_out)
+{
+	struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
+	int fd = -1;
+
+	if(desc != NULL){
+		fd = desc->fd;
+		*offset_out = desc->offset;
+	}
+	else if(phys < physmem_size){
+		fd = physmem_fd;
+		*offset_out = phys;
+	}
+	else if(phys < __pa(end_iomem)){
+		struct iomem_region *region = iomem_regions;
+
+		while(region != NULL){
+			if((phys >= region->phys) &&
+			   (phys < region->phys + region->size)){
+				fd = region->fd;
+				*offset_out = phys - region->phys;
+				break;
+			}
+			region = region->next;
+		}
+	}
+	else if(phys < __pa(end_iomem) + highmem){
+		fd = physmem_fd;
+		*offset_out = phys - iomem_size;
+	}
+
+	return(fd);
+}
+
+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 host.  It can\n"
+"    be more, and the excess, if it's ever used, will just be swapped out.\n"
+"	Example: mem=64M\n\n"
+);
+
+unsigned long find_iomem(char *driver, unsigned long *len_out)
+{
+	struct iomem_region *region = iomem_regions;
+
+	while(region != NULL){
+		if(!strcmp(region->driver, driver)){
+			*len_out = region->size;
+			return(region->virt);
+		}
+	}
+
+	return(0);
+}
+
+int setup_iomem(void)
+{
+	struct iomem_region *region = iomem_regions;
+	unsigned long iomem_start = high_physmem + PAGE_SIZE;
+	int err;
+
+	while(region != NULL){
+		err = os_map_memory((void *) iomem_start, region->fd, 0,
+				    region->size, 1, 1, 0);
+		if(err)
+			printk("Mapping iomem region for driver '%s' failed, "
+			       "errno = %d\n", region->driver, -err);
+		else {
+			region->virt = iomem_start;
+			region->phys = __pa(region->virt);
+		}
+
+		iomem_start += region->size + PAGE_SIZE;
+		region = region->next;
+	}
+
+	return(0);
+}
+
+__initcall(setup_iomem);
+
+/*
+ * 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 --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
new file mode 100644
index 0000000..f76a269
--- /dev/null
+++ b/arch/um/kernel/process.c
@@ -0,0 +1,423 @@
+/* 
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#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 "ptrace_user.h"
+#include "time_user.h"
+#include "init.h"
+#include "os.h"
+#include "uml-config.h"
+#include "ptrace_user.h"
+#include "choose-mode.h"
+#include "mode.h"
+#ifdef UML_CONFIG_MODE_SKAS
+#include "skas.h"
+#include "skas_ptrace.h"
+#include "registers.h"
+#endif
+
+void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
+{
+	int flags = 0, pages;
+
+	if(sig_stack != NULL){
+		pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
+		set_sigstack(sig_stack, pages * page_size());
+		flags = SA_ONSTACK;
+	}
+	if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+}
+
+void init_new_thread_signals(int altstack)
+{
+	int flags = altstack ? SA_ONSTACK : 0;
+
+	set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
+		    flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	signal(SIGHUP, SIG_IGN);
+
+	init_irq_signals(altstack);
+}
+
+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, NULL);
+	kill(os_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(new_pid);
+
+	CATCH_EINTR(err = waitpid(new_pid, &status, 0));
+	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, "
+		      "status = %d", status);
+
+	return(arg.pid);
+}
+
+static int ptrace_child(void *arg)
+{
+	int ret;
+	int pid = os_getpid(), ppid = getppid();
+	int sc_result;
+
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+		perror("ptrace");
+		os_kill_process(pid, 0);
+	}
+	os_stop_process(pid);
+
+	/*This syscall will be intercepted by the parent. Don't call more than
+	 * once, please.*/
+	sc_result = os_getpid();
+
+	if (sc_result == pid)
+		ret = 1; /*Nothing modified by the parent, we are running
+			   normally.*/
+	else if (sc_result == ppid)
+		ret = 0; /*Expected in check_ptrace and check_sysemu when they
+			   succeed in modifying the stack frame*/
+	else
+		ret = 2; /*Serious trouble! This could be caused by a bug in
+			   host 2.6 SKAS3/2.6 patch before release -V6, together
+			   with a bug in the UML code itself.*/
+	_exit(ret);
+}
+
+static int start_ptraced_child(void **stack_out)
+{
+	void *stack;
+	unsigned long sp;
+	int pid, n, status;
+	
+	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);
+	CATCH_EINTR(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);
+
+	*stack_out = stack;
+	return(pid);
+}
+
+/* When testing for SYSEMU support, if it is one of the broken versions, we must
+ * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
+ * So only for SYSEMU features we test mustpanic, while normal host features
+ * must work anyway!*/
+static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
+{
+	int status, n, ret = 0;
+
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		panic("check_ptrace : ptrace failed, errno = %d", errno);
+	CATCH_EINTR(n = waitpid(pid, &status, 0));
+	if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
+		int exit_with = WEXITSTATUS(status);
+		if (exit_with == 2)
+			printk("check_ptrace : child exited with status 2. "
+			       "Serious trouble happening! Try updating your "
+			       "host skas patch!\nDisabling SYSEMU support.");
+		printk("check_ptrace : child exited with exitcode %d, while "
+		      "expecting %d; status 0x%x", exit_with,
+		      exitcode, status);
+		if (mustpanic)
+			panic("\n");
+		else
+			printk("\n");
+		ret = -1;
+	}
+
+	if(munmap(stack, PAGE_SIZE) < 0)
+		panic("check_ptrace : munmap failed, errno = %d", errno);
+	return ret;
+}
+
+static int force_sysemu_disabled = 0;
+
+static int __init nosysemu_cmd_param(char *str, int* add)
+{
+	force_sysemu_disabled = 1;
+	return 0;
+}
+
+__uml_setup("nosysemu", nosysemu_cmd_param,
+		"nosysemu\n"
+		"    Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
+		"    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
+		"    behaviour of ptrace() and helps reducing host context switch rate.\n"
+		"    To make it working, you need a kernel patch for your host, too.\n"
+		"    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
+
+static void __init check_sysemu(void)
+{
+	void *stack;
+	int pid, syscall, n, status, count=0;
+
+	printk("Checking syscall emulation patch for ptrace...");
+	sysemu_supported = 0;
+	pid = start_ptraced_child(&stack);
+
+	if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
+		goto fail;
+
+	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+	if (n < 0)
+		panic("check_sysemu : wait failed, errno = %d", errno);
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+		panic("check_sysemu : expected SIGTRAP, "
+		      "got status = %d", status);
+
+	n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
+		   os_getpid());
+	if(n < 0)
+		panic("check_sysemu : failed to modify system "
+		      "call return, errno = %d", errno);
+
+	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
+		goto fail_stopped;
+
+	sysemu_supported = 1;
+	printk("OK\n");
+	set_using_sysemu(!force_sysemu_disabled);
+
+	printk("Checking advanced syscall emulation patch for ptrace...");
+	pid = start_ptraced_child(&stack);
+	while(1){
+		count++;
+		if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
+			goto fail;
+		CATCH_EINTR(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|SYSCALL_TRAP), "
+			      "got status = %d", status);
+
+		syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
+				 0);
+		if(syscall == __NR_getpid){
+			if (!count)
+				panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep");
+			n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
+				   os_getpid());
+			if(n < 0)
+				panic("check_sysemu : failed to modify system "
+				      "call return, errno = %d", errno);
+			break;
+		}
+	}
+	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
+		goto fail_stopped;
+
+	sysemu_supported = 2;
+	printk("OK\n");
+
+	if ( !force_sysemu_disabled )
+		set_using_sysemu(sysemu_supported);
+	return;
+
+fail:
+	stop_ptraced_child(pid, stack, 1, 0);
+fail_stopped:
+	printk("missing\n");
+}
+
+void __init check_ptrace(void)
+{
+	void *stack;
+	int pid, syscall, n, status;
+
+	printk("Checking that ptrace can change system call numbers...");
+	pid = start_ptraced_child(&stack);
+
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
+
+	while(1){
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			panic("check_ptrace : ptrace failed, errno = %d", 
+			      errno);
+		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+		if(n < 0)
+			panic("check_ptrace : wait failed, errno = %d", errno);
+		if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80))
+			panic("check_ptrace : expected SIGTRAP + 0x80, "
+			      "got status = %d", status);
+		
+		syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
+				 0);
+		if(syscall == __NR_getpid){
+			n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
+				   __NR_getppid);
+			if(n < 0)
+				panic("check_ptrace : failed to modify system "
+				      "call, errno = %d", errno);
+			break;
+		}
+	}
+	stop_ptraced_child(pid, stack, 0, 1);
+	printk("OK\n");
+	check_sysemu();
+}
+
+int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+{
+	sigjmp_buf buf;
+	int n;
+
+	*jmp_ptr = &buf;
+	n = sigsetjmp(buf, 1);
+	if(n != 0)
+		return(n);
+	(*fn)(arg);
+	return(0);
+}
+
+void forward_pending_sigio(int target)
+{
+	sigset_t sigs;
+
+	if(sigpending(&sigs)) 
+		panic("forward_pending_sigio : sigpending failed");
+	if(sigismember(&sigs, SIGIO))
+		kill(target, SIGIO);
+}
+
+#ifdef UML_CONFIG_MODE_SKAS
+static inline int check_skas3_ptrace_support(void)
+{
+	struct ptrace_faultinfo fi;
+	void *stack;
+	int pid, n, ret = 1;
+
+	printf("Checking for the skas3 patch in the host...");
+	pid = start_ptraced_child(&stack);
+
+	n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
+	if (n < 0) {
+		if(errno == EIO)
+			printf("not found\n");
+		else {
+			perror("not found");
+		}
+		ret = 0;
+	} else {
+		printf("found\n");
+	}
+
+	init_registers(pid);
+	stop_ptraced_child(pid, stack, 1, 1);
+
+	return(ret);
+}
+
+int can_do_skas(void)
+{
+	int ret = 1;
+
+	printf("Checking for /proc/mm...");
+	if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
+		printf("not found\n");
+		ret = 0;
+		goto out;
+	} else {
+		printf("found\n");
+	}
+
+	ret = check_skas3_ptrace_support();
+out:
+	return ret;
+}
+#else
+int can_do_skas(void)
+{
+	return(0);
+}
+#endif
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
new file mode 100644
index 0000000..1d719d5
--- /dev/null
+++ b/arch/um/kernel/process_kern.c
@@ -0,0 +1,500 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
+ * 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 "linux/vmalloc.h"
+#include "linux/spinlock.h"
+#include "linux/proc_fs.h"
+#include "linux/ptrace.h"
+#include "linux/random.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/tlbflush.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 "time_user.h"
+#include "tlb.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+#include "2_5compat.h"
+#include "os.h"
+#include "mode.h"
+#include "mode_kern.h"
+#include "choose-mode.h"
+
+/* This is a per-cpu array.  A processor only modifies its entry and it only
+ * cares about its entry, so it's OK if another processor is modifying its
+ * entry.
+ */
+struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
+
+struct task_struct *get_task(int pid, int require)
+{
+        struct task_struct *ret;
+
+        read_lock(&tasklist_lock);
+	ret = find_task_by_pid(pid);
+        read_unlock(&tasklist_lock);
+
+        if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
+        return(ret);
+}
+
+int external_pid(void *t)
+{
+	struct task_struct *task = t ? t : current;
+
+	return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
+}
+
+int pid_to_processor_id(int pid)
+{
+	int i;
+
+	for(i = 0; i < ncpus; i++){
+		if(cpu_tasks[i].pid == pid) return(i);
+	}
+	return(-1);
+}
+
+void free_stack(unsigned long stack, int order)
+{
+	free_pages(stack, order);
+}
+
+unsigned long alloc_stack(int order, int atomic)
+{
+	unsigned long page;
+	int flags = GFP_KERNEL;
+
+	if(atomic) flags |= GFP_ATOMIC;
+	page = __get_free_pages(flags, order);
+	if(page == 0)
+		return(0);
+	stack_protections(page);
+	return(page);
+}
+
+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 | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
+		      NULL);
+	if(pid < 0)
+		panic("do_fork failed in kernel_thread, errno = %d", pid);
+	return(pid);
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+	       struct task_struct *tsk)
+{
+	int cpu = smp_processor_id();
+
+	if (prev != next) 
+		cpu_clear(cpu, prev->cpu_vm_mask);
+	cpu_set(cpu, next->cpu_vm_mask);
+}
+
+void set_current(void *t)
+{
+	struct task_struct *task = t;
+
+	cpu_tasks[task->thread_info->cpu] = ((struct cpu_task) 
+		{ external_pid(task), task });
+}
+
+void *_switch_to(void *prev, void *next, void *last)
+{
+	return(CHOOSE_MODE(switch_to_tt(prev, next), 
+			   switch_to_skas(prev, next)));
+}
+
+void interrupt_end(void)
+{
+	if(need_resched()) schedule();
+	if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
+}
+
+void release_thread(struct task_struct *task)
+{
+	CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
+}
+ 
+void exit_thread(void)
+{
+	CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
+	unprotect_stack((unsigned long) current_thread);
+}
+ 
+void *get_current(void)
+{
+	return(current);
+}
+
+void prepare_to_copy(struct task_struct *tsk)
+{
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+		unsigned long stack_top, struct task_struct * p, 
+		struct pt_regs *regs)
+{
+	p->thread = (struct thread_struct) INIT_THREAD;
+	return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, 
+				clone_flags, sp, stack_top, p, regs));
+}
+
+void initial_thread_cb(void (*proc)(void *), void *arg)
+{
+	int save_kmalloc_ok = kmalloc_ok;
+
+	kmalloc_ok = 0;
+	CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, 
+			 arg);
+	kmalloc_ok = save_kmalloc_ok;
+}
+ 
+unsigned long stack_sp(unsigned long page)
+{
+	return(page + PAGE_SIZE - sizeof(void *));
+}
+
+int current_pid(void)
+{
+	return(current->pid);
+}
+
+void default_idle(void)
+{
+	uml_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(need_resched())
+			schedule();
+		
+		idle_sleep(10);
+	}
+}
+
+void cpu_idle(void)
+{
+	CHOOSE_MODE(init_idle_tt(), init_idle_skas());
+}
+
+int page_size(void)
+{
+	return(PAGE_SIZE);
+}
+
+unsigned long page_mask(void)
+{
+	return(PAGE_MASK);
+}
+
+void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
+		      pte_t *pte_out)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	if(task->mm == NULL) 
+		return(ERR_PTR(-EINVAL));
+	pgd = pgd_offset(task->mm, addr);
+	if(!pgd_present(*pgd))
+		return(ERR_PTR(-EINVAL));
+
+	pud = pud_offset(pgd, addr);
+	if(!pud_present(*pud))
+		return(ERR_PTR(-EINVAL));
+
+	pmd = pmd_offset(pud, addr);
+	if(!pmd_present(*pmd)) 
+		return(ERR_PTR(-EINVAL));
+
+	pte = pte_offset_kernel(pmd, addr);
+	if(!pte_present(*pte)) 
+		return(ERR_PTR(-EINVAL));
+
+	if(pte_out != NULL)
+		*pte_out = *pte;
+	return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
+}
+
+char *current_cmd(void)
+{
+#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
+	return("(Unknown)");
+#else
+	void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
+	return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) 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->flags |= PF_SIGNALED;
+	do_exit(SIGBUS | 0x80);
+}
+
+void dump_thread(struct pt_regs *regs, struct user *u)
+{
+}
+
+void enable_hlt(void)
+{
+	panic("enable_hlt");
+}
+
+EXPORT_SYMBOL(enable_hlt);
+
+void disable_hlt(void)
+{
+	panic("disable_hlt");
+}
+
+EXPORT_SYMBOL(disable_hlt);
+
+void *um_kmalloc(int size)
+{
+	return(kmalloc(size, GFP_KERNEL));
+}
+
+void *um_kmalloc_atomic(int size)
+{
+	return(kmalloc(size, GFP_ATOMIC));
+}
+
+void *um_vmalloc(int size)
+{
+	return(vmalloc(size));
+}
+
+unsigned long get_fault_addr(void)
+{
+	return((unsigned long) current->thread.fault_addr);
+}
+
+EXPORT_SYMBOL(get_fault_addr);
+
+void not_implemented(void)
+{
+	printk(KERN_DEBUG "Something isn't implemented in here\n");
+}
+
+EXPORT_SYMBOL(not_implemented);
+
+int user_context(unsigned long sp)
+{
+	unsigned long stack;
+
+	stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
+	return(stack != (unsigned long) current_thread);
+}
+
+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)();
+}
+
+char *uml_strdup(char *string)
+{
+	char *new;
+
+	new = kmalloc(strlen(string) + 1, GFP_KERNEL);
+	if(new == NULL) return(NULL);
+	strcpy(new, string);
+	return(new);
+}
+
+void *get_init_task(void)
+{
+	return(&init_thread_union.thread_info.task);
+}
+
+int copy_to_user_proc(void __user *to, void *from, int size)
+{
+	return(copy_to_user(to, from, size));
+}
+
+int copy_from_user_proc(void *to, void __user *from, int size)
+{
+	return(copy_from_user(to, from, size));
+}
+
+int clear_user_proc(void __user *buf, int size)
+{
+	return(clear_user(buf, size));
+}
+
+int strlen_user_proc(char __user *str)
+{
+	return(strlen_user(str));
+}
+
+int smp_sigio_handler(void)
+{
+#ifdef CONFIG_SMP
+	int cpu = current_thread->cpu;
+	IPI_handler(cpu);
+	if(cpu != 0)
+		return(1);
+#endif
+	return(0);
+}
+
+int um_in_interrupt(void)
+{
+	return(in_interrupt());
+}
+
+int cpu(void)
+{
+	return(current_thread->cpu);
+}
+
+static atomic_t using_sysemu = ATOMIC_INIT(0);
+int sysemu_supported;
+
+void set_using_sysemu(int value)
+{
+	if (value > sysemu_supported)
+		return;
+	atomic_set(&using_sysemu, value);
+}
+
+int get_using_sysemu(void)
+{
+	return atomic_read(&using_sysemu);
+}
+
+static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
+{
+	if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
+		*eof = 1;
+
+	return strlen(buf);
+}
+
+static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
+{
+	char tmp[2];
+
+	if (copy_from_user(tmp, buf, 1))
+		return -EFAULT;
+
+	if (tmp[0] >= '0' && tmp[0] <= '2')
+		set_using_sysemu(tmp[0] - '0');
+	return count; /*We use the first char, but pretend to write everything*/
+}
+
+int __init make_proc_sysemu(void)
+{
+	struct proc_dir_entry *ent;
+	if (!sysemu_supported)
+		return 0;
+
+	ent = create_proc_entry("sysemu", 0600, &proc_root);
+
+	if (ent == NULL)
+	{
+		printk("Failed to register /proc/sysemu\n");
+		return(0);
+	}
+
+	ent->read_proc  = proc_read_sysemu;
+	ent->write_proc = proc_write_sysemu;
+
+	return 0;
+}
+
+late_initcall(make_proc_sysemu);
+
+int singlestepping(void * t)
+{
+	struct task_struct *task = t ? t : current;
+
+	if ( ! (task->ptrace & PT_DTRACE) )
+		return(0);
+
+	if (task->thread.singlestep_syscall)
+		return(1);
+
+	return 2;
+}
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (randomize_va_space)
+		sp -= get_random_int() % 8192;
+	return sp & ~0xf;
+}
+
+
+/*
+ * 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 --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
new file mode 100644
index 0000000..3a99ee6
--- /dev/null
+++ b/arch/um/kernel/ptrace.c
@@ -0,0 +1,388 @@
+/* 
+ * 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 "linux/security.h"
+#include "linux/ptrace.h"
+#include "linux/audit.h"
+#ifdef CONFIG_PROC_MM
+#include "linux/proc_mm.h"
+#endif
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+#include "skas_ptrace.h"
+#include "sysdep/ptrace.h"
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+	child->ptrace &= ~PT_DTRACE;
+	child->thread.singlestep_syscall = 0;
+}
+
+long 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;
+
+		ret = security_ptrace(current->parent, current);
+		if (ret)
+ 			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 __user *) 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 < MAX_REG_OFFSET){
+			tmp = getreg(child, addr);
+		}
+		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+			(addr <= offsetof(struct user, u_debugreg[7]))){
+			addr -= offsetof(struct user, u_debugreg[0]);
+			addr = addr >> 2;
+			tmp = child->thread.arch.debugregs[addr];
+		}
+		ret = put_user(tmp, (unsigned long __user *) 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 < MAX_REG_OFFSET) {
+			ret = putreg(child, addr, data);
+			break;
+		}
+#if 0 /* XXX x86_64 */
+		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+			(addr <= offsetof(struct user, u_debugreg[7]))){
+			  addr -= offsetof(struct user, u_debugreg[0]);
+			  addr = addr >> 2;
+			  if((addr == 4) || (addr == 5)) break;
+			  child->thread.arch.debugregs[addr] = data;
+			  ret = 0;
+		}
+#endif
+
+		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;
+
+		child->ptrace &= ~PT_DTRACE;
+		child->thread.singlestep_syscall = 0;
+		if (request == PTRACE_SYSCALL) {
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		else {
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		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->exit_state == EXIT_ZOMBIE)	/* already dead */
+			break;
+
+		child->ptrace &= ~PT_DTRACE;
+		child->thread.singlestep_syscall = 0;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->ptrace |= PT_DTRACE;
+		child->thread.singlestep_syscall = 0;
+		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 long *)data, 
+			       MAX_REG_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
+			__put_user(getreg(child, i),
+				   (unsigned long __user *) 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, 
+			       MAX_REG_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
+			__get_user(tmp, (unsigned long __user *) data);
+			putreg(child, i, tmp);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+#endif
+#ifdef PTRACE_GETFPREGS
+	case PTRACE_GETFPREGS: /* Get the child FPU state. */
+		ret = get_fpregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_SETFPREGS
+	case PTRACE_SETFPREGS: /* Set the child FPU state. */
+	        ret = set_fpregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_GETFPXREGS
+	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
+		ret = get_fpxregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_SETFPXREGS
+	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
+		ret = set_fpxregs(data, child);
+		break;
+#endif
+	case PTRACE_FAULTINFO: {
+		struct ptrace_faultinfo fault;
+
+		fault = ((struct ptrace_faultinfo) 
+			{ .is_write	= child->thread.err,
+			  .addr		= child->thread.cr2 });
+		ret = copy_to_user((unsigned long __user *) data, &fault,
+				   sizeof(fault));
+		if(ret)
+			break;
+		break;
+	}
+	case PTRACE_SIGPENDING:
+		ret = copy_to_user((unsigned long __user *) data,
+				   &child->pending.signal,
+				   sizeof(child->pending.signal));
+		break;
+
+	case PTRACE_LDT: {
+		struct ptrace_ldt ldt;
+
+		if(copy_from_user(&ldt, (unsigned long __user *) data,
+				  sizeof(ldt))){
+			ret = -EIO;
+			break;
+		}
+
+		/* This one is confusing, so just punt and return -EIO for 
+		 * now
+		 */
+		ret = -EIO;
+		break;
+	}
+#ifdef CONFIG_PROC_MM
+	case PTRACE_SWITCH_MM: {
+		struct mm_struct *old = child->mm;
+		struct mm_struct *new = proc_mm_get_mm(data);
+
+		if(IS_ERR(new)){
+			ret = PTR_ERR(new);
+			break;
+		}
+
+		atomic_inc(&new->mm_users);
+		child->mm = new;
+		child->active_mm = new;
+		mmput(old);
+		ret = 0;
+		break;
+	}
+#endif
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+ out_tsk:
+	put_task_struct(child);
+ out:
+	unlock_kernel();
+	return ret;
+}
+
+void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
+		  int error_code)
+{
+	struct siginfo info;
+
+	memset(&info, 0, sizeof(info));
+	info.si_signo = SIGTRAP;
+	info.si_code = TRAP_BRKPT;
+
+	/* User-mode eip? */
+	info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
+
+	/* Send us the fakey SIGTRAP */
+	force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
+ * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
+ */
+void syscall_trace(union uml_pt_regs *regs, int entryexit)
+{
+	int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
+	int tracesysgood;
+
+	if (unlikely(current->audit_context)) {
+		if (!entryexit)
+			audit_syscall_entry(current, 
+					    UPT_SYSCALL_NR(&regs->regs),
+					    UPT_SYSCALL_ARG1(&regs->regs),
+					    UPT_SYSCALL_ARG2(&regs->regs),
+					    UPT_SYSCALL_ARG3(&regs->regs),
+					    UPT_SYSCALL_ARG4(&regs->regs));
+		else
+			audit_syscall_exit(current, 
+					   UPT_SYSCALL_RET(&regs->regs));
+	}
+
+	/* Fake a debug trap */
+	if (is_singlestep)
+		send_sigtrap(current, regs, 0);
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
+	ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
+
+	if (entryexit) /* force do_signal() --> is_syscall() */
+		set_thread_flag(TIF_SIGPENDING);
+
+	/* 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 --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
new file mode 100644
index 0000000..207f89d
--- /dev/null
+++ b/arch/um/kernel/reboot.c
@@ -0,0 +1,79 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+#include "linux/sched.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "os.h"
+#include "mode.h"
+#include "choose-mode.h"
+
+#ifdef CONFIG_SMP
+static void kill_idlers(int me)
+{
+#ifdef CONFIG_MODE_TT
+	struct task_struct *p;
+	int i;
+
+	for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
+		p = idle_threads[i];
+		if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
+			os_kill_process(p->thread.mode.tt.extern_pid, 0);
+	}
+#endif
+}
+#endif
+
+static void kill_off_processes(void)
+{
+	CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
+#ifdef CONFIG_SMP
+	kill_idlers(os_getpid());
+#endif
+}
+
+void uml_cleanup(void)
+{
+	kill_off_processes();
+	do_uml_exitcalls();
+}
+
+void machine_restart(char * __unused)
+{
+	do_uml_exitcalls();
+	kill_off_processes();
+	CHOOSE_MODE(reboot_tt(), reboot_skas());
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_power_off(void)
+{
+	do_uml_exitcalls();
+	kill_off_processes();
+	CHOOSE_MODE(halt_tt(), halt_skas());
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+void machine_halt(void)
+{
+	machine_power_off();
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+/*
+ * 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 --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c
new file mode 100644
index 0000000..32188e1
--- /dev/null
+++ b/arch/um/kernel/resource.c
@@ -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 --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
new file mode 100644
index 0000000..2299884
--- /dev/null
+++ b/arch/um/kernel/sigio_kern.c
@@ -0,0 +1,63 @@
+/* 
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/list.h"
+#include "linux/slab.h"
+#include "linux/signal.h"
+#include "linux/interrupt.h"
+#include "init.h"
+#include "sigio.h"
+#include "irq_user.h"
+#include "irq_kern.h"
+
+/* Protected by sigio_lock() called from write_sigio_workaround */
+static int sigio_irq_fd = -1;
+
+static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	read_sigio_fd(sigio_irq_fd);
+	reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
+	return(IRQ_HANDLED);
+}
+
+int write_sigio_irq(int fd)
+{
+	int err;
+
+	err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
+			     SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
+			     NULL);
+	if(err){
+		printk("write_sigio_irq : um_request_irq failed, err = %d\n",
+		       err);
+		return(-1);
+	}
+	sigio_irq_fd = fd;
+	return(0);
+}
+
+static DEFINE_SPINLOCK(sigio_spinlock);
+
+void sigio_lock(void)
+{
+	spin_lock(&sigio_spinlock);
+}
+
+void sigio_unlock(void)
+{
+	spin_unlock(&sigio_spinlock);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
new file mode 100644
index 0000000..668df13
--- /dev/null
+++ b/arch/um/kernel/sigio_user.c
@@ -0,0 +1,431 @@
+/* 
+ * 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 <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 "user_util.h"
+#include "sigio.h"
+#include "helper.h"
+#include "os.h"
+
+/* Changed during early boot */
+int pty_output_sigio = 0;
+int pty_close_sigio = 0;
+
+/* Used as a flag during SIGIO testing early in boot */
+static volatile int got_sigio = 0;
+
+void __init handler(int sig)
+{
+	got_sigio = 1;
+}
+
+struct openpty_arg {
+	int master;
+	int slave;
+	int err;
+};
+
+static void openpty_cb(void *arg)
+{
+	struct openpty_arg *info = arg;
+
+	info->err = 0;
+	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+		info->err = -errno;
+}
+
+void __init check_one_sigio(void (*proc)(int, int))
+{
+	struct sigaction old, new;
+	struct openpty_arg pty = { .master = -1, .slave = -1 };
+	int master, slave, err;
+
+	initial_thread_cb(openpty_cb, &pty);
+	if(pty.err){
+		printk("openpty failed, errno = %d\n", -pty.err);
+		return;
+	}
+
+	master = pty.master;
+	slave = pty.slave;
+
+	if((master == -1) || (slave == -1)){
+		printk("openpty failed to allocate a pty\n");
+		return;
+	}
+
+	/* Not now, but complain so we now where we failed. */
+	err = raw(master);
+	if (err < 0)
+		panic("check_sigio : __raw failed, errno = %d\n", -err);
+
+	err = os_sigio_async(master, slave);
+	if(err < 0)
+		panic("tty_fds : sigio_async failed, err = %d\n", -err);
+
+	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);
+
+	got_sigio = 0;
+	(*proc)(master, slave);
+		
+	os_close_file(master);
+	os_close_file(slave);
+
+	if(sigaction(SIGIO, &old, NULL) < 0)
+		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+	int n;
+	char buf[512];
+
+	printk("Checking that host ptys support output SIGIO...");
+
+	memset(buf, 0, sizeof(buf));
+
+	while(os_write_file(master, buf, sizeof(buf)) > 0) ;
+	if(errno != EAGAIN)
+		panic("check_sigio : write failed, errno = %d\n", errno);
+	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+	if (got_sigio) {
+		printk("Yes\n");
+		pty_output_sigio = 1;
+	} else if (n == -EAGAIN) {
+		printk("No, enabling workaround\n");
+	} else {
+		panic("check_sigio : read failed, err = %d\n", n);
+	}
+}
+
+static void tty_close(int master, int slave)
+{
+	printk("Checking that host ptys support SIGIO on close...");
+
+	os_close_file(slave);
+	if(got_sigio){
+		printk("Yes\n");
+		pty_close_sigio = 1;
+	}
+	else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+		printk("No pseudo-terminals available - skipping pty SIGIO "
+		       "check\n");
+		return;
+	}
+	check_one_sigio(tty_output);
+	check_one_sigio(tty_close);
+}
+
+/* Protected by sigio_lock(), also used by sigio_cleanup, which is an 
+ * exitcall.
+ */
+static int write_sigio_pid = -1;
+
+/* These arrays are initialized before the sigio thread is started, and
+ * the descriptors closed after it is killed.  So, it can't see them change.
+ * On the UML side, they are changed under the sigio_lock.
+ */
+static int write_sigio_fds[2] = { -1, -1 };
+static int sigio_private[2] = { -1, -1 };
+
+struct pollfds {
+	struct pollfd *poll;
+	int size;
+	int used;
+};
+
+/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
+ * synchronizes with it.
+ */
+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 = os_read_file(sigio_private[1], &c, sizeof(c));
+				if(n != sizeof(c))
+					printk("write_sigio_thread : "
+					       "read failed, err = %d\n", -n);
+				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 = os_write_file(respond_fd, &c, sizeof(c));
+			if(n != sizeof(c))
+				printk("write_sigio_thread : write failed, "
+				       "err = %d\n", -n);
+		}
+	}
+}
+
+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);
+}
+
+/* Must be called with sigio_lock held, because it's needed by the marked
+ * critical section. */
+static void update_thread(void)
+{
+	unsigned long flags;
+	int n;
+	char c;
+
+	flags = set_signals(0);
+	n = os_write_file(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : write failed, err = %d\n", -n);
+		goto fail;
+	}
+
+	n = os_read_file(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : read failed, err = %d\n", -n);
+		goto fail;
+	}
+
+	set_signals(flags);
+	return;
+ fail:
+	/* Critical section start */
+	if(write_sigio_pid != -1) 
+		os_kill_process(write_sigio_pid, 1);
+	write_sigio_pid = -1;
+	os_close_file(sigio_private[0]);
+	os_close_file(sigio_private[1]);
+	os_close_file(write_sigio_fds[0]);
+	os_close_file(write_sigio_fds[1]);
+	/* Critical section end */
+	set_signals(flags);
+}
+
+int add_sigio_fd(int fd, int read)
+{
+	int err = 0, i, n, events;
+
+	sigio_lock();
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) 
+			goto out;
+	}
+
+	n = current_poll.used + 1;
+	err = need_poll(n);
+	if(err) 
+		goto out;
+
+	for(i = 0; i < current_poll.used; i++)
+		next_poll.poll[i] = current_poll.poll[i];
+
+	if(read) events = POLLIN;
+	else events = POLLOUT;
+
+	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
+						   .events 	= events,
+						   .revents 	= 0 });
+	update_thread();
+ out:
+	sigio_unlock();
+	return(err);
+}
+
+int ignore_sigio_fd(int fd)
+{
+	struct pollfd *p;
+	int err = 0, i, n = 0;
+
+	sigio_lock();
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) break;
+	}
+	if(i == current_poll.used)
+		goto out;
+	
+	err = need_poll(current_poll.used - 1);
+	if(err)
+		goto out;
+
+	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);
+		err = -1;
+		goto out;
+	}
+
+	update_thread();
+ out:
+	sigio_unlock();
+	return(err);
+}
+
+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(void)
+{
+	unsigned long stack;
+	int err;
+
+	sigio_lock();
+	if(write_sigio_pid != -1)
+		goto out;
+
+	err = os_pipe(write_sigio_fds, 1, 1);
+	if(err < 0){
+		printk("write_sigio_workaround - os_pipe 1 failed, "
+		       "err = %d\n", -err);
+		goto out;
+	}
+	err = os_pipe(sigio_private, 1, 1);
+	if(err < 0){
+		printk("write_sigio_workaround - os_pipe 2 failed, "
+		       "err = %d\n", -err);
+		goto out_close1;
+	}
+	if(setup_initial_poll(sigio_private[1]))
+		goto out_close2;
+
+	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 
+					    CLONE_FILES | CLONE_VM, &stack, 0);
+
+	if(write_sigio_pid < 0) goto out_close2;
+
+	if(write_sigio_irq(write_sigio_fds[0])) 
+		goto out_kill;
+
+ out:
+	sigio_unlock();
+	return;
+
+ out_kill:
+	os_kill_process(write_sigio_pid, 1);
+	write_sigio_pid = -1;
+ out_close2:
+	os_close_file(sigio_private[0]);
+	os_close_file(sigio_private[1]);
+ out_close1:
+	os_close_file(write_sigio_fds[0]);
+	os_close_file(write_sigio_fds[1]);
+	sigio_unlock();
+}
+
+int read_sigio_fd(int fd)
+{
+	int n;
+	char c;
+
+	n = os_read_file(fd, &c, sizeof(c));
+	if(n != sizeof(c)){
+		if(n < 0) {
+			printk("read_sigio_fd - read failed, err = %d\n", -n);
+			return(n);
+		}
+		else {
+			printk("read_sigio_fd - short read, bytes = %d\n", n);
+			return(-EIO);
+		}
+	}
+	return(n);
+}
+
+static void sigio_cleanup(void)
+{
+	if (write_sigio_pid != -1) {
+		os_kill_process(write_sigio_pid, 1);
+		write_sigio_pid = -1;
+	}
+}
+
+__uml_exitcall(sigio_cleanup);
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
new file mode 100644
index 0000000..7807a3e
--- /dev/null
+++ b/arch/um/kernel/signal_kern.c
@@ -0,0 +1,213 @@
+/* 
+ * 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 "linux/tty.h"
+#include "linux/binfmts.h"
+#include "linux/ptrace.h"
+#include "asm/signal.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+#include "user_util.h"
+#include "asm/ucontext.h"
+#include "kern_util.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "kern.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+#include "mode.h"
+
+EXPORT_SYMBOL(block_signals);
+EXPORT_SYMBOL(unblock_signals);
+
+#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)
+{
+	unsigned long sp;
+	int err;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/* Did we come from a system call? */
+	if(PT_REGS_SYSCALL_NR(regs) >= 0){
+		/* If so, check system call restarting.. */
+		switch(PT_REGS_SYSCALL_RET(regs)){
+		case -ERESTART_RESTARTBLOCK:
+		case -ERESTARTNOHAND:
+			PT_REGS_SYSCALL_RET(regs) = -EINTR;
+			break;
+
+		case -ERESTARTSYS:
+			if (!(ka->sa.sa_flags & SA_RESTART)) {
+				PT_REGS_SYSCALL_RET(regs) = -EINTR;
+				break;
+			}
+		/* fallthrough */
+		case -ERESTARTNOINTR:
+			PT_REGS_RESTART_SYSCALL(regs);
+			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+			break;
+		}
+	}
+
+	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;
+
+#ifdef CONFIG_ARCH_HAS_SC_SIGNALS
+	if(!(ka->sa.sa_flags & SA_SIGINFO))
+		err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
+	else
+#endif
+		err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
+
+	if(err){
+		spin_lock_irq(&current->sighand->siglock);
+		current->blocked = *oldset;
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+		force_sigsegv(signr, current);
+	}
+	else if(!(ka->sa.sa_flags & SA_NODEFER)){
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked, &current->blocked, 
+			  &ka->sa.sa_mask);
+		sigaddset(&current->blocked, signr);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+
+	return err;
+}
+
+static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+	struct k_sigaction ka_copy;
+	siginfo_t info;
+	int sig, handled_sig = 0;
+
+	while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){
+		handled_sig = 1;
+		/* Whee!  Actually deliver the signal.  */
+		if(!handle_signal(regs, sig, &ka_copy, &info, oldset))
+			break;
+	}
+
+	/* Did we come from a system call? */
+	if(!handled_sig && (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);
+		}
+		else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
+			PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
+			PT_REGS_RESTART_SYSCALL(regs);
+ 		}
+	}
+
+	/* This closes a way to execute a system call on the host.  If
+	 * you set a breakpoint on a system call instruction and singlestep
+	 * from it, the tracing thread used to PTRACE_SINGLESTEP the process
+	 * rather than PTRACE_SYSCALL it, allowing the system call to execute
+	 * on the host.  The tracing thread will check this flag and 
+	 * PTRACE_SYSCALL if necessary.
+	 */
+	if(current->ptrace & PT_DTRACE)
+		current->thread.singlestep_syscall =
+			is_syscall(PT_REGS_IP(&current->thread.regs));
+	return(handled_sig);
+}
+
+int do_signal(void)
+{
+	return(kern_do_signal(&current->thread.regs, &current->blocked));
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if(kern_do_signal(&current->thread.regs, &saveset))
+			return(-EINTR);
+	}
+}
+
+long sys_rt_sigsuspend(sigset_t __user *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->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (kern_do_signal(&current->thread.regs, &saveset))
+			return(-EINTR);
+	}
+}
+
+long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
+{
+	return(do_sigaltstack(uss, uoss, PT_REGS_SP(&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 --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
new file mode 100644
index 0000000..62f4578
--- /dev/null
+++ b/arch/um/kernel/signal_user.c
@@ -0,0 +1,157 @@
+/* 
+ * 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"
+
+void set_sigstack(void *sig_stack, int size)
+{
+	stack_t stack = ((stack_t) { .ss_flags	= 0,
+				     .ss_sp	= (__ptr_t) sig_stack,
+				     .ss_size 	= size - sizeof(void *) });
+
+	if(sigaltstack(&stack, NULL) != 0)
+		panic("enabling signal stack failed, errno = %d\n", errno);
+}
+
+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);
+	}
+	va_end(ap);
+	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));
+}
+
+/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
+ * disable profiling; it's safe because the profiling code does not interact
+ * with the kernel code at all.*/
+
+static void change_signals(int type)
+{
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGVTALRM);
+	sigaddset(&mask, SIGALRM);
+	sigaddset(&mask, SIGIO);
+	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);
+}
+
+/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
+ * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
+ * be able to profile all of UML, not just the non-critical sections.  If
+ * profiling is not thread-safe, then that is not my problem.  We can disable
+ * profiling when SMP is enabled in that case.
+ */
+#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;
+	return(sigs);
+}
+
+int get_signals(void)
+{
+	sigset_t mask;
+	
+	if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
+		panic("Failed to get signal mask");
+	return(enable_mask(&mask));
+}
+
+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)){
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+
+	/* This is safe - sigprocmask is guaranteed to copy locally the
+	 * value of new_set, do his work and then, at the end, write to
+	 * old_set.
+	 */
+	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){
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+	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 --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
new file mode 100644
index 0000000..d37d1bf
--- /dev/null
+++ b/arch/um/kernel/skas/Makefile
@@ -0,0 +1,13 @@
+# 
+# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
+	syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
+
+subdir- := util
+
+USER_OBJS := process.o time.o
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
new file mode 100644
index 0000000..c6b4d5d
--- /dev/null
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -0,0 +1,41 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "asm/current.h"
+#include "asm/page.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/mmu_context.h"
+#include "tlb.h"
+#include "skas.h"
+#include "um_mmu.h"
+#include "os.h"
+
+void flush_thread_skas(void)
+{
+	force_flush_all();
+	switch_mm_skas(current->mm->context.skas.mm_fd);
+}
+
+void start_thread_skas(struct pt_regs *regs, unsigned long eip, 
+		       unsigned long esp)
+{
+	set_fs(USER_DS);
+        PT_REGS_IP(regs) = eip;
+	PT_REGS_SP(regs) = 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 --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
new file mode 100644
index 0000000..4cd60d7
--- /dev/null
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MMU_H
+#define __SKAS_MMU_H
+
+struct mmu_context_skas {
+	int mm_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 --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
new file mode 100644
index 0000000..c1e33bd
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode-skas.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_SKAS_H__
+#define __MODE_SKAS_H__
+
+#include <sysdep/ptrace.h>
+
+extern unsigned long exec_regs[];
+extern unsigned long exec_fp_regs[];
+extern unsigned long exec_fpx_regs[];
+extern int have_fpx_regs;
+
+extern void user_time_init_skas(void);
+extern void sig_handler_common_skas(int sig, void *sc_ptr);
+extern void halt_skas(void);
+extern void reboot_skas(void);
+extern void kill_off_processes_skas(void);
+extern int is_skas_winch(int pid, int fd, void *data);
+
+#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 --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
new file mode 100644
index 0000000..94c5649
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode_kern-skas.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MODE_KERN_H__
+#define __SKAS_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+
+extern void flush_thread_skas(void);
+extern void *switch_to_skas(void *prev, void *next);
+extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+			      unsigned long esp);
+extern int copy_thread_skas(int nr, unsigned long clone_flags,
+			    unsigned long sp, unsigned long stack_top,
+			    struct task_struct *p, struct pt_regs *regs);
+extern void release_thread_skas(struct task_struct *task);
+extern void exit_thread_skas(void);
+extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
+extern void init_idle_skas(void);
+extern void flush_tlb_kernel_range_skas(unsigned long start,
+					unsigned long end);
+extern void flush_tlb_kernel_vm_skas(void);
+extern void __flush_tlb_one_skas(unsigned long addr);
+extern void flush_tlb_range_skas(struct vm_area_struct *vma,
+				 unsigned long start, unsigned long end);
+extern void flush_tlb_mm_skas(struct mm_struct *mm);
+extern void force_flush_all_skas(void);
+extern long execute_syscall_skas(void *r);
+extern void before_mem_skas(unsigned long unused);
+extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
+					 unsigned long *task_size_out);
+extern int start_uml_skas(void);
+extern int external_pid_skas(struct task_struct *task);
+extern int thread_pid_skas(struct task_struct *task);
+
+#define kmem_end_skas (host_task_size - 1024 * 1024)
+
+#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 --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h
new file mode 100644
index 0000000..cce61a6
--- /dev/null
+++ b/arch/um/kernel/skas/include/proc_mm.h
@@ -0,0 +1,55 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_PROC_MM_H
+#define __SKAS_PROC_MM_H
+
+#define MM_MMAP 54
+#define MM_MUNMAP 55
+#define MM_MPROTECT 56
+#define MM_COPY_SEGMENTS 57
+
+struct mm_mmap {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+struct mm_munmap {
+	unsigned long addr;
+	unsigned long len;	
+};
+
+struct mm_mprotect {
+	unsigned long addr;
+	unsigned long len;
+        unsigned int prot;
+};
+
+struct proc_mm_op {
+	int op;
+	union {
+		struct mm_mmap mmap;
+		struct mm_munmap munmap;
+	        struct mm_mprotect mprotect;
+		int copy_segments;
+	} u;
+};
+
+#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 --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
new file mode 100644
index 0000000..f0702c2
--- /dev/null
+++ b/arch/um/kernel/skas/include/skas.h
@@ -0,0 +1,46 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_H
+#define __SKAS_H
+
+#include "sysdep/ptrace.h"
+
+extern int userspace_pid[];
+
+extern void switch_threads(void *me, void *next);
+extern void thread_wait(void *sw, void *fb);
+extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+                       void (*handler)(int));
+extern int start_idle_thread(void *stack, void *switch_buf_ptr, 
+			     void **fork_buf_ptr);
+extern int user_thread(unsigned long stack, int flags);
+extern void userspace(union uml_pt_regs *regs);
+extern void new_thread_proc(void *stack, void (*handler)(int sig));
+extern void remove_sigstack(void);
+extern void new_thread_handler(int sig);
+extern void handle_syscall(union uml_pt_regs *regs);
+extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
+		int x, int phys_fd, unsigned long long offset);
+extern int unmap(int fd, void *addr, unsigned long len);
+extern int protect(int fd, unsigned long addr, unsigned long len, 
+		   int r, int w, int x);
+extern void user_signal(int sig, union uml_pt_regs *regs);
+extern int new_mm(int from);
+extern void start_userspace(int cpu);
+extern long execute_syscall_skas(void *r);
+
+#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 --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
new file mode 100644
index 0000000..11986c9
--- /dev/null
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_UACCESS_H
+#define __SKAS_UACCESS_H
+
+#include "asm/errno.h"
+#include "asm/fixmap.h"
+
+#define access_ok_skas(type, addr, size) \
+	((segment_eq(get_fs(), KERNEL_DS)) || \
+	 (((unsigned long) (addr) < TASK_SIZE) && \
+	  ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
+	 ((type == VERIFY_READ ) && \
+	  ((unsigned long) (addr) >= FIXADDR_USER_START) && \
+	  ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
+	  ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
+
+static inline int verify_area_skas(int type, const void * addr,
+				   unsigned long size)
+{
+	return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern int copy_from_user_skas(void *to, const void *from, int n);
+extern int copy_to_user_skas(void *to, const void *from, int n);
+extern int strncpy_from_user_skas(char *dst, const char *src, int count);
+extern int __clear_user_skas(void *mem, int len);
+extern int clear_user_skas(void *mem, int len);
+extern int strnlen_user_skas(const void *str, int len);
+
+#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 --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
new file mode 100644
index 0000000..438db2f
--- /dev/null
+++ b/arch/um/kernel/skas/mem.c
@@ -0,0 +1,35 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "mem_user.h"
+
+unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 
+				  unsigned long *task_size_out)
+{
+	/* Round up to the nearest 4M */
+	unsigned long top = ROUND_4M((unsigned long) &arg);
+
+#ifdef CONFIG_HOST_TASK_SIZE
+	*host_size_out = CONFIG_HOST_TASK_SIZE;
+	*task_size_out = CONFIG_HOST_TASK_SIZE;
+#else
+	*host_size_out = top;
+	*task_size_out = top;
+#endif
+	return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
new file mode 100644
index 0000000..1310bf1
--- /dev/null
+++ b/arch/um/kernel/skas/mem_user.c
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include "mem_user.h"
+#include "mem.h"
+#include "user.h"
+#include "os.h"
+#include "proc_mm.h"
+
+void map(int fd, unsigned long virt, unsigned long len, int r, int w,
+	 int x, int phys_fd, unsigned long long offset)
+{
+	struct proc_mm_op map;
+	int prot, n;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+
+	map = ((struct proc_mm_op) { .op 	= MM_MMAP,
+				     .u 	= 
+				     { .mmap	= 
+				       { .addr 		= virt,
+					 .len		= len,
+					 .prot		= prot,
+					 .flags		= MAP_SHARED | 
+					                  MAP_FIXED,
+					 .fd		= phys_fd,
+					 .offset	= offset
+				       } } } );
+	n = os_write_file(fd, &map, sizeof(map));
+	if(n != sizeof(map)) 
+		printk("map : /proc/mm map failed, err = %d\n", -n);
+}
+
+int unmap(int fd, void *addr, unsigned long len)
+{
+	struct proc_mm_op unmap;
+	int n;
+
+	unmap = ((struct proc_mm_op) { .op 	= MM_MUNMAP,
+				       .u 	= 
+				       { .munmap	= 
+					 { .addr 	= (unsigned long) addr,
+					   .len		= len } } } );
+	n = os_write_file(fd, &unmap, sizeof(unmap));
+	if(n != sizeof(unmap)) {
+		if(n < 0)
+			return(n);
+		else if(n > 0)
+			return(-EIO);
+	}
+
+	return(0);
+}
+
+int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 
+	    int x, int must_succeed)
+{
+	struct proc_mm_op protect;
+	int prot, n;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+
+	protect = ((struct proc_mm_op) { .op 	= MM_MPROTECT,
+				       .u 	= 
+				       { .mprotect	= 
+					 { .addr 	= (unsigned long) addr,
+					   .len		= len,
+					   .prot	= prot } } } );
+
+	n = os_write_file(fd, &protect, sizeof(protect));
+	if(n != sizeof(protect)) {
+		if(n == 0) return(0);
+
+		if(must_succeed)
+			panic("protect failed, err = %d", -n);
+
+		return(-EIO);
+	}
+
+	return(0);
+}
+
+void before_mem_skas(unsigned long unused)
+{
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
new file mode 100644
index 0000000..6cb9a6d
--- /dev/null
+++ b/arch/um/kernel/skas/mmu.c
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/list.h"
+#include "linux/spinlock.h"
+#include "linux/slab.h"
+#include "asm/current.h"
+#include "asm/segment.h"
+#include "asm/mmu.h"
+#include "os.h"
+#include "skas.h"
+
+int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
+{
+	int from;
+
+	if((current->mm != NULL) && (current->mm != &init_mm))
+		from = current->mm->context.skas.mm_fd;
+	else from = -1;
+
+	mm->context.skas.mm_fd = new_mm(from);
+	if(mm->context.skas.mm_fd < 0){
+		printk("init_new_context_skas - new_mm failed, errno = %d\n",
+		       mm->context.skas.mm_fd);
+		return(mm->context.skas.mm_fd);
+	}
+
+	return(0);
+}
+
+void destroy_context_skas(struct mm_struct *mm)
+{
+	os_close_file(mm->context.skas.mm_fd);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 0000000..b4ffaaa
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,339 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <asm/unistd.h>
+#include "user.h"
+#include "ptrace_user.h"
+#include "time_user.h"
+#include "sysdep/ptrace.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "skas.h"
+#include "sysdep/sigcontext.h"
+#include "os.h"
+#include "proc_mm.h"
+#include "skas_ptrace.h"
+#include "chan_user.h"
+#include "signal_user.h"
+#include "registers.h"
+
+int is_skas_winch(int pid, int fd, void *data)
+{
+	if(pid != os_getpid())
+		return(0);
+
+	register_winch_irq(-1, fd, -1, data);
+	return(1);
+}
+
+static void handle_segv(int pid)
+{
+	struct ptrace_faultinfo fault;
+	int err;
+
+	err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
+	if(err)
+		panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
+		      errno);
+
+	segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
+}
+
+/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
+static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
+{
+	int err, status;
+
+	/* Mark this as a syscall */
+	UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
+
+	if (!local_using_sysemu)
+	{
+		err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+		if(err < 0)
+			panic("handle_trap - nullifying syscall failed errno = %d\n",
+			      errno);
+
+		err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+		if(err < 0)
+			panic("handle_trap - continuing to end of syscall failed, "
+			      "errno = %d\n", errno);
+
+		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+		if((err < 0) || !WIFSTOPPED(status) ||
+		   (WSTOPSIG(status) != SIGTRAP + 0x80))
+			panic("handle_trap - failed to wait at end of syscall, "
+			      "errno = %d, status = %d\n", errno, status);
+	}
+
+	handle_syscall(regs);
+}
+
+static int userspace_tramp(void *arg)
+{
+	init_new_thread_signals(0);
+	enable_timer();
+	ptrace(PTRACE_TRACEME, 0, 0, 0);
+	os_stop_process(os_getpid());
+	return(0);
+}
+
+/* Each element set once, and only accessed by a single processor anyway */
+#undef NR_CPUS
+#define NR_CPUS 1
+int userspace_pid[NR_CPUS];
+
+void start_userspace(int cpu)
+{
+	void *stack;
+	unsigned long sp;
+	int pid, status, n;
+
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if(stack == MAP_FAILED)
+		panic("start_userspace : mmap failed, errno = %d", errno);
+	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+
+	pid = clone(userspace_tramp, (void *) sp, 
+		    CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
+	if(pid < 0)
+		panic("start_userspace : clone failed, errno = %d", errno);
+
+	do {
+		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+		if(n < 0)
+			panic("start_userspace : wait failed, errno = %d", 
+			      errno);
+	} while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
+
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
+		panic("start_userspace : expected SIGSTOP, got status = %d",
+		      status);
+
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n",
+		      errno);
+
+	if(munmap(stack, PAGE_SIZE) < 0)
+		panic("start_userspace : munmap failed, errno = %d\n", errno);
+
+	userspace_pid[cpu] = pid;
+}
+
+void userspace(union uml_pt_regs *regs)
+{
+	int err, status, op, pid = userspace_pid[0];
+	int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+
+	while(1){
+		restore_registers(pid, regs);
+
+		/* Now we set local_using_sysemu to be used for one loop */
+		local_using_sysemu = get_using_sysemu();
+
+		op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+
+		err = ptrace(op, pid, 0, 0);
+		if(err)
+			panic("userspace - could not resume userspace process, "
+			      "pid=%d, ptrace operation = %d, errno = %d\n",
+			      op, errno);
+
+		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+		if(err < 0)
+			panic("userspace - waitpid failed, errno = %d\n", 
+			      errno);
+
+		regs->skas.is_user = 1;
+		save_registers(pid, regs);
+		UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
+
+		if(WIFSTOPPED(status)){
+		  	switch(WSTOPSIG(status)){
+			case SIGSEGV:
+				handle_segv(pid);
+				break;
+			case SIGTRAP + 0x80:
+			        handle_trap(pid, regs, local_using_sysemu);
+				break;
+			case SIGTRAP:
+				relay_signal(SIGTRAP, regs);
+				break;
+			case SIGIO:
+			case SIGVTALRM:
+			case SIGILL:
+			case SIGBUS:
+			case SIGFPE:
+			case SIGWINCH:
+				user_signal(WSTOPSIG(status), regs);
+				break;
+			default:
+			        printk("userspace - child stopped with signal "
+				       "%d\n", WSTOPSIG(status));
+			}
+			interrupt_end();
+
+			/* Avoid -ERESTARTSYS handling in host */
+			PT_SYSCALL_NR(regs->skas.regs) = -1;
+		}
+	}
+}
+
+void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+		void (*handler)(int))
+{
+	unsigned long flags;
+	sigjmp_buf switch_buf, fork_buf;
+
+	*switch_buf_ptr = &switch_buf;
+	*fork_buf_ptr = &fork_buf;
+
+	/* Somewhat subtle - siglongjmp restores the signal mask before doing
+	 * the longjmp.  This means that when jumping from one stack to another
+	 * when the target stack has interrupts enabled, an interrupt may occur
+	 * on the source stack.  This is bad when starting up a process because
+	 * it's not supposed to get timer ticks until it has been scheduled.
+	 * So, we disable interrupts around the sigsetjmp to ensure that
+	 * they can't happen until we get back here where they are safe.
+	 */
+	flags = get_signals();
+	block_signals();
+	if(sigsetjmp(fork_buf, 1) == 0)
+		new_thread_proc(stack, handler);
+
+	remove_sigstack();
+
+	set_signals(flags);
+}
+
+void thread_wait(void *sw, void *fb)
+{
+	sigjmp_buf buf, **switch_buf = sw, *fork_buf;
+
+	*switch_buf = &buf;
+	fork_buf = fb;
+	if(sigsetjmp(buf, 1) == 0)
+		siglongjmp(*fork_buf, 1);
+}
+
+void switch_threads(void *me, void *next)
+{
+	sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
+	
+	*me_ptr = &my_buf;
+	if(sigsetjmp(my_buf, 1) == 0)
+		siglongjmp(*next_buf, 1);
+}
+
+static sigjmp_buf initial_jmpbuf;
+
+/* XXX Make these percpu */
+static void (*cb_proc)(void *arg);
+static void *cb_arg;
+static sigjmp_buf *cb_back;
+
+int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+{
+	sigjmp_buf **switch_buf = switch_buf_ptr;
+	int n;
+
+	*fork_buf_ptr = &initial_jmpbuf;
+	n = sigsetjmp(initial_jmpbuf, 1);
+	if(n == 0)
+		new_thread_proc((void *) stack, new_thread_handler);
+	else if(n == 1)
+		remove_sigstack();
+	else if(n == 2){
+		(*cb_proc)(cb_arg);
+		siglongjmp(*cb_back, 1);
+	}
+	else if(n == 3){
+		kmalloc_ok = 0;
+		return(0);
+	}
+	else if(n == 4){
+		kmalloc_ok = 0;
+		return(1);
+	}
+	siglongjmp(**switch_buf, 1);
+}
+
+void remove_sigstack(void)
+{
+	stack_t stack = ((stack_t) { .ss_flags	= SS_DISABLE,
+				     .ss_sp	= NULL,
+				     .ss_size	= 0 });
+
+	if(sigaltstack(&stack, NULL) != 0)
+		panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void initial_thread_cb_skas(void (*proc)(void *), void *arg)
+{
+	sigjmp_buf here;
+
+	cb_proc = proc;
+	cb_arg = arg;
+	cb_back = &here;
+
+	block_signals();
+	if(sigsetjmp(here, 1) == 0)
+		siglongjmp(initial_jmpbuf, 2);
+	unblock_signals();
+
+	cb_proc = NULL;
+	cb_arg = NULL;
+	cb_back = NULL;
+}
+
+void halt_skas(void)
+{
+	block_signals();
+	siglongjmp(initial_jmpbuf, 3);
+}
+
+void reboot_skas(void)
+{
+	block_signals();
+	siglongjmp(initial_jmpbuf, 4);
+}
+
+void switch_mm_skas(int mm_fd)
+{
+	int err;
+
+#warning need cpu pid in switch_mm_skas
+	err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
+	if(err)
+		panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
+		      errno);
+}
+
+void kill_off_processes_skas(void)
+{
+#warning need to loop over userspace_pids in kill_off_processes_skas
+	os_kill_ptraced_process(userspace_pid[0], 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 --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
new file mode 100644
index 0000000..5d096ea
--- /dev/null
+++ b/arch/um/kernel/skas/process_kern.c
@@ -0,0 +1,213 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/ptrace.h"
+#include "linux/proc_fs.h"
+#include "linux/file.h"
+#include "linux/errno.h"
+#include "linux/init.h"
+#include "asm/uaccess.h"
+#include "asm/atomic.h"
+#include "kern_util.h"
+#include "time_user.h"
+#include "signal_user.h"
+#include "skas.h"
+#include "os.h"
+#include "user_util.h"
+#include "tlb.h"
+#include "kern.h"
+#include "mode.h"
+#include "proc_mm.h"
+#include "registers.h"
+
+void *switch_to_skas(void *prev, void *next)
+{
+	struct task_struct *from, *to;
+
+	from = prev;
+	to = next;
+
+	/* XXX need to check runqueues[cpu].idle */
+	if(current->pid == 0)
+		switch_timers(0);
+
+	to->thread.prev_sched = from;
+	set_current(to);
+
+	switch_threads(&from->thread.mode.skas.switch_buf, 
+		       to->thread.mode.skas.switch_buf);
+
+	if(current->pid == 0)
+		switch_timers(1);
+
+	return(current->thread.prev_sched);
+}
+
+extern void schedule_tail(struct task_struct *prev);
+
+void new_thread_handler(int sig)
+{
+	int (*fn)(void *), n;
+	void *arg;
+
+	fn = current->thread.request.u.thread.proc;
+	arg = current->thread.request.u.thread.arg;
+	change_sig(SIGUSR1, 1);
+	thread_wait(&current->thread.mode.skas.switch_buf, 
+		    current->thread.mode.skas.fork_buf);
+
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	/* The return value is 1 if the kernel thread execs a process,
+	 * 0 if it just exits
+	 */
+	n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
+	if(n == 1)
+		userspace(&current->thread.regs.regs);
+	else do_exit(0);
+}
+
+void new_thread_proc(void *stack, void (*handler)(int sig))
+{
+	init_new_thread_stack(stack, handler);
+	os_usr1_process(os_getpid());
+}
+
+void release_thread_skas(struct task_struct *task)
+{
+}
+
+void exit_thread_skas(void)
+{
+}
+
+void fork_handler(int sig)
+{
+        change_sig(SIGUSR1, 1);
+ 	thread_wait(&current->thread.mode.skas.switch_buf, 
+		    current->thread.mode.skas.fork_buf);
+  	
+	force_flush_all();
+	if(current->thread.prev_sched == NULL)
+		panic("blech");
+
+	schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	userspace(&current->thread.regs.regs);
+}
+
+int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
+		     unsigned long stack_top, struct task_struct * p, 
+		     struct pt_regs *regs)
+{
+  	void (*handler)(int);
+
+	if(current->thread.forking){
+	  	memcpy(&p->thread.regs.regs.skas, 
+		       &current->thread.regs.regs.skas, 
+		       sizeof(p->thread.regs.regs.skas));
+		REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
+		if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
+
+		handler = fork_handler;
+	}
+	else {
+		init_thread_registers(&p->thread.regs.regs);
+                p->thread.request.u.thread = current->thread.request.u.thread;
+		handler = new_thread_handler;
+	}
+
+	new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
+		   &p->thread.mode.skas.fork_buf, handler);
+	return(0);
+}
+
+int new_mm(int from)
+{
+	struct proc_mm_op copy;
+	int n, fd;
+
+	fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+	if(fd < 0)
+		return(fd);
+
+	if(from != -1){
+		copy = ((struct proc_mm_op) { .op 	= MM_COPY_SEGMENTS,
+					      .u 	=
+					      { .copy_segments	= from } } );
+		n = os_write_file(fd, &copy, sizeof(copy));
+		if(n != sizeof(copy))
+			printk("new_mm : /proc/mm copy_segments failed, "
+			       "err = %d\n", -n);
+	}
+
+	return(fd);
+}
+
+void init_idle_skas(void)
+{
+	cpu_tasks[current_thread->cpu].pid = os_getpid();
+	default_idle();
+}
+
+extern void start_kernel(void);
+
+static int start_kernel_proc(void *unused)
+{
+	int pid;
+
+	block_signals();
+	pid = os_getpid();
+
+	cpu_tasks[0].pid = pid;
+	cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ 	cpu_online_map = cpumask_of_cpu(0);
+#endif
+	start_kernel();
+	return(0);
+}
+
+int start_uml_skas(void)
+{
+	start_userspace(0);
+
+	init_new_thread_signals(1);
+	uml_idle_timer();
+
+	init_task.thread.request.u.thread.proc = start_kernel_proc;
+	init_task.thread.request.u.thread.arg = NULL;
+	return(start_idle_thread(init_task.thread_info,
+				 &init_task.thread.mode.skas.switch_buf,
+				 &init_task.thread.mode.skas.fork_buf));
+}
+
+int external_pid_skas(struct task_struct *task)
+{
+#warning Need to look up userspace_pid by cpu
+	return(userspace_pid[0]);
+}
+
+int thread_pid_skas(struct task_struct *task)
+{
+#warning Need to look up userspace_pid by cpu
+	return(userspace_pid[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 --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
new file mode 100644
index 0000000..bdf040c
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_kern.c
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sys.h"
+#include "linux/ptrace.h"
+#include "asm/errno.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/current.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall_skas(void *r)
+{
+	struct pt_regs *regs = r;
+	long res;
+	int syscall;
+
+	current->thread.nsyscalls++;
+	nsyscalls++;
+	syscall = UPT_SYSCALL_NR(&regs->regs);
+
+	if((syscall >= NR_syscalls) || (syscall < 0))
+		res = -ENOSYS;
+	else res = EXECUTE_SYSCALL(syscall, regs);
+
+	return(res);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
new file mode 100644
index 0000000..2828e6e
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -0,0 +1,44 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include "kern_util.h"
+#include "uml-config.h"
+#include "syscall_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "skas.h"
+
+void handle_syscall(union uml_pt_regs *regs)
+{
+	long result;
+#if UML_CONFIG_SYSCALL_DEBUG
+  	int index;
+
+  	index = record_syscall_start(UPT_SYSCALL_NR(regs));
+#endif
+
+	syscall_trace(regs, 0);
+	result = execute_syscall_skas(regs);
+
+	REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
+
+	syscall_trace(regs, 1);
+#if UML_CONFIG_SYSCALL_DEBUG
+  	record_syscall_end(index, 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 --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
new file mode 100644
index 0000000..9809149
--- /dev/null
+++ b/arch/um/kernel/skas/time.c
@@ -0,0 +1,30 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <sys/signal.h>
+#include <sys/time.h>
+#include "time_user.h"
+#include "process.h"
+#include "user.h"
+
+void user_time_init_skas(void)
+{
+        if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+                panic("Couldn't set SIGALRM handler");
+ 	if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+ 		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
new file mode 100644
index 0000000..b8c5e717
--- /dev/null
+++ b/arch/um/kernel/skas/tlb.c
@@ -0,0 +1,85 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/mmu.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "mem.h"
+#include "skas.h"
+#include "os.h"
+#include "tlb.h"
+
+static void do_ops(int fd, struct host_vm_op *ops, int last)
+{
+	struct host_vm_op *op;
+	int i;
+
+	for(i = 0; i <= last; i++){
+		op = &ops[i];
+		switch(op->type){
+		case MMAP:
+			map(fd, op->u.mmap.addr, op->u.mmap.len,
+			    op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
+			    op->u.mmap.fd, op->u.mmap.offset);
+			break;
+		case MUNMAP:
+			unmap(fd, (void *) op->u.munmap.addr,
+			      op->u.munmap.len);
+			break;
+		case MPROTECT:
+			protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
+				op->u.mprotect.r, op->u.mprotect.w,
+				op->u.mprotect.x);
+			break;
+		default:
+			printk("Unknown op type %d in do_ops\n", op->type);
+			break;
+		}
+	}
+}
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+		      unsigned long end_addr, int force)
+{
+        int fd = mm->context.skas.mm_fd;
+
+        fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+}
+
+void __flush_tlb_one_skas(unsigned long addr)
+{
+        flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
+}
+
+void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, 
+		     unsigned long end)
+{
+        if(vma->vm_mm == NULL)
+                flush_tlb_kernel_range_common(start, end);
+        else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm_skas(struct mm_struct *mm)
+{
+	/* Don't bother flushing if this address space is about to be
+         * destroyed.
+         */
+        if(atomic_read(&mm->mm_users) == 0)
+                return;
+
+        fix_range(mm, 0, host_task_size, 0);
+        flush_tlb_kernel_range_common(start_vm, end_vm);
+}
+
+void force_flush_all_skas(void)
+{
+        fix_range(current->mm, 0, host_task_size, 1);
+}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
new file mode 100644
index 0000000..8e9b46d
--- /dev/null
+++ b/arch/um/kernel/skas/trap_user.c
@@ -0,0 +1,71 @@
+/* 
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <errno.h>
+#include "sysdep/ptrace.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "sigcontext.h"
+
+void sig_handler_common_skas(int sig, void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+	struct skas_regs *r;
+	struct signal_info *info;
+	int save_errno = errno;
+	int save_user;
+
+	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
+	 * handler.  This can happen in copy_user, and if SEGV is disabled,
+	 * the process will die.
+	 * XXX Figure out why this is better than SA_NODEFER
+	 */
+	if(sig == SIGSEGV)
+		change_sig(SIGSEGV, 1);
+
+	r = &TASK_REGS(get_current())->skas;
+	save_user = r->is_user;
+	r->is_user = 0;
+	r->fault_addr = SC_FAULT_ADDR(sc);
+	r->fault_type = SC_FAULT_TYPE(sc);
+	r->trap_type = SC_TRAP_TYPE(sc);
+
+	change_sig(SIGUSR1, 1);
+	info = &sig_info[sig];
+	if(!info->is_irq) unblock_signals();
+
+	(*info->handler)(sig, (union uml_pt_regs *) r);
+
+	errno = save_errno;
+	r->is_user = save_user;
+}
+
+void user_signal(int sig, union uml_pt_regs *regs)
+{
+	struct signal_info *info;
+
+	regs->skas.is_user = 1;
+	regs->skas.fault_addr = 0;
+	regs->skas.fault_type = 0;
+	regs->skas.trap_type = 0;
+	info = &sig_info[sig];
+	(*info->handler)(sig, regs);
+
+	unblock_signals();
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
new file mode 100644
index 0000000..7575ec4
--- /dev/null
+++ b/arch/um/kernel/skas/uaccess.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/string.h"
+#include "linux/fs.h"
+#include "linux/highmem.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+#include "user_util.h"
+
+extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
+			     pte_t *pte_out);
+
+static unsigned long maybe_map(unsigned long virt, int is_write)
+{
+	pte_t pte;
+	int err;
+
+	void *phys = um_virt_to_phys(current, virt, &pte);
+	int dummy_code;
+
+	if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+		err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
+		if(err)
+			return(0);
+		phys = um_virt_to_phys(current, virt, NULL);
+	}
+	return((unsigned long) phys);
+}
+
+static int do_op(unsigned long addr, int len, int is_write,
+		 int (*op)(unsigned long addr, int len, void *arg), void *arg)
+{
+	struct page *page;
+	int n;
+
+	addr = maybe_map(addr, is_write);
+	if(addr == -1)
+		return(-1);
+
+	page = phys_to_page(addr);
+	addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
+	n = (*op)(addr, len, arg);
+	kunmap(page);
+
+	return(n);
+}
+
+static void do_buffer_op(void *jmpbuf, void *arg_ptr)
+{
+	va_list args;
+	unsigned long addr;
+	int len, is_write, size, remain, n;
+	int (*op)(unsigned long, int, void *);
+	void *arg;
+	int *res;
+
+	/* Some old gccs recognize __va_copy, but not va_copy */
+	__va_copy(args, *(va_list *)arg_ptr);
+	addr = va_arg(args, unsigned long);
+	len = va_arg(args, int);
+	is_write = va_arg(args, int);
+	op = va_arg(args, void *);
+	arg = va_arg(args, void *);
+	res = va_arg(args, int *);
+	va_end(args);
+	size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
+	remain = len;
+
+	current->thread.fault_catcher = jmpbuf;
+	n = do_op(addr, size, is_write, op, arg);
+	if(n != 0){
+		*res = (n < 0 ? remain : 0);
+		goto out;
+	}
+
+	addr += size;
+	remain -= size;
+	if(remain == 0){
+		*res = 0;
+		goto out;
+	}
+
+	while(addr < ((addr + remain) & PAGE_MASK)){
+		n = do_op(addr, PAGE_SIZE, is_write, op, arg);
+		if(n != 0){
+			*res = (n < 0 ? remain : 0);
+			goto out;
+		}
+
+		addr += PAGE_SIZE;
+		remain -= PAGE_SIZE;
+	}
+	if(remain == 0){
+		*res = 0;
+		goto out;
+	}
+
+	n = do_op(addr, remain, is_write, op, arg);
+	if(n != 0)
+		*res = (n < 0 ? remain : 0);
+	else *res = 0;
+ out:
+	current->thread.fault_catcher = NULL;
+}
+
+static int buffer_op(unsigned long addr, int len, int is_write,
+		     int (*op)(unsigned long addr, int len, void *arg),
+		     void *arg)
+{
+	int faulted, res;
+
+	faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
+				 &res);
+	if(!faulted)
+		return(res);
+
+	return(addr + len - (unsigned long) current->thread.fault_addr);
+}
+
+static int copy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+	unsigned long *to_ptr = arg, to = *to_ptr;
+
+	memcpy((void *) to, (void *) from, len);
+	*to_ptr += len;
+	return(0);
+}
+
+int copy_from_user_skas(void *to, const void __user *from, int n)
+{
+	if(segment_eq(get_fs(), KERNEL_DS)){
+		memcpy(to, (__force void*)from, n);
+		return(0);
+	}
+
+	return(access_ok_skas(VERIFY_READ, from, n) ?
+	       buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
+	       n);
+}
+
+static int copy_chunk_to_user(unsigned long to, int len, void *arg)
+{
+	unsigned long *from_ptr = arg, from = *from_ptr;
+
+	memcpy((void *) to, (void *) from, len);
+	*from_ptr += len;
+	return(0);
+}
+
+int copy_to_user_skas(void __user *to, const void *from, int n)
+{
+	if(segment_eq(get_fs(), KERNEL_DS)){
+		memcpy((__force void*)to, from, n);
+		return(0);
+	}
+
+	return(access_ok_skas(VERIFY_WRITE, to, n) ?
+	       buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
+	       n);
+}
+
+static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+	char **to_ptr = arg, *to = *to_ptr;
+	int n;
+
+	strncpy(to, (void *) from, len);
+	n = strnlen(to, len);
+	*to_ptr += n;
+
+	if(n < len)
+	        return(1);
+	return(0);
+}
+
+int strncpy_from_user_skas(char *dst, const char __user *src, int count)
+{
+	int n;
+	char *ptr = dst;
+
+	if(segment_eq(get_fs(), KERNEL_DS)){
+		strncpy(dst, (__force void*)src, count);
+		return(strnlen(dst, count));
+	}
+
+	if(!access_ok_skas(VERIFY_READ, src, 1))
+		return(-EFAULT);
+
+	n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
+		      &ptr);
+	if(n != 0)
+		return(-EFAULT);
+	return(strnlen(dst, count));
+}
+
+static int clear_chunk(unsigned long addr, int len, void *unused)
+{
+	memset((void *) addr, 0, len);
+	return(0);
+}
+
+int __clear_user_skas(void __user *mem, int len)
+{
+	return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
+}
+
+int clear_user_skas(void __user *mem, int len)
+{
+	if(segment_eq(get_fs(), KERNEL_DS)){
+		memset((__force void*)mem, 0, len);
+		return(0);
+	}
+
+	return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+	       buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
+}
+
+static int strnlen_chunk(unsigned long str, int len, void *arg)
+{
+	int *len_ptr = arg, n;
+
+	n = strnlen((void *) str, len);
+	*len_ptr += n;
+
+	if(n < len)
+		return(1);
+	return(0);
+}
+
+int strnlen_user_skas(const void __user *str, int len)
+{
+	int count = 0, n;
+
+	if(segment_eq(get_fs(), KERNEL_DS))
+		return(strnlen((__force char*)str, len) + 1);
+
+	n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
+	if(n == 0)
+		return(count + 1);
+	return(-EFAULT);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
new file mode 100644
index 0000000..17f5909
--- /dev/null
+++ b/arch/um/kernel/skas/util/Makefile
@@ -0,0 +1,4 @@
+hostprogs-y		:= mk_ptregs
+always			:= $(hostprogs-y)
+
+mk_ptregs-objs := mk_ptregs-$(SUBARCH).o
diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c
new file mode 100644
index 0000000..0788dd0
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
+
+int main(int argc, char **argv)
+{
+	printf("/* Automatically generated by "
+	       "arch/um/kernel/skas/util/mk_ptregs */\n");
+	printf("\n");
+	printf("#ifndef __SKAS_PT_REGS_\n");
+	printf("#define __SKAS_PT_REGS_\n");
+	printf("\n");
+	printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
+	printf("#define HOST_FP_SIZE %d\n",
+	       sizeof(struct user_i387_struct) / sizeof(unsigned long));
+	printf("#define HOST_XFP_SIZE %d\n",
+	       sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
+
+	PRINT_REG("IP", EIP);
+	PRINT_REG("SP", UESP);
+	PRINT_REG("EFLAGS", EFL);
+	PRINT_REG("EAX", EAX);
+	PRINT_REG("EBX", EBX);
+	PRINT_REG("ECX", ECX);
+	PRINT_REG("EDX", EDX);
+	PRINT_REG("ESI", ESI);
+	PRINT_REG("EDI", EDI);
+	PRINT_REG("EBP", EBP);
+	PRINT_REG("CS", CS);
+	PRINT_REG("SS", SS);
+	PRINT_REG("DS", DS);
+	PRINT_REG("FS", FS);
+	PRINT_REG("ES", ES);
+	PRINT_REG("GS", GS);
+	printf("\n");
+	printf("#endif\n");
+	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 --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
new file mode 100644
index 0000000..67aee92
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2003 PathScale, Inc.
+ *
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#define __FRAME_OFFSETS
+#include <asm/ptrace.h>
+
+#define PRINT_REG(name, val) \
+	printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val))
+
+int main(int argc, char **argv)
+{
+	printf("/* Automatically generated by "
+	       "arch/um/kernel/skas/util/mk_ptregs */\n");
+	printf("\n");
+	printf("#ifndef __SKAS_PT_REGS_\n");
+	printf("#define __SKAS_PT_REGS_\n");
+	printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n",
+	       FRAME_SIZE);
+	PRINT_REG("RBX", RBX);
+	PRINT_REG("RCX", RCX);
+	PRINT_REG("RDI", RDI);
+	PRINT_REG("RSI", RSI);
+	PRINT_REG("RDX", RDX);
+	PRINT_REG("RBP", RBP);
+	PRINT_REG("RAX", RAX);
+	PRINT_REG("R8", R8);
+	PRINT_REG("R9", R9);
+	PRINT_REG("R10", R10);
+	PRINT_REG("R11", R11);
+	PRINT_REG("R12", R12);
+	PRINT_REG("R13", R13);
+	PRINT_REG("R14", R14);
+	PRINT_REG("R15", R15);
+	PRINT_REG("ORIG_RAX", ORIG_RAX);
+	PRINT_REG("CS", CS);
+	PRINT_REG("SS", SS);
+	PRINT_REG("EFLAGS", EFLAGS);
+#if 0
+	PRINT_REG("FS", FS);
+	PRINT_REG("GS", GS);
+	PRINT_REG("DS", DS);
+	PRINT_REG("ES", ES);
+#endif
+
+	PRINT_REG("IP", RIP);
+	PRINT_REG("SP", RSP);
+	printf("#define HOST_FP_SIZE 0\n");
+	printf("#define HOST_XFP_SIZE 0\n");
+	printf("\n");
+	printf("\n");
+	printf("#endif\n");
+	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 --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
new file mode 100644
index 0000000..72113b0
--- /dev/null
+++ b/arch/um/kernel/smp.c
@@ -0,0 +1,269 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/percpu.h"
+#include "asm/pgalloc.h"
+#include "asm/tlb.h"
+
+/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+#ifdef CONFIG_SMP
+
+#include "linux/sched.h"
+#include "linux/module.h"
+#include "linux/threads.h"
+#include "linux/interrupt.h"
+#include "linux/err.h"
+#include "linux/hardirq.h"
+#include "asm/smp.h"
+#include "asm/processor.h"
+#include "asm/spinlock.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "os.h"
+
+/* CPU online map, set by smp_boot_cpus */
+cpumask_t cpu_online_map = CPU_MASK_NONE;
+cpumask_t cpu_possible_map = CPU_MASK_NONE;
+
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(cpu_possible_map);
+
+/* Per CPU bogomips and other parameters
+ * The only piece used here is the ipi pipe, which is set before SMP is
+ * started and never changed.
+ */
+struct cpuinfo_um cpu_data[NR_CPUS];
+
+/* A statistic, can be a little off */
+int num_reschedules_sent = 0;
+
+/* Not changed after boot */
+struct task_struct *idle_threads[NR_CPUS];
+
+void smp_send_reschedule(int cpu)
+{
+	os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
+	num_reschedules_sent++;
+}
+
+void smp_send_stop(void)
+{
+	int i;
+
+	printk(KERN_INFO "Stopping all CPUs...");
+	for(i = 0; i < num_online_cpus(); i++){
+		if(i == current_thread->cpu)
+			continue;
+		os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
+	}
+	printk("done\n");
+}
+
+static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
+static cpumask_t cpu_callin_map = CPU_MASK_NONE;
+
+static int idle_proc(void *cpup)
+{
+	int cpu = (int) cpup, err;
+
+	err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
+	if(err < 0)
+		panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
+
+	activate_ipi(cpu_data[cpu].ipi_pipe[0], 
+		     current->thread.mode.tt.extern_pid);
+ 
+	wmb();
+	if (cpu_test_and_set(cpu, cpu_callin_map)) {
+		printk("huh, CPU#%d already present??\n", cpu);
+		BUG();
+	}
+
+	while (!cpu_isset(cpu, smp_commenced_mask))
+		cpu_relax();
+
+	cpu_set(cpu, cpu_online_map);
+	default_idle();
+	return(0);
+}
+
+static struct task_struct *idle_thread(int cpu)
+{
+	struct task_struct *new_task;
+	unsigned char c;
+
+        current->thread.request.u.thread.proc = idle_proc;
+        current->thread.request.u.thread.arg = (void *) cpu;
+	new_task = fork_idle(cpu);
+	if(IS_ERR(new_task))
+		panic("copy_process failed in idle_thread, error = %ld",
+		      PTR_ERR(new_task));
+
+	cpu_tasks[cpu] = ((struct cpu_task) 
+		          { .pid = 	new_task->thread.mode.tt.extern_pid,
+			    .task = 	new_task } );
+	idle_threads[cpu] = new_task;
+	CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
+			  sizeof(c)),
+		    ({ panic("skas mode doesn't support SMP"); }));
+	return(new_task);
+}
+
+void smp_prepare_cpus(unsigned int maxcpus)
+{
+	struct task_struct *idle;
+	unsigned long waittime;
+	int err, cpu, me = smp_processor_id();
+	int i;
+
+	for (i = 0; i < ncpus; ++i)
+		cpu_set(i, cpu_possible_map);
+
+	cpu_clear(me, cpu_online_map);
+	cpu_set(me, cpu_online_map);
+	cpu_set(me, cpu_callin_map);
+
+	err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
+	if(err < 0)
+		panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
+
+	activate_ipi(cpu_data[me].ipi_pipe[0],
+		     current->thread.mode.tt.extern_pid);
+
+	for(cpu = 1; cpu < ncpus; cpu++){
+		printk("Booting processor %d...\n", cpu);
+		
+		idle = idle_thread(cpu);
+
+		init_idle(idle, cpu);
+		unhash_process(idle);
+
+		waittime = 200000000;
+		while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
+			cpu_relax();
+
+		if (cpu_isset(cpu, cpu_callin_map))
+			printk("done\n");
+		else printk("failed\n");
+	}
+}
+
+void smp_prepare_boot_cpu(void)
+{
+	cpu_set(smp_processor_id(), cpu_online_map);
+}
+
+int __cpu_up(unsigned int cpu)
+{
+	cpu_set(cpu, smp_commenced_mask);
+	while (!cpu_isset(cpu, cpu_online_map))
+		mb();
+	return(0);
+}
+
+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 (os_read_file(fd, &c, 1) == 1) {
+		switch (c) {
+		case 'C':
+			smp_call_function_slave(cpu);
+			break;
+
+		case 'R':
+			set_tsk_need_resched(current);
+			break;
+
+		case 'S':
+			printk("CPU#%d stopping\n", cpu);
+			while(1)
+				pause();
+			break;
+
+		default:
+			printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
+			break;
+		}
+	}
+}
+
+int hard_smp_processor_id(void)
+{
+	return(pid_to_processor_id(os_getpid()));
+}
+
+static DEFINE_SPINLOCK(call_lock);
+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 = num_online_cpus() - 1;
+	int i;
+
+	if (!cpus)
+		return 0;
+
+	/* Can deadlock when called with interrupts disabled */
+	WARN_ON(irqs_disabled());
+
+	spin_lock_bh(&call_lock);
+	atomic_set(&scf_started, 0);
+	atomic_set(&scf_finished, 0);
+	func = _func;
+	info = _info;
+
+	for_each_online_cpu(i)
+		os_write_file(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 --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
new file mode 100644
index 0000000..7fc06c8
--- /dev/null
+++ b/arch/um/kernel/sys_call_table.c
@@ -0,0 +1,276 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/unistd.h"
+#include "linux/sys.h"
+#include "linux/swap.h"
+#include "linux/syscalls.h"
+#include "linux/sysctl.h"
+#include "asm/signal.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+#ifdef CONFIG_NFSD
+#define NFSSERVCTL sys_nfsservctl
+#else
+#define NFSSERVCTL sys_ni_syscall
+#endif
+
+#define LAST_GENERIC_SYSCALL __NR_keyctl
+
+#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+#define LAST_SYSCALL LAST_GENERIC_SYSCALL
+#else
+#define LAST_SYSCALL LAST_ARCH_SYSCALL
+#endif
+
+extern syscall_handler_t sys_fork;
+extern syscall_handler_t sys_execve;
+extern syscall_handler_t um_time;
+extern syscall_handler_t um_stime;
+extern syscall_handler_t sys_pipe;
+extern syscall_handler_t sys_olduname;
+extern syscall_handler_t sys_sigaction;
+extern syscall_handler_t sys_sigsuspend;
+extern syscall_handler_t old_readdir;
+extern syscall_handler_t sys_uname;
+extern syscall_handler_t sys_ipc;
+extern syscall_handler_t sys_sigreturn;
+extern syscall_handler_t sys_clone;
+extern syscall_handler_t sys_rt_sigreturn;
+extern syscall_handler_t sys_sigaltstack;
+extern syscall_handler_t sys_vfork;
+extern syscall_handler_t old_select;
+extern syscall_handler_t sys_modify_ldt;
+extern syscall_handler_t sys_rt_sigsuspend;
+extern syscall_handler_t sys_mbind;
+extern syscall_handler_t sys_get_mempolicy;
+extern syscall_handler_t sys_set_mempolicy;
+extern syscall_handler_t sys_sys_setaltroot;
+
+syscall_handler_t *sys_call_table[] = {
+	[ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
+	[ __NR_exit ] = (syscall_handler_t *) sys_exit,
+	[ __NR_fork ] = (syscall_handler_t *) sys_fork,
+	[ __NR_read ] = (syscall_handler_t *) sys_read,
+	[ __NR_write ] = (syscall_handler_t *) 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_creat ] = (syscall_handler_t *) sys_creat,
+	[ __NR_link ] = (syscall_handler_t *) sys_link,
+	[ __NR_unlink ] = (syscall_handler_t *) sys_unlink,
+	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
+
+	/* declared differently in kern_util.h */
+	[ __NR_chdir ] = (syscall_handler_t *) sys_chdir,
+	[ __NR_time ] = um_time,
+	[ __NR_mknod ] = (syscall_handler_t *) sys_mknod,
+	[ __NR_chmod ] = (syscall_handler_t *) sys_chmod,
+	[ __NR_lchown ] = (syscall_handler_t *) sys_lchown16,
+	[ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
+	[ __NR_getpid ] = (syscall_handler_t *) sys_getpid,
+	[ __NR_mount ] = (syscall_handler_t *) sys_mount,
+	[ __NR_setuid ] = (syscall_handler_t *) sys_setuid16,
+	[ __NR_getuid ] = (syscall_handler_t *) sys_getuid16,
+ 	[ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace,
+	[ __NR_alarm ] = (syscall_handler_t *) sys_alarm,
+	[ __NR_pause ] = (syscall_handler_t *) sys_pause,
+	[ __NR_utime ] = (syscall_handler_t *) sys_utime,
+	[ __NR_access ] = (syscall_handler_t *) sys_access,
+	[ __NR_sync ] = (syscall_handler_t *) sys_sync,
+	[ __NR_kill ] = (syscall_handler_t *) sys_kill,
+	[ __NR_rename ] = (syscall_handler_t *) sys_rename,
+	[ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir,
+	[ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir,
+
+	/* Declared differently in asm/unistd.h */
+	[ __NR_dup ] = (syscall_handler_t *) sys_dup,
+	[ __NR_pipe ] = (syscall_handler_t *) sys_pipe,
+	[ __NR_times ] = (syscall_handler_t *) sys_times,
+	[ __NR_brk ] = (syscall_handler_t *) sys_brk,
+	[ __NR_setgid ] = (syscall_handler_t *) sys_setgid16,
+	[ __NR_getgid ] = (syscall_handler_t *) sys_getgid16,
+	[ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16,
+	[ __NR_getegid ] = (syscall_handler_t *) sys_getegid16,
+	[ __NR_acct ] = (syscall_handler_t *) sys_acct,
+	[ __NR_umount2 ] = (syscall_handler_t *) sys_umount,
+	[ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl,
+	[ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl,
+	[ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid,
+	[ __NR_umask ] = (syscall_handler_t *) sys_umask,
+	[ __NR_chroot ] = (syscall_handler_t *) sys_chroot,
+	[ __NR_ustat ] = (syscall_handler_t *) sys_ustat,
+	[ __NR_dup2 ] = (syscall_handler_t *) sys_dup2,
+	[ __NR_getppid ] = (syscall_handler_t *) sys_getppid,
+	[ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp,
+	[ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
+	[ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16,
+	[ __NR_setregid ] = (syscall_handler_t *) sys_setregid16,
+	[ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname,
+	[ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit,
+	[ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit,
+	[ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage,
+	[ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday,
+	[ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday,
+	[ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16,
+	[ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16,
+	[ __NR_symlink ] = (syscall_handler_t *) sys_symlink,
+	[ __NR_readlink ] = (syscall_handler_t *) sys_readlink,
+	[ __NR_uselib ] = (syscall_handler_t *) sys_uselib,
+	[ __NR_swapon ] = (syscall_handler_t *) sys_swapon,
+	[ __NR_reboot ] = (syscall_handler_t *) sys_reboot,
+	[ __NR_munmap ] = (syscall_handler_t *) sys_munmap,
+	[ __NR_truncate ] = (syscall_handler_t *) sys_truncate,
+	[ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate,
+	[ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod,
+	[ __NR_fchown ] = (syscall_handler_t *) sys_fchown16,
+	[ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority,
+	[ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority,
+	[ __NR_statfs ] = (syscall_handler_t *) sys_statfs,
+	[ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs,
+	[ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_syslog ] = (syscall_handler_t *) sys_syslog,
+	[ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer,
+	[ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer,
+	[ __NR_stat ] = (syscall_handler_t *) sys_newstat,
+	[ __NR_lstat ] = (syscall_handler_t *) sys_newlstat,
+	[ __NR_fstat ] = (syscall_handler_t *) sys_newfstat,
+	[ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup,
+	[ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
+	[ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff,
+	[ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo,
+	[ __NR_fsync ] = (syscall_handler_t *) sys_fsync,
+	[ __NR_clone ] = (syscall_handler_t *) sys_clone,
+	[ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname,
+	[ __NR_uname ] = (syscall_handler_t *) sys_newuname,
+	[ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex,
+	[ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect,
+	[ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_init_module ] = (syscall_handler_t *) sys_init_module,
+	[ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module,
+	[ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl,
+	[ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid,
+	[ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir,
+	[ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs,
+	[ __NR_personality ] = (syscall_handler_t *) sys_personality,
+	[ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16,
+	[ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16,
+	[ __NR_getdents ] = (syscall_handler_t *) sys_getdents,
+	[ __NR_flock ] = (syscall_handler_t *) sys_flock,
+	[ __NR_msync ] = (syscall_handler_t *) sys_msync,
+	[ __NR_readv ] = (syscall_handler_t *) sys_readv,
+	[ __NR_writev ] = (syscall_handler_t *) sys_writev,
+	[ __NR_getsid ] = (syscall_handler_t *) sys_getsid,
+	[ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync,
+	[ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl,
+	[ __NR_mlock ] = (syscall_handler_t *) sys_mlock,
+	[ __NR_munlock ] = (syscall_handler_t *) sys_munlock,
+	[ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall,
+	[ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall,
+	[ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam,
+	[ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam,
+	[ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler,
+	[ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler,
+	[ __NR_sched_yield ] = (syscall_handler_t *) yield,
+	[ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max,
+	[ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min,
+	[ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval,
+	[ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep,
+	[ __NR_mremap ] = (syscall_handler_t *) sys_mremap,
+	[ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16,
+	[ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16,
+	[ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_poll ] = (syscall_handler_t *) sys_poll,
+	[ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL,
+	[ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16,
+	[ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16,
+	[ __NR_prctl ] = (syscall_handler_t *) sys_prctl,
+	[ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn,
+	[ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction,
+	[ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask,
+	[ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending,
+	[ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait,
+	[ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo,
+	[ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend,
+	[ __NR_pread64 ] = (syscall_handler_t *) sys_pread64,
+	[ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64,
+	[ __NR_chown ] = (syscall_handler_t *) sys_chown16,
+	[ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd,
+	[ __NR_capget ] = (syscall_handler_t *) sys_capget,
+	[ __NR_capset ] = (syscall_handler_t *) sys_capset,
+	[ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack,
+	[ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile,
+	[ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_vfork ] = (syscall_handler_t *) sys_vfork,
+	[ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64,
+	[ __NR_gettid ] = (syscall_handler_t *) sys_gettid,
+	[ __NR_readahead ] = (syscall_handler_t *) sys_readahead,
+	[ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr,
+	[ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr,
+	[ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr,
+	[ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr,
+	[ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr,
+	[ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr,
+	[ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr,
+	[ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr,
+	[ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr,
+	[ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr,
+	[ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr,
+	[ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr,
+	[ __NR_tkill ] = (syscall_handler_t *) sys_tkill,
+	[ __NR_futex ] = (syscall_handler_t *) sys_futex,
+	[ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity,
+	[ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity,
+	[ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup,
+	[ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy,
+	[ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents,
+	[ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit,
+	[ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel,
+	[ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group,
+	[ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie,
+	[ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create,
+	[ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl,
+	[ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait,
+	[ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages,
+	[ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address,
+	[ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create,
+	[ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime,
+	[ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime,
+	[ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun,
+	[ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete,
+	[ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime,
+	[ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime,
+	[ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres,
+	[ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep,
+	[ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill,
+	[ __NR_utimes ] = (syscall_handler_t *) sys_utimes,
+	[ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64,
+	[ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_mbind ] = (syscall_handler_t *) sys_mbind,
+	[ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy,
+	[ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy,
+	[ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open,
+	[ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink,
+	[ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend,
+	[ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive,
+	[ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify,
+	[ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr,
+	[ __NR_kexec_load ] = (syscall_handler_t *) sys_ni_syscall,
+	[ __NR_waitid ] = (syscall_handler_t *) sys_waitid,
+	[ __NR_add_key ] = (syscall_handler_t *) sys_add_key,
+	[ __NR_request_key ] = (syscall_handler_t *) sys_request_key,
+	[ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl,
+
+	ARCH_SYSCALLS
+	[ LAST_SYSCALL + 1 ... NR_syscalls ] = 
+		(syscall_handler_t *) sys_ni_syscall
+};
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
new file mode 100644
index 0000000..42731e0
--- /dev/null
+++ b/arch/um/kernel/syscall_kern.c
@@ -0,0 +1,176 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.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/syscalls.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"
+#include "mode_kern.h"
+#include "choose-mode.h"
+
+/*  Unlocked, I don't care if this is a bit off */
+int nsyscalls = 0;
+
+long sys_fork(void)
+{
+	long ret;
+
+	current->thread.forking = 1;
+        ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+	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, NULL,
+		      NULL);
+	current->thread.forking = 0;
+	return(ret);
+}
+
+/* common code for old and new mmaps */
+long sys_mmap2(unsigned long addr, unsigned long len,
+	       unsigned long prot, unsigned long flags,
+	       unsigned long fd, unsigned long pgoff)
+{
+	long 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 old_mmap(unsigned long addr, unsigned long len,
+	      unsigned long prot, unsigned long flags,
+	      unsigned long fd, unsigned long offset)
+{
+	long err = -EINVAL;
+	if (offset & ~PAGE_MASK)
+		goto out;
+
+	err = sys_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.
+ */
+long sys_pipe(unsigned long __user * fildes)
+{
+        int fd[2];
+        long error;
+
+        error = do_pipe(fd);
+        if (!error) {
+		if (copy_to_user(fildes, fd, sizeof(fd)))
+                        error = -EFAULT;
+        }
+        return error;
+}
+
+
+long sys_uname(struct old_utsname * name)
+{
+	long 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;
+}
+
+long sys_olduname(struct oldold_utsname * name)
+{
+	long 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;
+}
+
+DEFINE_SPINLOCK(syscall_lock);
+
+static int syscall_index = 0;
+
+int next_syscall_index(int limit)
+{
+	int ret;
+
+	spin_lock(&syscall_lock);
+	ret = syscall_index;
+	if(++syscall_index == limit)
+		syscall_index = 0;
+	spin_unlock(&syscall_lock);
+	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 --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
new file mode 100644
index 0000000..01b711e
--- /dev/null
+++ b/arch/um/kernel/syscall_user.c
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include "kern_util.h"
+#include "syscall_user.h"
+
+struct {
+	int syscall;
+	int pid;
+	long result;
+	struct timeval start;
+	struct timeval end;
+} syscall_record[1024];
+
+int record_syscall_start(int syscall)
+{
+	int max, index;
+
+	max = sizeof(syscall_record)/sizeof(syscall_record[0]);
+	index = next_syscall_index(max);
+
+	syscall_record[index].syscall = syscall;
+	syscall_record[index].pid = current_pid();
+	syscall_record[index].result = 0xdeadbeef;
+	gettimeofday(&syscall_record[index].start, NULL);
+	return(index);
+}
+
+void record_syscall_end(int index, long result)
+{
+	syscall_record[index].result = result;
+	gettimeofday(&syscall_record[index].end, NULL);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
new file mode 100644
index 0000000..e630438
--- /dev/null
+++ b/arch/um/kernel/sysrq.c
@@ -0,0 +1,81 @@
+/* 
+ * 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 "linux/kallsyms.h"
+#include "asm/page.h"
+#include "asm/processor.h"
+#include "sysrq.h"
+#include "user_util.h"
+
+void show_trace(unsigned long * stack)
+{
+	/* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from
+	 * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/
+        unsigned long addr;
+
+        if (!stack) {
+                stack = (unsigned long*) &stack;
+		WARN_ON(1);
+	}
+
+        printk("Call Trace: \n");
+        while (((long) stack & (THREAD_SIZE-1)) != 0) {
+                addr = *stack;
+		if (__kernel_text_address(addr)) {
+			printk("%08lx:  [<%08lx>]", (unsigned long) stack, addr);
+			print_symbol(" %s", addr);
+			printk("\n");
+                }
+                stack++;
+        }
+        printk("\n");
+}
+
+/*
+ * stack dumps generator - this is used by arch-independent code.
+ * And this is identical to i386 currently.
+ */
+void dump_stack(void)
+{
+	unsigned long stack;
+
+	show_trace(&stack);
+}
+EXPORT_SYMBOL(dump_stack);
+
+/*Stolen from arch/i386/kernel/traps.c */
+static int kstack_depth_to_print = 24;
+
+/* This recently started being used in arch-independent code too, as in
+ * kernel/sched.c.*/
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+	unsigned long *stack;
+	int i;
+
+	if (esp == NULL) {
+		if (task != current) {
+			esp = (unsigned long *) KSTK_ESP(task);
+			/* Which one? No actual difference - just coding style.*/
+			//esp = (unsigned long *) PT_REGS_IP(&task->thread.regs);
+		} else {
+			esp = (unsigned long *) &esp;
+		}
+	}
+
+	stack = esp;
+	for(i = 0; i < kstack_depth_to_print; i++) {
+		if (kstack_end(stack))
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n       ");
+		printk("%08lx ", *stack++);
+	}
+
+	show_trace(esp);
+}
diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
new file mode 100644
index 0000000..b1674bc
--- /dev/null
+++ b/arch/um/kernel/tempfile.c
@@ -0,0 +1,82 @@
+/*
+ * 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 <errno.h>
+#include <sys/param.h>
+#include "init.h"
+
+/* Modified from create_mem_file and start_debugger */
+static 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) && (*dir != '\0'))
+			break;
+	}
+	if((dir == NULL) || (*dir == '\0')) 
+		dir = "/tmp";
+
+	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);
+	fd = mkstemp(tempname);
+	if(fd < 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){
+		*out_tempname = strdup(tempname);
+		if(*out_tempname == NULL){
+			perror("strdup");
+			return -1;
+		}
+	}
+	return(fd);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
new file mode 100644
index 0000000..c40c86a
--- /dev/null
+++ b/arch/um/kernel/time.c
@@ -0,0 +1,167 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.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"
+#include "time_user.h"
+#include "kern_constants.h"
+
+/* XXX This really needs to be declared and initialized in a kernel file since
+ * it's in <linux/time.h>
+ */
+extern struct timespec wall_to_monotonic;
+
+extern struct timeval xtime;
+
+struct timeval local_offset = { 0, 0 };
+
+void timer(void)
+{
+	gettimeofday(&xtime, NULL);
+	timeradd(&xtime, &local_offset, &xtime);
+}
+
+void set_interval(int timer_type)
+{
+	int usec = 1000000/hz();
+	struct itimerval interval = ((struct itimerval) { { 0, usec },
+							  { 0, usec } });
+
+	if(setitimer(timer_type, &interval, NULL) == -1)
+		panic("setitimer failed - errno = %d\n", errno);
+}
+
+void enable_timer(void)
+{
+	int usec = 1000000/hz();
+	struct itimerval enable = ((struct itimerval) { { 0, usec },
+							{ 0, usec }});
+	if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
+		printk("enable_timer - setitimer failed, errno = %d\n",
+		       errno);
+}
+
+void disable_timer(void)
+{
+	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+	if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
+	   (setitimer(ITIMER_REAL, &disable, NULL) < 0))
+		printk("disnable_timer - setitimer failed, errno = %d\n",
+		       errno);
+	/* If there are signals already queued, after unblocking ignore them */
+	set_handler(SIGALRM, SIG_IGN, 0, -1);
+	set_handler(SIGVTALRM, SIG_IGN, 0, -1);
+}
+
+void switch_timers(int to_real)
+{
+	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+	struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
+							{ 0, 1000000/hz() }});
+	int old, new;
+
+	if(to_real){
+		old = ITIMER_VIRTUAL;
+		new = ITIMER_REAL;
+	}
+	else {
+		old = ITIMER_REAL;
+		new = ITIMER_VIRTUAL;
+	}
+
+	if((setitimer(old, &disable, NULL) < 0) ||
+	   (setitimer(new, &enable, NULL)))
+		printk("switch_timers - setitimer failed, errno = %d\n",
+		       errno);
+}
+
+void uml_idle_timer(void)
+{
+	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+		panic("Couldn't unset SIGVTALRM handler");
+	
+	set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
+		    SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
+	set_interval(ITIMER_REAL);
+}
+
+extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
+
+void time_init(void)
+{
+	struct timespec now;
+
+	if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+
+	do_posix_clock_monotonic_gettime(&now);
+	wall_to_monotonic.tv_sec = -now.tv_sec;
+	wall_to_monotonic.tv_nsec = -now.tv_nsec;
+}
+
+/* Declared in linux/time.h, which can't be included here */
+extern void clock_was_set(void);
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+
+	flags = time_lock();
+	gettimeofday(tv, NULL);
+	timeradd(tv, &local_offset, tv);
+	time_unlock(flags);
+	clock_was_set();
+}
+
+int do_settimeofday(struct timespec *tv)
+{
+	struct timeval now;
+	unsigned long flags;
+	struct timeval tv_in;
+
+	if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
+		return -EINVAL;
+
+	tv_in.tv_sec = tv->tv_sec;
+	tv_in.tv_usec = tv->tv_nsec / 1000;
+
+	flags = time_lock();
+	gettimeofday(&now, NULL);
+	timersub(&tv_in, &now, &local_offset);
+	time_unlock(flags);
+
+	return(0);
+}
+
+void idle_sleep(int secs)
+{
+	struct timespec ts;
+
+	ts.tv_sec = secs;
+	ts.tv_nsec = 0;
+	nanosleep(&ts, NULL);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
new file mode 100644
index 0000000..2461cd7
--- /dev/null
+++ b/arch/um/kernel/time_kern.c
@@ -0,0 +1,203 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/module.h"
+#include "linux/unistd.h"
+#include "linux/stddef.h"
+#include "linux/spinlock.h"
+#include "linux/time.h"
+#include "linux/sched.h"
+#include "linux/interrupt.h"
+#include "linux/init.h"
+#include "linux/delay.h"
+#include "asm/irq.h"
+#include "asm/param.h"
+#include "asm/current.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "time_user.h"
+#include "mode.h"
+#include "os.h"
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+int hz(void)
+{
+	return(HZ);
+}
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies_64 * (1000000000 / HZ);
+}
+
+/* Changed at early boot */
+int timer_irq_inited = 0;
+
+static int first_tick;
+static unsigned long long prev_usecs;
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
+static long long delta;   		/* Deviation per interval */
+#endif
+
+#define MILLION 1000000
+
+void timer_irq(union uml_pt_regs *regs)
+{
+	unsigned long long ticks = 0;
+
+	if(!timer_irq_inited){
+		/* This is to ensure that ticks don't pile up when
+		 * the timer handler is suspended */
+		first_tick = 0;
+		return;
+	}
+
+	if(first_tick){
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
+		/* We've had 1 tick */
+		unsigned long long usecs = os_usecs();
+
+		delta += usecs - prev_usecs;
+		prev_usecs = usecs;
+
+		/* Protect against the host clock being set backwards */
+		if(delta < 0)
+			delta = 0;
+
+		ticks += (delta * HZ) / MILLION;
+		delta -= (ticks * MILLION) / HZ;
+#else
+		ticks = 1;
+#endif
+	}
+	else {
+		prev_usecs = os_usecs();
+		first_tick = 1;
+	}
+
+	while(ticks > 0){
+		do_IRQ(TIMER_IRQ, regs);
+		ticks--;
+	}
+}
+
+void boot_timer_handler(int sig)
+{
+	struct pt_regs regs;
+
+	CHOOSE_MODE((void) 
+		    (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
+		    (void) (regs.regs.skas.is_user = 0));
+	do_timer(&regs);
+}
+
+irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	do_timer(regs);
+	write_seqlock_irqsave(&xtime_lock, flags);
+	timer();
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+	return(IRQ_HANDLED);
+}
+
+long um_time(int __user *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 __user *tptr)
+{
+	int value;
+	struct timespec new;
+
+	if (get_user(value, tptr))
+                return -EFAULT;
+	new.tv_sec = value;
+	new.tv_nsec = 0;
+	do_settimeofday(&new);
+	return 0;
+}
+
+void __udelay(unsigned long usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+	for(i=0;i<n;i++) ;
+}
+
+void __const_udelay(unsigned long usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / MILLION;
+	for(i=0;i<n;i++) ;
+}
+
+void timer_handler(int sig, union uml_pt_regs *regs)
+{
+	local_irq_disable();
+	update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user));
+	local_irq_enable();
+	if(current_thread->cpu == 0)
+		timer_irq(regs);
+}
+
+static DEFINE_SPINLOCK(timer_spinlock);
+
+unsigned long time_lock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_spinlock, flags);
+	return(flags);
+}
+
+void time_unlock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&timer_spinlock, flags);
+}
+
+int __init timer_init(void)
+{
+	int err;
+
+	CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
+	err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
+	if(err != 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 --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
new file mode 100644
index 0000000..eda477e
--- /dev/null
+++ b/arch/um/kernel/tlb.c
@@ -0,0 +1,369 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgalloc.h"
+#include "asm/tlbflush.h"
+#include "choose-mode.h"
+#include "mode_kern.h"
+#include "user_util.h"
+#include "tlb.h"
+#include "mem.h"
+#include "mem_user.h"
+#include "os.h"
+
+#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
+
+void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
+                      unsigned long end_addr, int force, int data,
+                      void (*do_ops)(int, struct host_vm_op *, int))
+{
+        pgd_t *npgd;
+        pud_t *npud;
+        pmd_t *npmd;
+        pte_t *npte;
+        unsigned long addr, end;
+        int r, w, x;
+        struct host_vm_op ops[16];
+        int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
+
+        if(mm == NULL) return;
+
+        for(addr = start_addr; addr < end_addr;){
+                npgd = pgd_offset(mm, addr);
+                if(!pgd_present(*npgd)){
+                        end = ADD_ROUND(addr, PGDIR_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pgd_newpage(*npgd)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pgd_mkuptodate(*npgd);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npud = pud_offset(npgd, addr);
+                if(!pud_present(*npud)){
+                        end = ADD_ROUND(addr, PUD_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pud_newpage(*npud)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pud_mkuptodate(*npud);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npmd = pmd_offset(npud, addr);
+                if(!pmd_present(*npmd)){
+                        end = ADD_ROUND(addr, PMD_SIZE);
+                        if(end > end_addr)
+                                end = end_addr;
+                        if(force || pmd_newpage(*npmd)){
+                                op_index = add_munmap(addr, end - addr, ops,
+                                                      op_index, last_op, data,
+                                                      do_ops);
+                                pmd_mkuptodate(*npmd);
+                        }
+                        addr = end;
+                        continue;
+                }
+
+                npte = pte_offset_kernel(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)){
+                        if(pte_present(*npte))
+                                op_index = add_mmap(addr,
+                                                    pte_val(*npte) & PAGE_MASK,
+                                                    PAGE_SIZE, r, w, x, ops,
+                                                    op_index, last_op, data,
+                                                    do_ops);
+                        else op_index = add_munmap(addr, PAGE_SIZE, ops,
+                                                   op_index, last_op, data,
+                                                   do_ops);
+                }
+                else if(pte_newprot(*npte))
+                        op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
+                                                op_index, last_op, data,
+                                                do_ops);
+
+                *npte = pte_mkuptodate(*npte);
+                addr += PAGE_SIZE;
+        }
+        (*do_ops)(data, ops, op_index);
+}
+
+int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
+{
+        struct mm_struct *mm;
+        pgd_t *pgd;
+        pud_t *pud;
+        pmd_t *pmd;
+        pte_t *pte;
+        unsigned long addr, last;
+        int updated = 0, err;
+
+        mm = &init_mm;
+        for(addr = start; addr < end;){
+                pgd = pgd_offset(mm, addr);
+                if(!pgd_present(*pgd)){
+                        last = ADD_ROUND(addr, PGDIR_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pgd_newpage(*pgd)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pud = pud_offset(pgd, addr);
+                if(!pud_present(*pud)){
+                        last = ADD_ROUND(addr, PUD_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pud_newpage(*pud)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pmd = pmd_offset(pud, addr);
+                if(!pmd_present(*pmd)){
+                        last = ADD_ROUND(addr, PMD_SIZE);
+                        if(last > end)
+                                last = end;
+                        if(pmd_newpage(*pmd)){
+                                updated = 1;
+                                err = os_unmap_memory((void *) addr,
+                                                      last - addr);
+                                if(err < 0)
+                                        panic("munmap failed, errno = %d\n",
+                                              -err);
+                        }
+                        addr = last;
+                        continue;
+                }
+
+                pte = pte_offset_kernel(pmd, addr);
+                if(!pte_present(*pte) || pte_newpage(*pte)){
+                        updated = 1;
+                        err = os_unmap_memory((void *) addr,
+                                              PAGE_SIZE);
+                        if(err < 0)
+                                panic("munmap failed, errno = %d\n",
+                                      -err);
+                        if(pte_present(*pte))
+                                map_memory(addr,
+                                           pte_val(*pte) & PAGE_MASK,
+                                           PAGE_SIZE, 1, 1, 1);
+                }
+                else if(pte_newprot(*pte)){
+                        updated = 1;
+                        protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
+                }
+                addr += PAGE_SIZE;
+        }
+        return(updated);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+        address &= PAGE_MASK;
+        flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+        flush_tlb_mm(current->mm);
+}
+  
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+        CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+                         flush_tlb_kernel_range_common, start, end);
+}
+
+void flush_tlb_kernel_vm(void)
+{
+        CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+                    flush_tlb_kernel_range_common(start_vm, end_vm));
+}
+
+void __flush_tlb_one(unsigned long addr)
+{
+        CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
+     unsigned long end)
+{
+        CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+                         end);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+        CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+}
+
+void force_flush_all(void)
+{
+        CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+}
+
+pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
+{
+        return(pgd_offset(mm, address));
+}
+
+pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
+{
+        return(pud_offset(pgd, address));
+}
+
+pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
+{
+        return(pmd_offset(pud, address));
+}
+
+pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
+{
+        return(pte_offset_kernel(pmd, address));
+}
+
+pte_t *addr_pte(struct task_struct *task, unsigned long addr)
+{
+        pgd_t *pgd = pgd_offset(task->mm, addr);
+        pud_t *pud = pud_offset(pgd, addr);
+        pmd_t *pmd = pmd_offset(pud, addr);
+
+        return(pte_offset_map(pmd, addr));
+}
+
+int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
+     int r, int w, int x, struct host_vm_op *ops, int index,
+     int last_filled, int data,
+     void (*do_ops)(int, struct host_vm_op *, int))
+{
+        __u64 offset;
+	struct host_vm_op *last;
+	int fd;
+
+	fd = phys_mapping(phys, &offset);
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MMAP) &&
+		   (last->u.mmap.addr + last->u.mmap.len == virt) &&
+		   (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
+		   (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+		   (last->u.mmap.offset + last->u.mmap.len == offset)){
+			last->u.mmap.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MMAP,
+					      .u = { .mmap = {
+						      .addr	= virt,
+						      .len	= len,
+						      .r	= r,
+						      .w	= w,
+						      .x	= x,
+						      .fd	= fd,
+						      .offset	= offset }
+					      } });
+	return(index);
+}
+
+int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
+	       int index, int last_filled, int data,
+	       void (*do_ops)(int, struct host_vm_op *, int))
+{
+	struct host_vm_op *last;
+
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MUNMAP) &&
+		   (last->u.munmap.addr + last->u.mmap.len == addr)){
+			last->u.munmap.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MUNMAP,
+					      .u = { .munmap = {
+						      .addr	= addr,
+						      .len	= len } } });
+	return(index);
+}
+
+int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
+		 struct host_vm_op *ops, int index, int last_filled, int data,
+		 void (*do_ops)(int, struct host_vm_op *, int))
+{
+	struct host_vm_op *last;
+
+	if(index != -1){
+		last = &ops[index];
+		if((last->type == MPROTECT) &&
+		   (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
+		   (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
+		   (last->u.mprotect.x == x)){
+			last->u.mprotect.len += len;
+			return(index);
+		}
+	}
+
+	if(index == last_filled){
+		(*do_ops)(data, ops, last_filled);
+		index = -1;
+	}
+
+	ops[++index] = ((struct host_vm_op) { .type	= MPROTECT,
+					      .u = { .mprotect = {
+						      .addr	= addr,
+						      .len	= len,
+						      .r	= r,
+						      .w	= w,
+						      .x	= x } } });
+	return(index);
+}
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
new file mode 100644
index 0000000..47e766e
--- /dev/null
+++ b/arch/um/kernel/trap_kern.c
@@ -0,0 +1,251 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "asm/errno.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/spinlock.h"
+#include "linux/config.h"
+#include "linux/init.h"
+#include "linux/ptrace.h"
+#include "asm/semaphore.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/tlbflush.h"
+#include "asm/a.out.h"
+#include "asm/current.h"
+#include "asm/irq.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "chan_kern.h"
+#include "mconsole_kern.h"
+#include "2_5compat.h"
+#include "mem.h"
+#include "mem_kern.h"
+
+int handle_page_fault(unsigned long address, unsigned long ip, 
+		      int is_write, int is_user, int *code_out)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long page;
+	int err = -EFAULT;
+
+	*code_out = SEGV_MAPERR;
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, address);
+	if(!vma) 
+		goto out;
+	else if(vma->vm_start <= address) 
+		goto good_area;
+	else if(!(vma->vm_flags & VM_GROWSDOWN)) 
+		goto out;
+	else if(!ARCH_IS_STACKGROW(address))
+		goto out;
+	else if(expand_stack(vma, address)) 
+		goto out;
+
+ good_area:
+	*code_out = SEGV_ACCERR;
+	if(is_write && !(vma->vm_flags & VM_WRITE)) 
+		goto out;
+	page = address & PAGE_MASK;
+	pgd = pgd_offset(mm, page);
+	pud = pud_offset(pgd, page);
+	pmd = pmd_offset(pud, page);
+	do {
+ survive:
+		switch (handle_mm_fault(mm, vma, address, is_write)){
+		case VM_FAULT_MINOR:
+			current->min_flt++;
+			break;
+		case VM_FAULT_MAJOR:
+			current->maj_flt++;
+			break;
+		case VM_FAULT_SIGBUS:
+			err = -EACCES;
+			goto out;
+		case VM_FAULT_OOM:
+			err = -ENOMEM;
+			goto out_of_memory;
+		default:
+			BUG();
+		}
+		pgd = pgd_offset(mm, page);
+		pud = pud_offset(pgd, page);
+		pmd = pmd_offset(pud, page);
+		pte = pte_offset_kernel(pmd, page);
+	} while(!pte_present(*pte));
+	err = 0;
+	*pte = pte_mkyoung(*pte);
+	if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
+	flush_tlb_page(vma, page);
+ out:
+	up_read(&mm->mmap_sem);
+	return(err);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	if (current->pid == 1) {
+		up_read(&mm->mmap_sem);
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
+	goto out;
+}
+
+LIST_HEAD(physmem_remappers);
+
+void register_remapper(struct remapper *info)
+{
+	list_add(&info->list, &physmem_remappers);
+}
+
+static int check_remapped_addr(unsigned long address, int is_write)
+{
+	struct remapper *remapper;
+	struct list_head *ele;
+	__u64 offset;
+	int fd;
+
+	fd = phys_mapping(__pa(address), &offset);
+	if(fd == -1)
+		return(0);
+
+	list_for_each(ele, &physmem_remappers){
+		remapper = list_entry(ele, struct remapper, list);
+		if((*remapper->proc)(fd, address, is_write, offset))
+			return(1);
+	}
+
+	return(0);
+}
+
+unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
+		   int is_user, void *sc)
+{
+	struct siginfo si;
+	void *catcher;
+	int err;
+
+        if(!is_user && (address >= start_vm) && (address < end_vm)){
+                flush_tlb_kernel_vm();
+                return(0);
+        }
+	else if(check_remapped_addr(address & PAGE_MASK, is_write))
+		return(0);
+	else if(current->mm == NULL)
+		panic("Segfault with no mm");
+	err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
+
+	catcher = current->thread.fault_catcher;
+	if(!err)
+		return(0);
+	else if(catcher != NULL){
+		current->thread.fault_addr = (void *) address;
+		do_longjmp(catcher, 1);
+	} 
+	else if(current->thread.fault_addr != NULL)
+		panic("fault_addr set but no fault catcher");
+	else if(arch_fixup(ip, sc))
+		return(0);
+
+ 	if(!is_user) 
+		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
+		      address, ip);
+
+	if(err == -EACCES){
+		si.si_signo = SIGBUS;
+		si.si_errno = 0;
+		si.si_code = BUS_ADRERR;
+		si.si_addr = (void *)address;
+		force_sig_info(SIGBUS, &si, current);
+	}
+	else if(err == -ENOMEM){
+		printk("VM: killing process %s\n", current->comm);
+		do_exit(SIGKILL);
+	}
+	else {
+		si.si_signo = SIGSEGV;
+		si.si_addr = (void *) address;
+		current->thread.cr2 = address;
+		current->thread.err = is_write;
+		force_sig_info(SIGSEGV, &si, current);
+	}
+	return(0);
+}
+
+void bad_segv(unsigned long address, unsigned long ip, int is_write)
+{
+	struct siginfo si;
+
+	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, union uml_pt_regs *regs)
+{
+	if(arch_handle_signal(sig, regs)) return;
+	if(!UPT_IS_USER(regs))
+		panic("Kernel mode signal %d", sig);
+	force_sig(sig, current);
+}
+
+void bus_handler(int sig, union uml_pt_regs *regs)
+{
+	if(current->thread.fault_catcher != NULL)
+		do_longjmp(current->thread.fault_catcher, 1);
+	else relay_signal(sig, regs);
+}
+
+void winch(int sig, union uml_pt_regs *regs)
+{
+	do_IRQ(WINCH_IRQ, regs);
+}
+
+void trap_init(void)
+{
+}
+
+DEFINE_SPINLOCK(trap_lock);
+
+static int trap_index = 0;
+
+int next_trap_index(int limit)
+{
+	int ret;
+
+	spin_lock(&trap_lock);
+	ret = trap_index;
+	if(++trap_index == limit)
+		trap_index = 0;
+	spin_unlock(&trap_lock);
+	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 --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
new file mode 100644
index 0000000..50a4042
--- /dev/null
+++ b/arch/um/kernel/trap_user.c
@@ -0,0 +1,120 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include "init.h"
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "irq_user.h"
+#include "signal_user.h"
+#include "time_user.h"
+#include "task.h"
+#include "mode.h"
+#include "choose-mode.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+
+void kill_child_dead(int pid)
+{
+	kill(pid, SIGKILL);
+	kill(pid, SIGCONT);
+	do {
+		int n;
+		CATCH_EINTR(n = waitpid(pid, NULL, 0));
+		if (n > 0)
+			kill(pid, SIGCONT);
+		else
+			break;
+	} while(1);
+}
+
+/* Unlocked - don't care if this is a bit off */
+int nsegfaults = 0;
+
+struct {
+	unsigned long address;
+	int is_write;
+	int pid;
+	unsigned long sp;
+	int is_user;
+} segfault_record[1024];
+
+void segv_handler(int sig, union uml_pt_regs *regs)
+{
+	int index, max;
+
+	if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){
+		bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), 
+			 UPT_FAULT_WRITE(regs));
+		return;
+	}
+	max = sizeof(segfault_record)/sizeof(segfault_record[0]);
+	index = next_trap_index(max);
+
+	nsegfaults++;
+	segfault_record[index].address = UPT_FAULT_ADDR(regs);
+	segfault_record[index].pid = os_getpid();
+	segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
+	segfault_record[index].sp = UPT_SP(regs);
+	segfault_record[index].is_user = UPT_IS_USER(regs);
+	segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
+	     UPT_IS_USER(regs), regs);
+}
+
+void usr2_handler(int sig, union uml_pt_regs *regs)
+{
+	CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
+}
+
+struct signal_info sig_info[] = {
+	[ SIGTRAP ] { .handler 		= relay_signal,
+		      .is_irq 		= 0 },
+	[ SIGFPE ] { .handler 		= relay_signal,
+		     .is_irq 		= 0 },
+	[ SIGILL ] { .handler 		= relay_signal,
+		     .is_irq 		= 0 },
+	[ SIGWINCH ] { .handler		= winch,
+		       .is_irq		= 1 },
+	[ SIGBUS ] { .handler 		= bus_handler,
+		     .is_irq 		= 0 },
+	[ SIGSEGV] { .handler 		= segv_handler,
+		     .is_irq 		= 0 },
+	[ SIGIO ] { .handler 		= sigio_handler,
+		    .is_irq 		= 1 },
+	[ SIGVTALRM ] { .handler 	= timer_handler,
+			.is_irq 	= 1 },
+        [ SIGALRM ] { .handler          = timer_handler,
+                      .is_irq           = 1 },
+	[ SIGUSR2 ] { .handler 		= usr2_handler,
+		      .is_irq 		= 0 },
+};
+
+void do_longjmp(void *b, int val)
+{
+	sigjmp_buf *buf = b;
+
+	siglongjmp(*buf, val);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
new file mode 100644
index 0000000..3d5177d
--- /dev/null
+++ b/arch/um/kernel/tt/Makefile
@@ -0,0 +1,28 @@
+# 
+# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+extra-y := unmap_fin.o
+clean-files := unmap_tmp.o
+
+obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
+	syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+	uaccess.o uaccess_user.o
+
+obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
+
+USER_OBJS := gdb.o time.o tracer.o
+
+include arch/um/scripts/Makefile.rules
+
+UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
+UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
+
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
+
+$(obj)/unmap_fin.o : $(obj)/unmap.o
+	$(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
+	$(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
+
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
new file mode 100644
index 0000000..065b504
--- /dev/null
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -0,0 +1,87 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/mm.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/pgalloc.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+#include "time_user.h"
+#include "signal_user.h"
+#include "mem_user.h"
+#include "os.h"
+#include "tlb.h"
+#include "mode.h"
+
+static int exec_tramp(void *sig_stack)
+{
+	init_new_thread_stack(sig_stack, NULL);
+	init_new_thread_signals(1);
+	os_stop_process(os_getpid());
+	return(0);
+}
+
+void flush_thread_tt(void)
+{
+	unsigned long stack;
+	int new_pid;
+
+	stack = alloc_stack(0, 0);
+	if(stack == 0){
+		printk(KERN_ERR 
+		       "flush_thread : failed to allocate temporary stack\n");
+		do_exit(SIGKILL);
+	}
+		
+	new_pid = start_fork_tramp(current->thread_info, 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(current_thread->cpu == 0)
+		forward_interrupts(new_pid);
+	current->thread.request.op = OP_EXEC;
+	current->thread.request.u.exec.pid = new_pid;
+	unprotect_stack((unsigned long) current_thread);
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+
+	change_sig(SIGUSR1, 0);
+	enable_timer();
+	free_page(stack);
+	protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+	task_protections((unsigned long) current_thread);
+	force_flush_all();
+	unblock_signals();
+}
+
+void start_thread_tt(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);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
new file mode 100644
index 0000000..a92c02f
--- /dev/null
+++ b/arch/um/kernel/tt/exec_user.c
@@ -0,0 +1,57 @@
+/* 
+ * 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 <signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ptrace_user.h"
+#include "os.h"
+
+void do_exec(int old_pid, int new_pid)
+{
+	unsigned long regs[FRAME_SIZE];
+	int err;
+
+	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
+		tracer_panic("do_exec failed to attach proc - errno = %d",
+			     errno);
+
+	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
+	if (err < 0)
+		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
+			     errno);
+
+	if(ptrace_getregs(old_pid, regs) < 0)
+		tracer_panic("do_exec failed to get registers - errno = %d",
+			     errno);
+
+	os_kill_ptraced_process(old_pid, 0);
+
+	if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
+
+	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 --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
new file mode 100644
index 0000000..19a0ad7
--- /dev/null
+++ b/arch/um/kernel/tt/gdb.c
@@ -0,0 +1,278 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include "ptrace_user.h"
+#include "uml-config.h"
+#include "kern_constants.h"
+#include "chan_user.h"
+#include "init.h"
+#include "user.h"
+#include "debug.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "tt.h"
+#include "sysdep/thread.h"
+
+extern int debugger_pid;
+extern int debugger_fd;
+extern int debugger_parent;
+
+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));
+}
+
+#ifdef UML_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,
+	.tramp_stack 	= 0,
+	.in_kernel  	= 0,
+};
+
+/* Accessed by the tracing thread, which automatically serializes access */
+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 *, char **);
+extern void xterm_close(int, void *);
+
+int open_gdb_chan(void)
+{
+	char stack[UM_KERN_PAGE_SIZE], *dummy;
+
+	opts.tramp_stack = (unsigned long) stack;
+	xterm_data = xterm_init("", 0, &opts);
+	xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
+	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(debugger_parent != -1)
+			detach(debugger_parent, SIGINT);
+	}
+	if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
+}
+
+static void exit_debugger(void)
+{
+	initial_thread_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;
+	void *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 = strtoul(data->str, NULL, 0);
+		task = cpu_tasks[0].task;
+		debugger_pid = attach_debugger(TASK_EXTERN_PID(task), 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;
+	initial_thread_cb(config_gdb_cb, &data);
+	return(data.err);
+}
+
+void remove_gdb_cb(void *unused)
+{
+	exit_debugger_cb(NULL);
+}
+
+int gdb_remove(char *unused)
+{
+	initial_thread_cb(remove_gdb_cb, NULL);
+	return(0);
+}
+
+void signal_usr1(int sig)
+{
+	if(debugger_pid != -1){
+		printf("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, NULL);
+ 	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, NULL);
+	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 = 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)
+{
+	printf("debug requested when CONFIG_PT_PROXY is off\n");
+	kill_child_dead(idle_pid);
+	exit(1);
+}
+
+void signal_usr1(int sig)
+{
+	printf("debug requested when CONFIG_PT_PROXY is off\n");
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	printf("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);
+}
+
+int init_parent_proxy(int pid)
+{
+	return(-1);
+}
+
+void debugger_parent_signal(int status, 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 --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
new file mode 100644
index 0000000..93fb121
--- /dev/null
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -0,0 +1,40 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/config.h"
+#include "mconsole_kern.h"
+
+#ifdef CONFIG_MCONSOLE
+
+extern int gdb_config(char *str);
+extern int gdb_remove(char *unused);
+
+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
+
+/*
+ * 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 --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
new file mode 100644
index 0000000..8eff674
--- /dev/null
+++ b/arch/um/kernel/tt/include/debug.h
@@ -0,0 +1,29 @@
+/* 
+ * 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);
+extern int gdb_config(char *str);
+extern int gdb_remove(char *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 --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
new file mode 100644
index 0000000..0440510
--- /dev/null
+++ b/arch/um/kernel/tt/include/mmu-tt.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MMU_H
+#define __TT_MMU_H
+
+struct mmu_context_tt {
+};
+
+#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 --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
new file mode 100644
index 0000000..efe4620
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_TT_H__
+#define __MODE_TT_H__
+
+#include "sysdep/ptrace.h"
+
+enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+
+extern int tracing_pid;
+
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void user_time_init_tt(void);
+extern void sig_handler_common_tt(int sig, void *sc);
+extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
+extern void reboot_tt(void);
+extern void halt_tt(void);
+extern int is_tracer_winch(int pid, int fd, void *data);
+extern void kill_off_processes_tt(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 --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
new file mode 100644
index 0000000..28aaab3
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode_kern-tt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MODE_KERN_H__
+#define __TT_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+
+extern void *switch_to_tt(void *prev, void *next);
+extern void flush_thread_tt(void);
+extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+			   unsigned long esp);
+extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+			  unsigned long stack_top, struct task_struct *p,
+			  struct pt_regs *regs);
+extern void release_thread_tt(struct task_struct *task);
+extern void exit_thread_tt(void);
+extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
+extern void init_idle_tt(void);
+extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_vm_tt(void);
+extern void __flush_tlb_one_tt(unsigned long addr);
+extern void flush_tlb_range_tt(struct vm_area_struct *vma,
+			       unsigned long start, unsigned long end);
+extern void flush_tlb_mm_tt(struct mm_struct *mm);
+extern void force_flush_all_tt(void);
+extern long execute_syscall_tt(void *r);
+extern void before_mem_tt(unsigned long brk_start);
+extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+				       unsigned long *task_size_out);
+extern int start_uml_tt(void);
+extern int external_pid_tt(struct task_struct *task);
+extern int thread_pid_tt(struct task_struct *task);
+
+#define kmem_end_tt (host_task_size - ABOVE_KMEM)
+
+#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 --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
new file mode 100644
index 0000000..c667b67a
--- /dev/null
+++ b/arch/um/kernel/tt/include/tt.h
@@ -0,0 +1,46 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_H__
+#define __TT_H__
+
+#include "sysdep/ptrace.h"
+
+extern int gdb_pid;
+extern int debug;
+extern int debug_stop;
+extern int debug_trace;
+
+extern int honeypot;
+
+extern int fork_tramp(void *sig_stack);
+extern int do_proc_op(void *t, int proc_id);
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void attach_process(int pid);
+extern void tracer_panic(char *format, ...);
+extern void set_init_pid(int pid);
+extern int set_user_mode(void *task);
+extern void set_tracing(void *t, int tracing);
+extern int is_tracing(void *task);
+extern void syscall_handler(int sig, union uml_pt_regs *regs);
+extern void exit_kernel(int pid, void *task);
+extern void do_syscall(void *task, int pid, int local_using_sysemu);
+extern void do_sigtrap(void *task);
+extern int is_valid_pid(int pid);
+extern void remap_data(void *segment_start, void *segment_end, int w);
+extern long execute_syscall_tt(void *r);
+
+#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 --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
new file mode 100644
index 0000000..f0bad01
--- /dev/null
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_UACCESS_H
+#define __TT_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"
+#include "uml_uaccess.h"
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+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 access_ok_tt(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_tt(int type, const void * addr,
+				 unsigned long size)
+{
+	return(access_ok_tt(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);
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+				  void **fault_addr, void **fault_catcher);
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+			   void **fault_catcher);
+extern int __do_strnlen_user(const char *str, unsigned long n,
+			     void **fault_addr, void **fault_catcher);
+
+extern int copy_from_user_tt(void *to, const void *from, int n);
+extern int copy_to_user_tt(void *to, const void *from, int n);
+extern int strncpy_from_user_tt(char *dst, const char *src, int count);
+extern int __clear_user_tt(void *mem, int len);
+extern int clear_user_tt(void *mem, int len);
+extern int strnlen_user_tt(const void *str, int len);
+
+#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 --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
new file mode 100644
index 0000000..92ec85d
--- /dev/null
+++ b/arch/um/kernel/tt/ksyms.c
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+#include "asm/uaccess.h"
+#include "mode.h"
+
+EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_copy_to_user);
+EXPORT_SYMBOL(__do_strncpy_from_user);
+EXPORT_SYMBOL(__do_strnlen_user); 
+EXPORT_SYMBOL(__do_clear_user);
+
+EXPORT_SYMBOL(tracing_pid);
+EXPORT_SYMBOL(honeypot);
+
+/*
+ * 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 --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
new file mode 100644
index 0000000..74346a0
--- /dev/null
+++ b/arch/um/kernel/tt/mem.c
@@ -0,0 +1,51 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "asm/uaccess.h"
+#include "mem_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "kern.h"
+#include "tt.h"
+
+void before_mem_tt(unsigned long brk_start)
+{
+	if(debug)
+		remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
+	remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
+	remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
+}
+
+#ifdef CONFIG_HOST_2G_2G
+#define TOP 0x80000000
+#else
+#define TOP 0xc0000000
+#endif
+
+#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
+#define START (TOP - SIZE)
+
+unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, 
+				unsigned long *task_size_out)
+{
+	/* Round up to the nearest 4M */
+	*host_size_out = ROUND_4M((unsigned long) &arg);
+	*task_size_out = START;
+	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 --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
new file mode 100644
index 0000000..3085267
--- /dev/null
+++ b/arch/um/kernel/tt/mem_user.c
@@ -0,0 +1,49 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "tt.h"
+#include "mem_user.h"
+#include "user_util.h"
+
+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);
+	addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
+	if(addr == MAP_FAILED){
+		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);
+	}
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
new file mode 100644
index 0000000..f19f7c1
--- /dev/null
+++ b/arch/um/kernel/tt/process_kern.c
@@ -0,0 +1,476 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/signal.h"
+#include "linux/kernel.h"
+#include "linux/interrupt.h"
+#include "linux/ptrace.h"
+#include "asm/system.h"
+#include "asm/pgalloc.h"
+#include "asm/ptrace.h"
+#include "asm/tlbflush.h"
+#include "irq_user.h"
+#include "signal_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "kern.h"
+#include "sigcontext.h"
+#include "time_user.h"
+#include "mem_user.h"
+#include "tlb.h"
+#include "mode.h"
+#include "init.h"
+#include "tt.h"
+
+void *switch_to_tt(void *prev, void *next, void *last)
+{
+	struct task_struct *from, *to, *prev_sched;
+	unsigned long flags;
+	int err, vtalrm, alrm, prof, cpu;
+	char c;
+	/* jailing and SMP are incompatible, so this doesn't need to be 
+	 * made per-cpu 
+	 */
+	static int reading;
+
+	from = prev;
+	to = next;
+
+	to->thread.prev_sched = from;
+
+	cpu = from->thread_info->cpu;
+	if(cpu == 0)
+		forward_interrupts(to->thread.mode.tt.extern_pid);
+#ifdef CONFIG_SMP
+	forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
+#endif
+	local_irq_save(flags);
+
+	vtalrm = change_sig(SIGVTALRM, 0);
+	alrm = change_sig(SIGALRM, 0);
+	prof = change_sig(SIGPROF, 0);
+
+	forward_pending_sigio(to->thread.mode.tt.extern_pid);
+
+	c = 0;
+	set_current(to);
+
+	reading = 0;
+	err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("write of switch_pipe failed, err = %d", -err);
+
+	reading = 1;
+	if((from->exit_state == EXIT_ZOMBIE) ||
+	   (from->exit_state == EXIT_DEAD))
+		os_kill_process(os_getpid(), 0);
+
+	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read of switch_pipe failed, errno = %d", -err);
+
+	/* If the process that we have just scheduled away from has exited,
+	 * then it needs to be killed here.  The reason is that, even though
+	 * it will kill itself when it next runs, that may be too late.  Its
+	 * stack will be freed, possibly before then, and if that happens,
+	 * we have a use-after-free situation.  So, it gets killed here
+	 * in case it has not already killed itself.
+	 */
+	prev_sched = current->thread.prev_sched;
+	if((prev_sched->exit_state == EXIT_ZOMBIE) ||
+	   (prev_sched->exit_state == EXIT_DEAD))
+		os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
+
+	change_sig(SIGVTALRM, vtalrm);
+	change_sig(SIGALRM, alrm);
+	change_sig(SIGPROF, prof);
+
+	arch_switch();
+
+	flush_tlb_all();
+	local_irq_restore(flags);
+
+	return(current->thread.prev_sched);
+}
+
+void release_thread_tt(struct task_struct *task)
+{
+	int pid = task->thread.mode.tt.extern_pid;
+
+	if(os_getpid() != pid)
+		os_kill_process(pid, 0);
+}
+
+void exit_thread_tt(void)
+{
+	os_close_file(current->thread.mode.tt.switch_pipe[0]);
+	os_close_file(current->thread.mode.tt.switch_pipe[1]);
+}
+
+void suspend_new_thread(int fd)
+{
+	int err;
+	char c;
+
+	os_stop_process(os_getpid());
+	err = os_read_file(fd, &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read failed in suspend_new_thread, err = %d", -err);
+}
+
+void schedule_tail(task_t *prev);
+
+static void new_thread_handler(int sig)
+{
+	unsigned long disable;
+	int (*fn)(void *);
+	void *arg;
+
+	fn = current->thread.request.u.thread.proc;
+	arg = current->thread.request.u.thread.arg;
+
+	UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+	disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
+		(1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
+	SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
+
+	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+	force_flush_all();
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	init_new_thread_signals(1);
+	enable_timer();
+	free_page(current->thread.temp_stack);
+	set_cmdline("(kernel thread)");
+
+	change_sig(SIGUSR1, 1);
+	change_sig(SIGVTALRM, 1);
+	change_sig(SIGPROF, 1);
+	local_irq_enable();
+	if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
+		do_exit(0);
+
+	/* XXX No set_user_mode here because a newly execed process will
+	 * immediately segfault on its non-existent IP, coming straight back
+	 * to the signal handler, which will call set_user_mode on its way
+	 * out.  This should probably change since it's confusing.
+	 */
+}
+
+static int new_thread_proc(void *stack)
+{
+	/* local_irq_disable is needed to block out signals until this thread is
+	 * properly scheduled.  Otherwise, the tracing thread will get mighty
+	 * upset about any signals that arrive before that.
+	 * This has the complication that it sets the saved signal mask in
+	 * the sigcontext to block signals.  This gets restored when this
+	 * thread (or a descendant, since they get a copy of this sigcontext)
+	 * returns to userspace.
+	 * So, this is compensated for elsewhere.
+	 * XXX There is still a small window until local_irq_disable() actually
+	 * finishes where signals are possible - shouldn't be a problem in
+	 * practice since SIGIO hasn't been forwarded here yet, and the
+	 * local_irq_disable should finish before a SIGVTALRM has time to be
+	 * delivered.
+	 */
+
+	local_irq_disable();
+	init_new_thread_stack(stack, new_thread_handler);
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+	return(0);
+}
+
+/* Signal masking - signals are blocked at the start of fork_tramp.  They
+ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
+ * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off,
+ * so it is blocked before it's called.  They are re-enabled on sigreturn
+ * despite the fact that they were blocked when the SIGUSR1 was issued because
+ * copy_thread copies the parent's sigcontext, including the signal mask
+ * onto the signal frame.
+ */
+
+void finish_fork_handler(int sig)
+{
+ 	UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+	force_flush_all();
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	enable_timer();
+	change_sig(SIGVTALRM, 1);
+	local_irq_enable();
+	if(current->mm != current->parent->mm)
+		protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
+			       1, 0, 1);
+	task_protections((unsigned long) current_thread);
+
+	free_page(current->thread.temp_stack);
+	local_irq_disable();
+	change_sig(SIGUSR1, 0);
+	set_user_mode(current);
+}
+
+int fork_tramp(void *stack)
+{
+	local_irq_disable();
+	arch_init_thread();
+	init_new_thread_stack(stack, finish_fork_handler);
+
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+	return(0);
+}
+
+int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+		   unsigned long stack_top, struct task_struct * p, 
+		   struct pt_regs *regs)
+{
+	int (*tramp)(void *);
+	int new_pid, err;
+	unsigned long stack;
+	
+	if(current->thread.forking)
+		tramp = fork_tramp;
+	else {
+		tramp = new_thread_proc;
+		p->thread.request.u.thread = current->thread.request.u.thread;
+	}
+
+	err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
+	if(err < 0){
+		printk("copy_thread : pipe failed, err = %d\n", -err);
+		return(err);
+	}
+
+	stack = alloc_stack(0, 0);
+	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(p->thread_info, 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(UPT_SC(&p->thread.regs.regs), 
+			 UPT_SC(&current->thread.regs.regs));
+		SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
+		if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
+	}
+	p->thread.mode.tt.extern_pid = new_pid;
+
+	current->thread.request.op = OP_FORK;
+	current->thread.request.u.fork.pid = new_pid;
+	os_usr1_process(os_getpid());
+
+	/* Enable the signal and then disable it to ensure that it is handled
+	 * here, and nowhere else.
+	 */
+	change_sig(SIGUSR1, 1);
+
+	change_sig(SIGUSR1, 0);
+	err = 0;
+	return(err);
+}
+
+void reboot_tt(void)
+{
+	current->thread.request.op = OP_REBOOT;
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+}
+
+void halt_tt(void)
+{
+	current->thread.request.op = OP_HALT;
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+}
+
+void kill_off_processes_tt(void)
+{
+	struct task_struct *p;
+	int me;
+
+	me = os_getpid();
+        for_each_process(p){
+		if(p->thread.mode.tt.extern_pid != me) 
+			os_kill_process(p->thread.mode.tt.extern_pid, 0);
+	}
+	if(init_task.thread.mode.tt.extern_pid != me) 
+		os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
+}
+
+void initial_thread_cb_tt(void (*proc)(void *), void *arg)
+{
+	if(os_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;
+		os_usr1_process(os_getpid());
+		change_sig(SIGUSR1, 1);
+
+		change_sig(SIGUSR1, 0);
+	}
+}
+
+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->mode.tt.extern_pid, pid);
+		thread->mode.tt.extern_pid = pid;
+		cpu_tasks[task->thread_info->cpu].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);
+}
+
+void init_idle_tt(void)
+{
+	default_idle();
+}
+
+extern void start_kernel(void);
+
+static int start_kernel_proc(void *unused)
+{
+	int pid;
+
+	block_signals();
+	pid = os_getpid();
+
+	cpu_tasks[0].pid = pid;
+	cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ 	cpu_online_map = cpumask_of_cpu(0);
+#endif
+	if(debug) os_stop_process(pid);
+	start_kernel();
+	return(0);
+}
+
+void set_tracing(void *task, int tracing)
+{
+	((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
+}
+
+int is_tracing(void *t)
+{
+	return (((struct task_struct *) t)->thread.mode.tt.tracing);
+}
+
+int set_user_mode(void *t)
+{
+	struct task_struct *task;
+
+	task = t ? t : current;
+	if(task->thread.mode.tt.tracing) 
+		return(1);
+	task->thread.request.op = OP_TRACE_ON;
+	os_usr1_process(os_getpid());
+	return(0);
+}
+
+void set_init_pid(int pid)
+{
+	int err;
+
+	init_task.thread.mode.tt.extern_pid = pid;
+	err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
+	if(err)
+		panic("Can't create switch pipe for init_task, errno = %d",
+		      -err);
+}
+
+int start_uml_tt(void)
+{
+	void *sp;
+	int pages;
+
+	pages = (1 << CONFIG_KERNEL_STACK_ORDER);
+	sp = (void *) ((unsigned long) init_task.thread_info) +
+		pages * PAGE_SIZE - sizeof(unsigned long);
+	return(tracer(start_kernel_proc, sp));
+}
+
+int external_pid_tt(struct task_struct *task)
+{
+	return(task->thread.mode.tt.extern_pid);
+}
+
+int thread_pid_tt(struct task_struct *task)
+{
+	return(task->thread.mode.tt.extern_pid);
+}
+
+int is_valid_pid(int pid)
+{
+	struct task_struct *task;
+
+        read_lock(&tasklist_lock);
+        for_each_process(task){
+                if(task->thread.mode.tt.extern_pid == pid){
+			read_unlock(&tasklist_lock);
+			return(1);
+                }
+        }
+	read_unlock(&tasklist_lock);
+	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 --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
new file mode 100644
index 0000000..3ad5b77
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -0,0 +1,10 @@
+# 
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = proxy.o ptrace.o sysdep.o wait.o
+
+USER_OBJS := $(obj-y)
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
new file mode 100644
index 0000000..58800c5
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -0,0 +1,377 @@
+/**********************************************************************
+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 <termios.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <asm/unistd.h>
+#include "ptrace_user.h"
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+
+#include "user_util.h"
+#include "user.h"
+#include "os.h"
+#include "tempfile.h"
+
+static int debugger_wait(debugger_state *debugger, int *status, int options,
+			 int (*syscall)(debugger_state *debugger, pid_t child),
+			 int (*normal_return)(debugger_state *debugger, 
+					      pid_t unused),
+			 int (*wait_return)(debugger_state *debugger, 
+					    pid_t unused))
+{
+	if(debugger->real_wait){
+		debugger->handle_trace = normal_return;
+		syscall_continue(debugger->pid);
+		debugger->real_wait = 0;
+		return(1);
+	}
+	debugger->wait_status_ptr = status;
+	debugger->wait_options = options;
+	if((debugger->debugee != NULL) && debugger->debugee->event){
+		syscall_continue(debugger->pid);
+		wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
+			      NULL);
+		(*wait_return)(debugger, -1);
+		return(0);
+	}
+	else if(debugger->wait_options & WNOHANG){
+		syscall_cancel(debugger->pid, 0);
+		debugger->handle_trace = syscall;
+		return(0);
+	}
+	else {
+		syscall_pause(debugger->pid);
+		debugger->handle_trace = wait_return;
+		debugger->waiting = 1;
+	}
+	return(1);
+}
+
+/*
+ * 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;
+		if(!debugger->debugee->in_context) 
+			child = 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);
+
+#ifdef __NR_waitpid
+	case __NR_waitpid:
+#endif
+	case __NR_wait4:
+		if(!debugger_wait(debugger, (int *) arg2, arg3, 
+				  debugger_syscall, debugger_normal_return, 
+				  proxy_wait_return))
+			return(0);
+		break;
+
+	case __NR_kill:
+		if(!debugger->debugee->in_context) 
+			child = debugger->debugee->pid;
+		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(0);
+}
+
+/* Used by the tracing thread */
+static debugger_state parent;
+static int parent_syscall(debugger_state *debugger, int pid);
+
+int init_parent_proxy(int pid)
+{
+	parent = ((debugger_state) { .pid 		= pid,
+				     .wait_options 	= 0,
+				     .wait_status_ptr 	= NULL,
+				     .waiting 		= 0,
+				     .real_wait 	= 0,
+				     .expecting_child 	= 0,
+				     .handle_trace  	= parent_syscall,
+				     .debugee 		= NULL } );
+	return(0);
+}
+
+int parent_normal_return(debugger_state *debugger, pid_t unused)
+{
+	debugger->handle_trace = parent_syscall;
+	syscall_continue(debugger->pid);
+	return(0);
+}
+
+static int parent_syscall(debugger_state *debugger, int pid)
+{
+	long arg1, arg2, arg3, arg4, arg5;
+	int syscall;
+
+	syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
+		
+	if((syscall == __NR_wait4)
+#ifdef __NR_waitpid
+	   || (syscall == __NR_waitpid)
+#endif
+	){
+		debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
+			      parent_normal_return, parent_wait_return);
+	}
+	else ptrace(PTRACE_SYSCALL, pid, 0, 0);
+	return(0);
+}
+
+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);
+}
+
+/* Used by the tracing thread */
+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;
+	debugger.real_wait = 0;
+	debugger.expecting_child = 0;
+
+	debugee.pid = 0;
+	debugee.traced = 0;
+	debugee.stopped = stopped;
+	debugee.event = 0;
+	debugee.zombie = 0;
+	debugee.died = 0;
+	debugee.wait_status = status;
+	debugee.in_context = 1;
+}
+
+int debugger_proxy(int status, int pid)
+{
+	int ret = 0, sig;
+
+	if(WIFSTOPPED(status)){
+		sig = WSTOPSIG(status);
+		if (sig == SIGTRAP)
+			ret = (*debugger.handle_trace)(&debugger, pid);
+						       
+		else if(sig == SIGCHLD){
+			if(debugger.expecting_child){
+				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+				debugger.expecting_child = 0;
+			}
+			else if(debugger.waiting)
+				real_wait_return(&debugger);
+			else {
+				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+				debugger.real_wait = 1;
+			}
+		}
+		else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+	}
+	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;
+		debugger.expecting_child = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else if(WIFEXITED(status) || WIFSIGNALED(status)){
+		debugee.zombie = 1;
+		debugger.expecting_child = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else panic("proxy got unknown status (0x%x) on child (pid %d)", 
+		   status, pid);
+}
+
+void debugger_parent_signal(int status, int pid)
+{
+	int sig;
+
+	if(WIFSTOPPED(status)){
+		sig = WSTOPSIG(status);
+		if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
+		else ptrace(PTRACE_SYSCALL, pid, 0, sig);
+	}
+}
+
+void fake_child_exit(void)
+{
+	int status, pid;
+
+	child_proxy(1, W_EXITCODE(0, 0));
+	while(debugger.waiting == 1){
+		CATCH_EINTR(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);
+	}
+	CATCH_EINTR(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 \n\
+b panic \n\
+b stop \n\
+handle SIGWINCH nostop noprint pass \n\
+";
+
+int start_debugger(char *prog, int startup, int stop, int *fd_out)
+{
+	int slave, child;
+
+	slave = open_gdb_chan();
+	child = fork();
+	if(child == 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, os_getpid()) < 0){
+			printk("start_debugger : tcsetpgrp failed, "
+			       "errno = %d\n", errno);
+#ifdef notdef
+			exit(1);
+#endif
+		}
+		fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
+		if(fd < 0){
+			printk("start_debugger : make_tempfile failed,"
+			       "err = %d\n", -fd);
+			exit(1);
+		}
+		os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+		if(startup){
+			if(stop){
+				os_write_file(fd, "b start_kernel\n",
+				      strlen("b start_kernel\n"));
+			}
+			os_write_file(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 --git a/arch/um/kernel/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
new file mode 100644
index 0000000..5eb0285
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptproxy.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+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;
+	unsigned int real_wait : 1;
+	unsigned int expecting_child : 1;
+	int (*handle_trace) (debugger_state *, pid_t);
+
+	debugee_state *debugee;
+};
+
+struct debugee
+{
+	pid_t pid;
+	int wait_status;
+	unsigned int died : 1;
+	unsigned int event : 1;
+	unsigned int stopped : 1;
+	unsigned int trace_singlestep : 1;
+	unsigned int trace_syscall : 1;
+	unsigned int traced : 1;
+	unsigned int zombie : 1;
+	unsigned int in_context : 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 --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
new file mode 100644
index 0000000..528a5fc
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -0,0 +1,237 @@
+/**********************************************************************
+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/wait.h>
+
+#include "ptproxy.h"
+#include "debug.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+#include "tt.h"
+
+long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
+		  long arg3, long arg4, pid_t child, int *ret)
+{
+	sigset_t relay;
+	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(is_valid_pid(arg2) && (arg2 != child)){
+			debugger->debugee->in_context = 0;
+			kill(arg2, SIGSTOP);
+			debugger->debugee->event = 1;
+			debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
+		}
+		else {
+			debugger->debugee->in_context = 1;
+			if(debugger->debugee->stopped) 
+				child_proxy(child, W_STOPCODE(SIGSTOP));
+			else kill(child, SIGSTOP);
+		}
+
+		return(0);
+
+	case PTRACE_DETACH:
+		if(!debugger->debugee->traced) return(-EPERM);
+		
+		debugger->debugee->traced = 0;
+		debugger->debugee->pid = 0;
+		if(!debugger->debugee->in_context)
+			kill(child, SIGCONT);
+
+		return(0);
+
+	case PTRACE_CONT:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		*ret = PTRACE_CONT;
+		return(ptrace(PTRACE_CONT, child, arg3, arg4));
+
+#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_PEEKUSR:
+		/* 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_POKEUSR:
+		result = ptrace(arg1, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
+		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:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		sigemptyset(&relay);
+		sigaddset(&relay, SIGSEGV);
+		sigaddset(&relay, SIGILL);
+		sigaddset(&relay, SIGBUS);
+		result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
+		if(result == -1) return(-errno);
+		
+		status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
+				       &relay);
+		child_proxy(child, status);
+		return(result);
+
+	case PTRACE_SYSCALL:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		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 --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
new file mode 100644
index 0000000..a5f0e01
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -0,0 +1,70 @@
+/**********************************************************************
+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 <errno.h>
+#include <sys/types.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_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
+	*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
+	*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
+	*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
+	*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
+	return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
+}
+
+void syscall_cancel(pid_t pid, int result)
+{
+	if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
+		   __NR_getpid) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
+	   (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
+	   (ptrace(PTRACE_POKEUSR, 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_POKEUSR, 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_POKEUSR, 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 --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
new file mode 100644
index 0000000..735f488
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.h
@@ -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 --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
new file mode 100644
index 0000000..12f6319
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -0,0 +1,86 @@
+/**********************************************************************
+wait.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+**********************************************************************/
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+#include "user_util.h"
+#include "ptrace_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.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);
+}
+
+int parent_wait_return(struct debugger *debugger, pid_t unused)
+{
+	return(debugger_normal_return(debugger, -1));
+}
+
+int real_wait_return(struct debugger *debugger)
+{
+	unsigned long ip;
+	int pid;
+
+	pid = debugger->pid;
+
+	ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
+	IP_RESTART_SYSCALL(ip);
+
+	if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
+		tracer_panic("real_wait_return : Failed to restart system "
+			     "call, errno = %d\n", errno);
+
+	if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+	   debugger_normal_return(debugger, -1))
+		tracer_panic("real_wait_return : gdb failed to wait, "
+			     "errno = %d\n", 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 --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
new file mode 100644
index 0000000..542e73e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.h
@@ -0,0 +1,15 @@
+/**********************************************************************
+wait.h
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#ifndef __PTPROXY_WAIT_H
+#define __PTPROXY_WAIT_H
+
+extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
+extern int real_wait_return(struct debugger *debugger);
+extern int parent_wait_return(struct debugger *debugger, pid_t unused);
+
+#endif
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
new file mode 100644
index 0000000..2650a62
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -0,0 +1,47 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/types.h"
+#include "linux/utime.h"
+#include "linux/sys.h"
+#include "linux/ptrace.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/stat.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall_tt(void *r)
+{
+	struct pt_regs *regs = r;
+	long res;
+	int syscall;
+
+#ifdef CONFIG_SYSCALL_DEBUG
+	current->thread.nsyscalls++;
+	nsyscalls++;
+#endif
+	syscall = UPT_SYSCALL_NR(&regs->regs);
+
+	if((syscall >= NR_syscalls) || (syscall < 0))
+		res = -ENOSYS;
+	else res = EXECUTE_SYSCALL(syscall, regs);
+
+	return(res);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
new file mode 100644
index 0000000..e4e7e9c
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -0,0 +1,90 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "ptrace_user.h"
+#include "task.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "syscall_user.h"
+#include "tt.h"
+
+
+void syscall_handler_tt(int sig, union uml_pt_regs *regs)
+{
+	void *sc;
+	long result;
+	int syscall;
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+	int index;
+#endif
+
+	syscall = UPT_SYSCALL_NR(regs);
+	sc = UPT_SC(regs);
+	SC_START_SYSCALL(sc);
+
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	index = record_syscall_start(syscall);
+#endif
+	syscall_trace(regs, 0);
+	result = execute_syscall_tt(regs);
+
+	/* regs->sc may have changed while the system call ran (there may
+	 * have been an interrupt or segfault), so it needs to be refreshed.
+	 */
+	UPT_SC(regs) = sc;
+
+	SC_SET_SYSCALL_RETURN(sc, result);
+
+	syscall_trace(regs, 1);
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	record_syscall_end(index, result);
+#endif
+}
+
+void do_sigtrap(void *task)
+{
+	UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
+}
+
+void do_syscall(void *task, int pid, int local_using_sysemu)
+{
+	unsigned long proc_regs[FRAME_SIZE];
+
+	if(ptrace_getregs(pid, proc_regs) < 0)
+		tracer_panic("Couldn't read registers");
+
+	UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
+
+	if(((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");
+
+	/* advanced sysemu mode set syscall number to -1 automatically */
+	if (local_using_sysemu==2)
+		return;
+
+	/* syscall number -1 in sysemu skips syscall restarting in host */
+	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
+		  local_using_sysemu ? -1 : __NR_getpid) < 0)
+		tracer_panic("do_syscall : Nullifying syscall failed, "
+			     "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 --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
new file mode 100644
index 0000000..8565b71
--- /dev/null
+++ b/arch/um/kernel/tt/time.c
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <sys/time.h>
+#include <time_user.h>
+#include "process.h"
+#include "user.h"
+
+void user_time_init_tt(void)
+{
+	if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
new file mode 100644
index 0000000..203216a
--- /dev/null
+++ b/arch/um/kernel/tt/tlb.c
@@ -0,0 +1,149 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "os.h"
+#include "tlb.h"
+
+static void do_ops(int unused, struct host_vm_op *ops, int last)
+{
+	struct host_vm_op *op;
+	int i;
+
+	for(i = 0; i <= last; i++){
+		op = &ops[i];
+		switch(op->type){
+		case MMAP:
+                        os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
+				      op->u.mmap.offset, op->u.mmap.len,
+				      op->u.mmap.r, op->u.mmap.w,
+				      op->u.mmap.x);
+			break;
+		case MUNMAP:
+			os_unmap_memory((void *) op->u.munmap.addr,
+					op->u.munmap.len);
+			break;
+		case MPROTECT:
+			protect_memory(op->u.mprotect.addr, op->u.munmap.len,
+				       op->u.mprotect.r, op->u.mprotect.w,
+				       op->u.mprotect.x, 1);
+			break;
+		default:
+			printk("Unknown op type %d in do_ops\n", op->type);
+			break;
+		}
+	}
+}
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
+		      unsigned long end_addr, int force)
+{
+        if((current->thread.mode.tt.extern_pid != -1) &&
+           (current->thread.mode.tt.extern_pid != os_getpid()))
+                panic("fix_range fixing wrong address space, current = 0x%p",
+                      current);
+
+        fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+}
+
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
+void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
+{
+        if(flush_tlb_kernel_range_common(start, end))
+                atomic_inc(&vmchange_seq);
+}
+
+static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+{
+	int err;
+
+	err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
+	if(err == 0) return;
+	else if((err == -EFAULT) || (err == -ENOMEM)){
+		flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+		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;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pud = pud_offset(pgd, addr);
+		pmd = pmd_offset(pud, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset_kernel(pmd, addr);
+			if(pte_present(*pte)) protect_vm_page(addr, w, 0);
+			addr += PAGE_SIZE;
+		}
+		else addr += PMD_SIZE;
+	}
+}
+
+void flush_tlb_kernel_vm_tt(void)
+{
+        flush_tlb_kernel_range(start_vm, end_vm);
+}
+
+void __flush_tlb_one_tt(unsigned long addr)
+{
+        flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+}
+  
+void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, 
+		     unsigned long end)
+{
+	if(vma->vm_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)){
+		if(flush_tlb_kernel_range_common(start, end))
+			atomic_inc(&vmchange_seq);
+	}
+	else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm_tt(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.mode.tt.vm_seq == seq)
+		return;
+	current->thread.mode.tt.vm_seq = seq;
+	flush_tlb_kernel_range_common(start_vm, end_vm);
+}
+
+void force_flush_all_tt(void)
+{
+	fix_range(current->mm, 0, STACK_TOP, 1);
+	flush_tlb_kernel_range_common(start_vm, end_vm);
+}
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
new file mode 100644
index 0000000..7b5d937
--- /dev/null
+++ b/arch/um/kernel/tt/tracer.c
@@ -0,0 +1,480 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "os.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "process.h"
+#include "kern_util.h"
+#include "chan_user.h"
+#include "ptrace_user.h"
+#include "mode.h"
+#include "tt.h"
+
+static int tracer_winch[2];
+
+int is_tracer_winch(int pid, int fd, void *data)
+{
+	if(pid != tracing_pid)
+		return(0);
+
+	register_winch_irq(tracer_winch[0], fd, -1, data);
+	return(1);
+}
+
+static void tracer_winch_handler(int sig)
+{
+	int n;
+	char c = 1;
+
+	n = os_write_file(tracer_winch[1], &c, sizeof(c));
+	if(n != sizeof(c))
+		printk("tracer_winch_handler - write failed, err = %d\n", -n);
+}
+
+/* Called only by the tracing thread during initialization */
+
+static void setup_tracer_winch(void)
+{
+	int err;
+
+	err = os_pipe(tracer_winch, 1, 1);
+	if(err < 0){
+		printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
+		return;
+	}
+	signal(SIGWINCH, tracer_winch_handler);
+}
+
+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, NULL);
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
+	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);
+	va_end(ap);
+	printf("\n");
+	while(1) pause();
+}
+
+static void tracer_segv(int sig, struct sigcontext sc)
+{
+	printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
+	       SC_FAULT_ADDR(&sc), SC_IP(&sc));
+	while(1)
+		pause();
+}
+
+/* Changed early in boot, and then only read */
+int debug = 0;
+int debug_stop = 1;
+int debug_parent = 0;
+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");
+	os_stop_process(os_getpid());
+	change_sig(SIGWINCH, 0);
+	signal(SIGUSR1, SIG_IGN);
+	change_sig(SIGCHLD, 0);
+	signal(SIGSEGV, (__sighandler_t) sig_handler);
+	set_cmdline("(idle thread)");
+	set_init_pid(os_getpid());
+	proc = arg;
+	return((*proc)(NULL));
+}
+
+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, signal = %d, "
+				     "errno = %d\n", pid, sig, errno);
+		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 + 0x80):
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "PTRACE_SYSCALL pid %d, errno = %d\n",
+				     pid, errno);
+		break;
+	case SIGSTOP:
+		break;
+	default:
+		tracer_panic("sleeping process %d got unexpected "
+			     "signal : %d\n", pid, sig);
+		break;
+	}
+}
+
+/* Accessed only by the tracing thread */
+int debugger_pid = -1;
+int debugger_parent = -1;
+int debugger_fd = -1;
+int gdb_pid = -1;
+
+struct {
+	int pid;
+	int signal;
+	unsigned long addr;
+	struct timeval time;
+} signal_record[1024][32];
+
+int signal_index[32];
+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 tracer(int (*init_proc)(void *), void *sp)
+{
+	void *task = NULL;
+	int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
+	int proc_id = 0, n, err, old_tracing = 0, strace = 0;
+	int local_using_sysemu = 0;
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+	unsigned long eip = 0;
+	int last_index;
+#endif
+	signal(SIGPIPE, SIG_IGN);
+	setup_tracer_winch();
+	tracing_pid = os_getpid();
+	printf("tracing thread pid = %d\n", tracing_pid);
+
+	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
+	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+	if(n < 0){
+		printf("waitpid on idle thread failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
+		printf("Failed to PTRACE_SETOPTIONS for idle thread, 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, (sighandler_t) tracer_segv);
+	signal(SIGUSR1, signal_usr1);
+	if(debug_trace){
+		printf("Tracing thread pausing to be attached\n");
+		stop();
+	}
+	if(debug){
+		if(gdb_pid != -1) 
+			debugger_pid = attach_debugger(pid, gdb_pid, 1);
+		else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
+		if(debug_parent){
+			debugger_parent = os_process_parent(debugger_pid);
+			init_parent_proxy(debugger_parent);
+			err = attach(debugger_parent);
+			if(err){
+				printf("Failed to attach debugger parent %d, "
+				       "errno = %d\n", debugger_parent, -err);
+				debugger_parent = -1;
+			}
+			else {
+				if(ptrace(PTRACE_SYSCALL, debugger_parent, 
+					  0, 0) < 0){
+					printf("Failed to continue debugger "
+					       "parent, errno = %d\n", errno);
+					debugger_parent = -1;
+				}
+			}
+		}
+	}
+	set_cmdline("(tracing thread)");
+	while(1){
+		CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
+		if(pid <= 0){
+			if(errno != ECHILD){
+				printf("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;
+		}
+		else if(pid == debugger_parent){
+			debugger_parent_signal(status, pid);
+			continue;
+		}
+		nsignals++;
+		if(WIFEXITED(status)) ;
+#ifdef notdef
+		{
+			printf("Child %d exited with status %d\n", pid, 
+			       WEXITSTATUS(status));
+		}
+#endif
+		else if(WIFSIGNALED(status)){
+			sig = WTERMSIG(status);
+			if(sig != 9){
+				printf("Child %d exited with signal %d\n", pid,
+				       sig);
+			}
+		}
+		else if(WIFSTOPPED(status)){
+			proc_id = pid_to_processor_id(pid);
+			sig = WSTOPSIG(status);
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+			if(signal_index[proc_id] == 1024){
+				signal_index[proc_id] = 0;
+				last_index = 1023;
+			}
+			else last_index = signal_index[proc_id] - 1;
+			if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
+			    (sig == SIGALRM)) &&
+			   (signal_record[proc_id][last_index].signal == sig)&&
+			   (signal_record[proc_id][last_index].pid == pid))
+				signal_index[proc_id] = last_index;
+			signal_record[proc_id][signal_index[proc_id]].pid = pid;
+			gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
+			eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
+			signal_record[proc_id][signal_index[proc_id]].addr = eip;
+			signal_record[proc_id][signal_index[proc_id]++].signal = sig;
+#endif
+			if(proc_id == -1){
+				sleeping_process_signal(pid, sig);
+				continue;
+			}
+
+			task = cpu_tasks[proc_id].task;
+			tracing = is_tracing(task);
+			old_tracing = tracing;
+
+			/* Assume: no syscall, when coming from user */
+			if ( tracing )
+				do_sigtrap(task);
+
+			switch(sig){
+			case SIGUSR1:
+				sig = 0;
+				op = do_proc_op(task, proc_id);
+				switch(op){
+				/*
+				 * This is called when entering user mode; after
+				 * this, we start intercepting syscalls.
+				 *
+				 * In fact, a process is started in kernel mode,
+				 * so with is_tracing() == 0 (and that is reset
+				 * when executing syscalls, since UML kernel has
+				 * the right to do syscalls);
+				 */
+				case OP_TRACE_ON:
+					arch_leave_kernel(task, pid);
+					tracing = 1;
+					break;
+				case OP_REBOOT:
+				case OP_HALT:
+					unmap_physmem();
+					kmalloc_ok = 0;
+					os_kill_ptraced_process(pid, 0);
+					/* Now let's reap remaining zombies */
+					errno = 0;
+					do {
+						waitpid(-1, &status,
+							WUNTRACED);
+					} while (errno != ECHILD);
+					return(op == OP_REBOOT);
+				case OP_NONE:
+					printf("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 + 0x80):
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status & 0x7fff);
+					continue;
+				}
+				tracing = 0;
+				/* local_using_sysemu has been already set
+				 * below, since if we are here, is_tracing() on
+				 * the traced task was 1, i.e. the process had
+				 * already run through one iteration of the
+				 * loop which executed a OP_TRACE_ON request.*/
+				do_syscall(task, pid, local_using_sysemu);
+				sig = SIGUSR2;
+				break;
+			case SIGTRAP:
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status);
+					continue;
+				}
+				tracing = 0;
+				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 && old_tracing)
+				arch_enter_kernel(task, pid);
+
+			if(!tracing && (debugger_pid != -1) && (sig != 0) &&
+				(sig != SIGALRM) && (sig != SIGVTALRM) &&
+				(sig != SIGSEGV) && (sig != SIGTRAP) &&
+				(sig != SIGUSR2) && (sig != SIGIO) &&
+				(sig != SIGFPE)){
+				child_signal(pid, status);
+				continue;
+			}
+
+			local_using_sysemu = get_using_sysemu();
+
+			if(tracing)
+				cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
+				                                    singlestepping(task));
+			else if((debugger_pid != -1) && strace)
+				cont_type = PTRACE_SYSCALL;
+			else
+				cont_type = PTRACE_CONT;
+
+			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_debug_setup(char *line, int *add)
+{
+	char *next;
+
+	debug = 1;
+	*add = 0;
+	if(*line != '=') return(0);
+	line++;
+
+	while(line != NULL){
+		next = strchr(line, ',');
+		if(next) *next++ = '\0';
+		
+		if(!strcmp(line, "go"))	debug_stop = 0;
+		else if(!strcmp(line, "parent")) debug_parent = 1;
+		else printf("Unknown debug option : '%s'\n", line);
+
+		line = next;
+	}
+	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"
+);
+
+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"
+);
+
+/*
+ * 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 --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
new file mode 100644
index 0000000..92a3820
--- /dev/null
+++ b/arch/um/kernel/tt/trap_user.c
@@ -0,0 +1,60 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include "sysdep/ptrace.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "tt.h"
+
+void sig_handler_common_tt(int sig, void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+	struct tt_regs save_regs, *r;
+	struct signal_info *info;
+	int save_errno = errno, is_user;
+
+	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
+	 * handler.  This can happen in copy_user, and if SEGV is disabled,
+	 * the process will die.
+	 */
+	if(sig == SIGSEGV)
+		change_sig(SIGSEGV, 1);
+
+	r = &TASK_REGS(get_current())->tt;
+	save_regs = *r;
+	is_user = user_context(SC_SP(sc));
+	r->sc = sc;
+	if(sig != SIGUSR2) 
+		r->syscall = -1;
+
+	info = &sig_info[sig];
+	if(!info->is_irq) unblock_signals();
+
+	(*info->handler)(sig, (union uml_pt_regs *) r);
+
+	if(is_user){
+		interrupt_end();
+		block_signals();
+		set_user_mode(NULL);
+	}
+	*r = save_regs;
+	errno = save_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 --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644
index 0000000..a72aa63
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/uaccess.h"
+
+int copy_from_user_tt(void *to, const void __user *from, int n)
+{
+	if(!access_ok_tt(VERIFY_READ, from, n))
+		return(n);
+
+	return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
+				   &current->thread.fault_catcher));
+}
+
+int copy_to_user_tt(void __user *to, const void *from, int n)
+{
+	if(!access_ok_tt(VERIFY_WRITE, to, n))
+		return(n);
+
+	return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+int strncpy_from_user_tt(char *dst, const char __user *src, int count)
+{
+	int n;
+
+	if(!access_ok_tt(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);
+}
+
+int __clear_user_tt(void __user *mem, int len)
+{
+	return(__do_clear_user(mem, len,
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+int clear_user_tt(void __user *mem, int len)
+{
+	if(!access_ok_tt(VERIFY_WRITE, mem, len))
+		return(len);
+
+	return(__do_clear_user(mem, len, &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+int strnlen_user_tt(const void __user *str, int len)
+{
+	return(__do_strnlen_user(str, len,
+				 &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+/*
+ * 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 --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
new file mode 100644
index 0000000..f014755
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -0,0 +1,98 @@
+/* 
+ * 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"
+#include "uml_uaccess.h"
+#include "task.h"
+#include "kern_util.h"
+
+int __do_copy_from_user(void *to, const void *from, int n,
+			void **fault_addr, void **fault_catcher)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) from));
+}
+
+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)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+			       __do_strncpy, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	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)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+			       __do_clear, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	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)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	int ret;
+	unsigned long *faddrp = (unsigned long *)fault_addr;
+	sigjmp_buf jbuf;
+
+	*fault_catcher = &jbuf;
+	if(sigsetjmp(jbuf, 1) == 0)
+		ret = strlen(str) + 1;
+	else ret = *faddrp - (unsigned long) str;
+
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+
+	TASK_REGS(get_current())->tt = save;
+	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 --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
new file mode 100644
index 0000000..3f7aecd
--- /dev/null
+++ b/arch/um/kernel/tt/unmap.c
@@ -0,0 +1,31 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <sys/mman.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 --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
new file mode 100644
index 0000000..9ada656
--- /dev/null
+++ b/arch/um/kernel/tty_log.c
@@ -0,0 +1,230 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and 
+ * geoffrey hing <ghing@net.ohio-state.edu>
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "init.h"
+#include "user.h"
+#include "kern_util.h"
+#include "os.h"
+
+#define TTY_LOG_DIR "./"
+
+/* Set early in boot and then unchanged */
+static char *tty_log_dir = TTY_LOG_DIR;
+static int tty_log_fd = -1;
+
+#define TTY_LOG_OPEN 1
+#define TTY_LOG_CLOSE 2
+#define TTY_LOG_WRITE 3
+#define TTY_LOG_EXEC 4
+
+#define TTY_READ 1
+#define TTY_WRITE 2
+
+struct tty_log_buf {
+	int what;
+	unsigned long tty;
+	int len;
+	int direction;
+	unsigned long sec;
+	unsigned long usec;
+};
+
+int open_tty_log(void *tty, void *current_tty)
+{
+	struct timeval tv;
+	struct tty_log_buf data;
+	char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
+	int fd;
+
+	gettimeofday(&tv, NULL);
+	if(tty_log_fd != -1){
+		data = ((struct tty_log_buf) { .what 	= TTY_LOG_OPEN,
+					       .tty  = (unsigned long) tty,
+					       .len  = sizeof(current_tty),
+					       .direction = 0,
+					       .sec = tv.tv_sec,
+					       .usec = tv.tv_usec } );
+		os_write_file(tty_log_fd, &data, sizeof(data));
+		os_write_file(tty_log_fd, &current_tty, data.len);
+		return(tty_log_fd);
+	}
+
+	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 
+ 		(unsigned int) tv.tv_usec);
+
+	fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
+			  0644);
+	if(fd < 0){
+		printk("open_tty_log : couldn't open '%s', errno = %d\n",
+		       buf, -fd);
+	}
+	return(fd);
+}
+
+void close_tty_log(int fd, void *tty)
+{
+	struct tty_log_buf data;
+	struct timeval tv;
+
+	if(tty_log_fd != -1){
+		gettimeofday(&tv, NULL);
+		data = ((struct tty_log_buf) { .what 	= TTY_LOG_CLOSE,
+					       .tty  = (unsigned long) tty,
+					       .len  = 0,
+					       .direction = 0,
+					       .sec = tv.tv_sec,
+					       .usec = tv.tv_usec } );
+		os_write_file(tty_log_fd, &data, sizeof(data));
+		return;
+	}
+	os_close_file(fd);
+}
+
+static int log_chunk(int fd, const char *buf, int len)
+{
+	int total = 0, try, missed, n;
+	char chunk[64];
+
+	while(len > 0){
+		try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
+		missed = copy_from_user_proc(chunk, (char *) buf, try);
+		try -= missed;
+		n = os_write_file(fd, chunk, try);
+		if(n != try) {
+			if(n < 0)
+				return(n);
+			return(-EIO);
+		}
+		if(missed != 0)
+			return(-EFAULT);
+
+		len -= try;
+		total += try;
+		buf += try;
+	}
+
+	return(total);
+}
+
+int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
+{
+	struct timeval tv;
+	struct tty_log_buf data;
+	int direction;
+
+	if(fd == tty_log_fd){
+		gettimeofday(&tv, NULL);
+		direction = is_read ? TTY_READ : TTY_WRITE;
+		data = ((struct tty_log_buf) { .what 	= TTY_LOG_WRITE,
+					       .tty  = (unsigned long) tty,
+					       .len  = len,
+					       .direction = direction,
+					       .sec = tv.tv_sec,
+					       .usec = tv.tv_usec } );
+		os_write_file(tty_log_fd, &data, sizeof(data));
+	}
+
+	return(log_chunk(fd, buf, len));
+}
+
+void log_exec(char **argv, void *tty)
+{
+	struct timeval tv;
+	struct tty_log_buf data;
+	char **ptr,*arg;
+	int len;
+
+	if(tty_log_fd == -1) return;
+
+	gettimeofday(&tv, NULL);
+
+	len = 0;
+	for(ptr = argv; ; ptr++){
+		if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
+			return;
+		if(arg == NULL) break;
+		len += strlen_user_proc(arg);
+	}
+
+	data = ((struct tty_log_buf) { .what 	= TTY_LOG_EXEC,
+				       .tty  = (unsigned long) tty,
+				       .len  = len,
+				       .direction = 0,
+				       .sec = tv.tv_sec,
+				       .usec = tv.tv_usec } );
+	os_write_file(tty_log_fd, &data, sizeof(data));
+
+	for(ptr = argv; ; ptr++){
+		if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
+			return;
+		if(arg == NULL) break;
+		log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
+	}
+}
+
+extern void register_tty_logger(int (*opener)(void *, void *),
+				int (*writer)(int, const char *, int,
+					      void *, int),
+				void (*closer)(int, void *));
+
+static int register_logger(void)
+{
+	register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
+	return(0);
+}
+
+__uml_initcall(register_logger);
+
+static int __init set_tty_log_dir(char *name, int *add)
+{
+	tty_log_dir = name;
+	return 0;
+}
+
+__uml_setup("tty_log_dir=", set_tty_log_dir,
+"tty_log_dir=<directory>\n"
+"    This is used to specify the directory where the logs of all pty\n"
+"    data from this UML machine will be written.\n\n"
+);
+
+static int __init set_tty_log_fd(char *name, int *add)
+{
+	char *end;
+
+	tty_log_fd = strtoul(name, &end, 0);
+	if((*end != '\0') || (end == name)){
+		printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
+		tty_log_fd = -1;
+	}
+
+	*add = 0;
+	return 0;
+}
+
+__uml_setup("tty_log_fd=", set_tty_log_fd,
+"tty_log_fd=<fd>\n"
+"    This is used to specify a preconfigured file descriptor to which all\n"
+"    tty data will be written.  Preconfigure the descriptor with something\n"
+"    like '10>tty_log tty_log_fd=10'.\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 --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c
new file mode 100644
index 0000000..d035257
--- /dev/null
+++ b/arch/um/kernel/uaccess_user.c
@@ -0,0 +1,64 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <setjmp.h>
+#include <string.h>
+
+/* These are here rather than tt/uaccess.c because skas mode needs them in
+ * order to do SIGBUS recovery when a tmpfs mount runs out of room.
+ */
+
+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;
+
+	sigjmp_buf jbuf;
+	*fault_catcher = &jbuf;
+	if(sigsetjmp(jbuf, 1) == 0){
+		(*op)(to, from, n);
+		ret = 0;
+		*faulted_out = 0;
+	} 
+	else {
+		ret = *faddrp;
+		*faulted_out = 1;
+	}
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+	return ret;
+}
+
+void __do_copy(void *to, const void *from, int n)
+{
+	memcpy(to, from, n);
+}	
+
+
+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));
+}
+
+/*
+ * 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 --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
new file mode 100644
index 0000000..5c49d88
--- /dev/null
+++ b/arch/um/kernel/um_arch.c
@@ -0,0 +1,467 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/notifier.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/sysrq.h"
+#include "linux/seq_file.h"
+#include "linux/delay.h"
+#include "linux/module.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/ptrace.h"
+#include "asm/elf.h"
+#include "asm/user.h"
+#include "ubd_user.h"
+#include "asm/current.h"
+#include "asm/setup.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mem_user.h"
+#include "mem.h"
+#include "umid.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+#include "choose-mode.h"
+#include "mode_kern.h"
+#include "mode.h"
+
+#define DEFAULT_COMMAND_LINE "root=98:0"
+
+/* Changed in linux_main and setup_arch, which run before SMP is started */
+char command_line[COMMAND_LINE_SIZE] = { 0 };
+
+void add_arg(char *arg)
+{
+	if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
+		printf("add_arg: Too many command line arguments!\n");
+		exit(1);
+	}
+	if(strlen(command_line) > 0)
+		strcat(command_line, " ");
+	strcat(command_line, arg);
+}
+
+struct cpuinfo_um boot_cpu_data = { 
+	.loops_per_jiffy	= 0,
+	.ipi_pipe		= { -1, -1 }
+};
+
+unsigned long thread_saved_pc(struct task_struct *task)
+{
+	return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+					      task)));
+}
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	int index = 0;
+
+#ifdef CONFIG_SMP
+	index = (struct cpuinfo_um *) v - cpu_data;
+	if (!cpu_online(index))
+		return 0;
+#endif
+
+	seq_printf(m, "processor\t: %d\n", index);
+	seq_printf(m, "vendor_id\t: User Mode Linux\n");
+	seq_printf(m, "model name\t: UML\n");
+	seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
+	seq_printf(m, "host\t\t: %s\n", host_info);
+	seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+		   loops_per_jiffy/(500000/HZ),
+		   (loops_per_jiffy/(5000/HZ)) % 100);
+
+	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);
+}
+
+/* Set in linux_main */
+unsigned long host_task_size;
+unsigned long task_size;
+
+unsigned long uml_start;
+
+/* Set in early boot */
+unsigned long uml_physmem;
+unsigned long uml_reserved;
+unsigned long start_vm;
+unsigned long end_vm;
+int ncpus = 1;
+
+#ifdef CONFIG_MODE_TT
+/* Pointer set in linux_main, the array itself is private to each thread,
+ * and changed at address space creation time so this poses no concurrency
+ * problems.
+ */
+static char *argv1_begin = NULL;
+static char *argv1_end = NULL;
+#endif
+
+/* Set in early boot */
+static int have_root __initdata = 0;
+long physmem_size = 32 * 1024 * 1024;
+
+void set_cmdline(char *cmd)
+{
+#ifdef CONFIG_MODE_TT
+	char *umid, *ptr;
+
+	if(CHOOSE_MODE(honeypot, 0)) return;
+
+	umid = get_umid(1);
+	if(umid != NULL){
+		snprintf(argv1_begin, 
+			 (argv1_end - argv1_begin) * sizeof(*ptr), 
+			 "(%s) ", umid);
+		ptr = &argv1_begin[strlen(argv1_begin)];
+	}
+	else ptr = argv1_begin;
+
+	snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
+	memset(argv1_begin + strlen(argv1_begin), '\0', 
+	       argv1_end - argv1_begin - strlen(argv1_begin));
+#endif
+}
+
+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);
+
+	return 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)) {
+               printf("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\n" 
+);
+#endif
+
+static int force_tt = 0;
+
+#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
+#define DEFAULT_TT 0
+
+static int __init mode_tt_setup(char *line, int *add)
+{
+	force_tt = 1;
+	return(0);
+}
+
+#else
+#ifdef CONFIG_MODE_SKAS
+
+#define DEFAULT_TT 0
+
+static int __init mode_tt_setup(char *line, int *add)
+{
+	printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
+	return(0);
+}
+
+#else
+#ifdef CONFIG_MODE_TT
+
+#define DEFAULT_TT 1
+
+static int __init mode_tt_setup(char *line, int *add)
+{
+	printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
+	return(0);
+}
+
+#else
+
+#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
+
+#endif
+#endif
+#endif
+
+__uml_setup("mode=tt", mode_tt_setup,
+"mode=tt\n"
+"    When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
+"    forces UML to run in tt (tracing thread) mode.  It is not the default\n"
+"    because it's slower and less secure than skas mode.\n\n"
+);
+
+int mode_tt = DEFAULT_TT;
+
+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);
+
+	return 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;
+}
+
+/* Set during early boot */
+unsigned long brk_start;
+unsigned long end_iomem;
+EXPORT_SYMBOL(end_iomem);
+
+#define MIN_VMALLOC (32 * 1024 * 1024)
+
+int linux_main(int argc, char **argv)
+{
+	unsigned long avail, diff;
+	unsigned long virtmem_size, max_physmem;
+	unsigned int i, add;
+
+	for (i = 1; i < argc; i++){
+		if((i == 1) && (argv[i][0] == ' ')) continue;
+		add = 1;
+		uml_checksetup(argv[i], &add);
+		if (add)
+			add_arg(argv[i]);
+	}
+	if(have_root == 0)
+		add_arg(DEFAULT_COMMAND_LINE);
+
+	mode_tt = force_tt ? 1 : !can_do_skas();
+#ifndef CONFIG_MODE_TT
+	if (mode_tt) {
+		/*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
+		 * can_do_skas() returned 0, and the message is correct. */
+		printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
+		exit(1);
+	}
+#endif
+	uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
+				     &host_task_size, &task_size);
+
+	/* Need to check this early because mmapping happens before the
+	 * kernel is running.
+	 */
+	check_tmpexec();
+
+	brk_start = (unsigned long) sbrk(0);
+	CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
+	/* Increase physical memory size for exec-shield users
+	so they actually get what they asked for. This should
+	add zero for non-exec shield users */
+
+	diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
+	if(diff > 1024 * 1024){
+		printf("Adding %ld bytes to physical memory to account for "
+		       "exec-shield gap\n", diff);
+		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
+	}
+
+	uml_physmem = uml_start;
+
+	/* Reserve up to 4M after the current brk */
+	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
+
+	setup_machinename(system_utsname.machine);
+
+#ifdef CONFIG_MODE_TT
+	argv1_begin = argv[1];
+	argv1_end = &argv[1][strlen(argv[1])];
+#endif
+  
+	highmem = 0;
+	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
+	max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+
+	/* Zones have to begin on a 1 << MAX_ORDER page boundary,
+	 * so this makes sure that's true for highmem
+	 */
+	max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
+	if(physmem_size + iomem_size > max_physmem){
+		highmem = physmem_size + iomem_size - max_physmem;
+		physmem_size -= highmem;
+#ifndef CONFIG_HIGHMEM
+		highmem = 0;
+		printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
+		       "to %ld bytes\n", physmem_size);
+#endif
+	}
+
+	high_physmem = uml_physmem + physmem_size;
+	end_iomem = high_physmem + iomem_size;
+	high_memory = (void *) end_iomem;
+
+	start_vm = VMALLOC_START;
+
+	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
+	if(init_maps(physmem_size, iomem_size, highmem)){
+		printf("Failed to allocate mem_map for %ld bytes of physical "
+		       "memory and %ld bytes of highmem\n", physmem_size,
+		       highmem);
+		exit(1);
+	}
+
+	virtmem_size = physmem_size;
+	avail = get_kmem_end() - start_vm;
+	if(physmem_size > avail) virtmem_size = avail;
+	end_vm = start_vm + virtmem_size;
+
+	if(virtmem_size < physmem_size)
+		printf("Kernel virtual memory size shrunk to %ld bytes\n",
+		       virtmem_size);
+
+  	uml_postsetup();
+
+	task_protections((unsigned long) &init_thread_info);
+	os_flush_stdout();
+
+	return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+}
+
+extern int uml_exitcode;
+
+static int panic_exit(struct notifier_block *self, unsigned long unused1,
+		      void *unused2)
+{
+	bust_spinlocks(1);
+	show_regs(&(current->thread.regs));
+	bust_spinlocks(0);
+	uml_exitcode = 1;
+	machine_halt();
+	return(0);
+}
+
+static struct notifier_block panic_exit_notifier = {
+	.notifier_call 		= panic_exit,
+	.next 			= NULL,
+	.priority 		= 0
+};
+
+void __init setup_arch(char **cmdline_p)
+{
+	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
+	paging_init();
+ 	strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+ 	*cmdline_p = command_line;
+	setup_hostinfo();
+}
+
+void __init check_bugs(void)
+{
+	arch_check_bugs();
+	check_ptrace();
+	check_sigio();
+	check_devanon();
+}
+
+void apply_alternatives(void *start, void *end)
+{
+}
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
new file mode 100644
index 0000000..186c288
--- /dev/null
+++ b/arch/um/kernel/umid.c
@@ -0,0 +1,325 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.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"
+#include "os.h"
+#include "user_util.h"
+#include "choose-mode.h"
+
+#define UMID_LEN 64
+#define UML_DIR "~/.uml/"
+
+/* Changed by set_umid and make_umid, which are run early in boot */
+static char umid[UMID_LEN] = { 0 };
+
+/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
+static char *uml_dir = UML_DIR;
+
+/* Changed by set_umid */
+static int umid_is_random = 1;
+static int umid_inited = 0;
+
+static int make_umid(int (*printer)(const char *fmt, ...));
+
+static int __init set_umid(char *name, int is_random,
+			   int (*printer)(const char *fmt, ...))
+{
+	if(umid_inited){
+		(*printer)("Unique machine name can't be set twice\n");
+		return(-1);
+	}
+
+	if(strlen(name) > UMID_LEN - 1)
+		(*printer)("Unique machine name is being truncated to %d "
+			   "characters\n", UMID_LEN);
+	strlcpy(umid, name, sizeof(umid));
+
+	umid_is_random = is_random;
+	umid_inited = 1;
+	return 0;
+}
+
+static int __init set_umid_arg(char *name, int *add)
+{
+	*add = 0;
+	return(set_umid(name, 0, printf));
+}
+
+__uml_setup("umid=", set_umid_arg,
+"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(printk)) 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, n;
+
+	if(umid_file_name("pid", file, sizeof(file))) return 0;
+
+	fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
+			  0644);
+	if(fd < 0){
+		printf("Open of machine pid file \"%s\" failed: %s\n",
+		       file, strerror(-fd));
+		return 0;
+	}
+
+	sprintf(pid, "%d\n", os_getpid());
+	n = os_write_file(fd, pid, strlen(pid));
+	if(n != strlen(pid))
+		printf("Write of pid file failed - err = %d\n", -n);
+	os_close_file(fd);
+	return 0;
+}
+
+static int actually_do_remove(char *dir)
+{
+	DIR *directory;
+	struct dirent *ent;
+	int len;
+	char file[256];
+
+	directory = opendir(dir);
+	if(directory == 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(int only_if_set)
+{
+	if(only_if_set && umid_is_random) return(NULL);
+	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, n;
+
+	sprintf(file, "%s/pid", dir);
+	dead = 0;
+	fd = os_open_file(file, of_read(OPENFLAGS()), 0);
+	if(fd < 0){
+		if(fd != -ENOENT){
+			printk("not_dead_yet : couldn't open pid file '%s', "
+			       "err = %d\n", file, -fd);
+			return(1);
+		}
+		dead = 1;
+	}
+	if(fd > 0){
+		n = os_read_file(fd, pid, sizeof(pid));
+		if(n < 0){
+			printk("not_dead_yet : couldn't read pid file '%s', "
+			       "err = %d\n", file, -n);
+			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 == CHOOSE_MODE(tracing_pid, os_getpid())))
+			dead = 1;
+	}
+	if(!dead) return(1);
+	return(actually_do_remove(dir));
+}
+
+static int __init set_uml_dir(char *name, int *add)
+{
+	if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+		uml_dir = malloc(strlen(name) + 2);
+		if(uml_dir == NULL){
+			printf("Failed to malloc uml_dir - error = %d\n",
+			       errno);
+			uml_dir = name;
+			/* Return 0 here because do_initcalls doesn't look at
+			 * the return value.
+			 */
+			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){
+			printf("make_uml_dir : no value in environment for "
+			       "$HOME\n");
+			exit(1);
+		}
+		strlcpy(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';
+	}
+
+	uml_dir = malloc(strlen(dir) + 1);
+	if(uml_dir == 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)){
+	        printf("Failed to mkdir %s: %s\n", uml_dir, strerror(errno));
+		return(-1);
+	}
+	return 0;
+}
+
+static int __init make_umid(int (*printer)(const char *fmt, ...))
+{
+	int fd, err;
+	char tmp[strlen(uml_dir) + UMID_LEN + 1];
+
+	strlcpy(tmp, uml_dir, sizeof(tmp));
+
+	if(!umid_inited){
+		strcat(tmp, "XXXXXX");
+		fd = mkstemp(tmp);
+		if(fd < 0){
+			(*printer)("make_umid - mkstemp(%s) failed: %s\n",
+				   tmp,strerror(errno));
+			return(1);
+		}
+
+		os_close_file(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);
+		set_umid(&tmp[strlen(uml_dir)], 1, printer);
+	}
+	
+	sprintf(tmp, "%s%s", uml_dir, umid);
+
+	err = mkdir(tmp, 0777);
+	if(err < 0){
+		if(errno == EEXIST){
+			if(not_dead_yet(tmp)){
+				(*printer)("umid '%s' is in use\n", umid);
+				return(-1);
+			}
+			err = mkdir(tmp, 0777);
+		}
+	}
+	if(err < 0){
+		(*printer)("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"
+);
+
+static int __init make_umid_setup(void)
+{
+	/* one function with the ordering we need ... */
+	make_uml_dir();
+	make_umid(printf);
+	return create_pid_file();
+}
+__uml_postsetup(make_umid_setup);
+
+/*
+ * 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 --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
new file mode 100644
index 0000000..76eadb3
--- /dev/null
+++ b/arch/um/kernel/uml.lds.S
@@ -0,0 +1,106 @@
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  /*This must contain the right address - not quite the default ELF one.*/
+  PROVIDE (__executable_start = START);
+  . = START + SIZEOF_HEADERS;
+
+  /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
+   * is remapped.*/
+  __binary_start = .;
+#ifdef MODE_TT
+  .thread_private : {
+    __start_thread_private = .;
+    errno = .;
+    . += 4;
+    arch/um/kernel/tt/unmap_fin.o (.data)
+    __end_thread_private = .;
+  }
+  . = ALIGN(4096);
+  .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
+
+  /* We want it only if we are in MODE_TT. In both cases, however, when MODE_TT
+   * is off the resulting binary segfaults.*/
+
+  . = ALIGN(4096);		/* Init code and data */
+#endif
+
+  _stext = .;
+  __init_begin = .;
+  .init.text : {
+	_sinittext = .;
+	*(.init.text)
+	_einittext = .;
+  }
+  . = ALIGN(4096);
+  .text      :
+  {
+    *(.text)
+    SCHED_TEXT
+    LOCK_TEXT
+    *(.fixup)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  }
+
+  #include "asm/common.lds.S"
+
+  init.data : { *(init.data) }
+  .data    :
+  {
+    . = ALIGN(KERNEL_STACK_SIZE);		/* 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 --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
new file mode 100644
index 0000000..954ff67
--- /dev/null
+++ b/arch/um/kernel/user_util.c
@@ -0,0 +1,173 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include <sys/time.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"
+#include "helper.h"
+#include "ptrace_user.h"
+#include "uml-config.h"
+
+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, pages;
+
+#ifdef notdef
+	if(mprotect((void *) stack, page_size(), prot) < 0)
+		panic("protecting guard page failed, errno = %d", errno);
+#endif
+	pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
+	prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	if(mprotect((void *) stack, pages * page_size(), prot) < 0)
+		panic("protecting stack failed, errno = %d", errno);
+}
+
+int wait_for_stop(int pid, int sig, int cont_type, void *relay)
+{
+	sigset_t *relay_signals = relay;
+	int status, ret;
+
+	while(1){
+		CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
+		if((ret < 0) ||
+		   !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
+			if(ret < 0){
+				printk("wait failed, errno = %d\n",
+				       errno);
+			}
+			else if(WIFEXITED(status)) 
+				printk("process %d exited with status %d\n",
+				       pid, WEXITSTATUS(status));
+			else if(WIFSIGNALED(status))
+				printk("process %d exited with signal %d\n",
+				       pid, 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 if((relay_signals != NULL) &&
+				sigismember(relay_signals, WSTOPSIG(status))){
+				ptrace(cont_type, pid, 0, WSTOPSIG(status));
+				continue;
+			}
+			else printk("process %d stopped with signal %d\n",
+				    pid, WSTOPSIG(status));
+			panic("wait_for_stop failed to wait for %d to stop "
+			      "with %d\n", pid, sig);
+		}
+		return(status);
+	}
+}
+
+int raw(int fd)
+{
+	struct termios tt;
+	int err;
+
+	CATCH_EINTR(err = tcgetattr(fd, &tt));
+	if (err < 0) {
+			printk("tcgetattr failed, errno = %d\n", errno);
+		return(-errno);
+	}
+
+	cfmakeraw(&tt);
+
+ 	CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
+	if (err < 0) {
+			printk("tcsetattr failed, errno = %d\n", errno);
+		return(-errno);
+	}
+
+	/* XXX tcsetattr could have applied only some changes
+	 * (and cfmakeraw() is a set of changes) */
+	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);
+}
+
+int setjmp_wrapper(void (*proc)(void *, void *), ...)
+{
+        va_list args;
+	sigjmp_buf buf;
+	int n;
+
+	n = sigsetjmp(buf, 1);
+	if(n == 0){
+		va_start(args, proc);
+		(*proc)(&buf, &args);
+	}
+	va_end(args);
+	return(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:
+ */