memory.  All the memory that can't be mapped directly will be treated
        as high memory.
 
+config STUB_CODE
+       hex
+       default 0xbfffe000
+
+config STUB_DATA
+       hex
+       default 0xbffff000
+
+config STUB_START
+       hex
+       default STUB_CODE
+
 config ARCH_HAS_SC_SIGNALS
        bool
        default y
 
        bool
        default y
 
+config STUB_CODE
+       hex
+       default 0x7fbfffe000
+
+config STUB_DATA
+       hex
+       default 0x7fbffff000
+
+config STUB_START
+       hex
+       default STUB_CODE
+
 config ARCH_HAS_SC_SIGNALS
        bool
        default n
 
   endif
 endif
 
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
 ARCH_USER_CFLAGS :=
 
 ifneq ($(CONFIG_GPROF),y)
 
 SUBARCH_LIBS := arch/um/sys-x86_64/
 START := 0x60000000
 
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
 ARCH_USER_CFLAGS := -D__x86_64__
 
 ELF_ARCH := i386:x86-64
 
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
-# Sun Apr 24 19:46:10 2005
+# Linux kernel version: 2.6.12-rc6-mm1
+# Tue Jun 14 18:22:21 2005
 #
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_UML=y
 #
 # UML-specific options
 #
-CONFIG_MODE_TT=y
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
 CONFIG_MODE_SKAS=y
 CONFIG_UML_X86=y
 # CONFIG_64BIT is not set
 CONFIG_TOP_ADDR=0xc0000000
 # CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0xbfffe000
+CONFIG_STUB_DATA=0xbffff000
+CONFIG_STUB_START=0xbfffe000
 CONFIG_ARCH_HAS_SC_SIGNALS=y
 CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
-CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LD_SCRIPT_DYN=y
 CONFIG_NET=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
-CONFIG_HOSTFS=y
+# CONFIG_HOSTFS is not set
 CONFIG_MCONSOLE=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_HOST_2G_2G is not set
-# CONFIG_SMP is not set
 CONFIG_NEST_LEVEL=0
 CONFIG_KERNEL_HALF_GIGS=1
 # CONFIG_HIGHMEM is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
 CONFIG_SOUND=m
 CONFIG_HOSTAUDIO=m
 CONFIG_UML_RANDOM=y
+# CONFIG_MMAPPER is not set
 
 #
 # Block devices
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
 # CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 CONFIG_SLIP=m
 # CONFIG_SLIP_COMPRESSED is not set
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
+# CONFIG_REISER4_FS is not set
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 CONFIG_QUOTA=y
 # CONFIG_QFMT_V1 is not set
 # CONFIG_QFMT_V2 is not set
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 # CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
 # CONFIG_GCOV is not set
 # CONFIG_SYSCALL_DEBUG is not set
 
 extern int is_remapped(void *virt);
 extern int physmem_remove_mapping(void *virt);
 extern void physmem_forget_descriptor(int fd);
+extern unsigned long to_phys(void *virt);
 
 #endif
 
 
 extern void save_registers(int pid, union uml_pt_regs *regs);
 extern void restore_registers(int pid, union uml_pt_regs *regs);
 extern void init_registers(int pid);
+extern void get_safe_registers(unsigned long * regs);
 
 #endif
 
 
 #define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
 #define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
 #define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
 
 #define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
 
+#define REGS_SYSCALL_NR EAX /* This is used before a system call */
+#define REGS_SYSCALL_ARG1 EBX
+#define REGS_SYSCALL_ARG2 ECX
+#define REGS_SYSCALL_ARG3 EDX
+#define REGS_SYSCALL_ARG4 ESI
+#define REGS_SYSCALL_ARG5 EDI
+#define REGS_SYSCALL_ARG6 EBP
+
+#define REGS_IP_INDEX EIP
+#define REGS_SP_INDEX UESP
+
 #define PT_IP_OFFSET PT_OFFSET(EIP)
 #define PT_IP(regs) ((regs)[EIP])
+#define PT_SP_OFFSET PT_OFFSET(UESP)
 #define PT_SP(regs) ((regs)[UESP])
 
 #ifndef FRAME_SIZE
 
--- /dev/null
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+extern void stub_segv_handler(int sig);
+
+#define STUB_SYSCALL_RET EAX
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+#endif
 
 #define PTRACE_OLDSETOPTIONS 21
 #endif
 
+/* These are before the system call, so the the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+#define REGS_SYSCALL_NR PT_INDEX(RAX)
+#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
+#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
+#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
+#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
+#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
+#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
+
+#define REGS_IP_INDEX PT_INDEX(RIP)
+#define REGS_SP_INDEX PT_INDEX(RSP)
+
 #endif
 
 /*
 
--- /dev/null
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <sysdep/ptrace_user.h>
+
+extern void stub_segv_handler(int sig);
+
+#define STUB_SYSCALL_RET PT_INDEX(RAX)
+#define STUB_MMAP_NR __NR_mmap
+#define MMAP_OFFSET(o) (o)
+
+#endif
 
 extern void mprotect_kernel_vm(int w);
 extern void force_flush_all(void);
 extern 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));
+                             unsigned long end_addr, int force,
+                             void (*do_ops)(union mm_context *,
+                                            struct host_vm_op *, int));
 extern int flush_tlb_kernel_range_common(unsigned long start,
                                         unsigned long end);
 
 extern 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));
+                    int last_filled, union mm_context *mmu,
+                    void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                   int));
 extern 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));
+                      union mm_context *mmu,
+                      void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                     int));
 extern 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));
+                        int last_filled, union mm_context *mmu,
+                        void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                       int));
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
 
     *(.stub .text.* .gnu.linkonce.t.*)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
+
+    . = ALIGN(4096);
+    __syscall_stub_start = .;
+    *(.__syscall_stub*)
+    __syscall_stub_end = .;
+    . = ALIGN(4096);
   } =0x90909090
   .fini           : {
     KEEP (*(.fini))
 
 
 #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 
+extern int __syscall_stub_start, __binary_start;
+
 void setup_physmem(unsigned long start, unsigned long reserve_end,
                   unsigned long len, unsigned long highmem)
 {
                exit(1);
        }
 
+       /* Special kludge - This page will be mapped in to userspace processes
+        * from physmem_fd, so it needs to be written out there.
+        */
+       os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
+       os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+
        bootmap_size = init_bootmem(pfn, pfn + delta);
        free_bootmem(__pa(reserve_end) + bootmap_size,
                     len - bootmap_size - reserve);
 
 #include "uml-config.h"
 #include "choose-mode.h"
 #include "mode.h"
+#include "tempfile.h"
 #ifdef UML_CONFIG_MODE_SKAS
 #include "skas.h"
 #include "skas_ptrace.h"
                kill(target, SIGIO);
 }
 
+int ptrace_faultinfo = 0;
+int proc_mm = 1;
+
+extern void *__syscall_stub_start, __syscall_stub_end;
+
 #ifdef UML_CONFIG_MODE_SKAS
-static inline int check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_support(void)
 {
        struct ptrace_faultinfo fi;
-       int pid, n, ret = 1;
+       int pid, n;
 
        printf("Checking for the skas3 patch in the host...");
        pid = start_ptraced_child();
                else {
                        perror("not found");
                }
-               ret = 0;
-       } else {
+       }
+       else {
+               ptrace_faultinfo = 1;
                printf("found\n");
        }
 
        init_registers(pid);
        stop_ptraced_child(pid, 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) {
+               proc_mm = 0;
                printf("not found\n");
-               ret = 0;
                goto out;
-       } else {
+       }
+       else {
                printf("found\n");
        }
 
-       ret = check_skas3_ptrace_support();
 out:
-       return ret;
+       check_skas3_ptrace_support();
+       return 1;
 }
 #else
 int can_do_skas(void)
 
 void flush_thread_skas(void)
 {
        force_flush_all();
-       switch_mm_skas(current->mm->context.skas.mm_fd);
+        switch_mm_skas(¤t->mm->context.skas.id);
 }
 
 void start_thread_skas(struct pt_regs *regs, unsigned long eip, 
 
--- /dev/null
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MM_ID_H
+#define __MM_ID_H
+
+struct mm_id {
+       union {
+               int mm_fd;
+               int pid;
+       } u;
+       unsigned long stack;
+};
+
+#endif
 
 #ifndef __SKAS_MMU_H
 #define __SKAS_MMU_H
 
+#include "mm_id.h"
+
 struct mmu_context_skas {
-       int mm_fd;
+       struct mm_id id;
+        unsigned long last_page_table;
 };
 
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
 #endif
 
 /*
 
 #ifndef __SKAS_H
 #define __SKAS_H
 
+#include "mm_id.h"
 #include "sysdep/ptrace.h"
 
 extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo;
 
 extern void switch_threads(void *me, void *next);
 extern void thread_wait(void *sw, void *fb);
 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 int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+               int r, int w, int x, int phys_fd, unsigned long long offset);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+                  unsigned long len, int r, int w, int x);
 extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
 extern int new_mm(int from);
-extern void start_userspace(int cpu);
+extern int start_userspace(unsigned long stub_stack);
 extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
 extern long execute_syscall_skas(void *r);
+extern unsigned long current_stub_stack(void);
 
 #endif
 
 
 
 #include "linux/config.h"
 #include "linux/mm.h"
+#include "asm/pgtable.h"
 #include "mem_user.h"
+#include "skas.h"
 
 unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 
                                  unsigned long *task_size_out)
        *task_size_out = CONFIG_HOST_TASK_SIZE;
 #else
        *host_size_out = top;
-       *task_size_out = top;
+       if (proc_mm && ptrace_faultinfo)
+               *task_size_out = top;
+       else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
 #endif
        return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
 }
 
  * Licensed under the GPL
  */
 
+#include <signal.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
 #include "mem_user.h"
 #include "mem.h"
+#include "mm_id.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)
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+#include "skas.h"
+
+extern unsigned long syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+                             unsigned long *args)
 {
-       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 n, pid = mm_idp->u.pid;
+        unsigned long regs[MAX_REG_NR];
+
+        get_safe_registers(regs);
+        regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+                ((unsigned long) &syscall_stub -
+                 (unsigned long) &__syscall_stub_start);
+        /* XXX Don't have a define for starting a syscall */
+        regs[REGS_SYSCALL_NR] = syscall;
+        regs[REGS_SYSCALL_ARG1] = args[0];
+        regs[REGS_SYSCALL_ARG2] = args[1];
+        regs[REGS_SYSCALL_ARG3] = args[2];
+        regs[REGS_SYSCALL_ARG4] = args[3];
+        regs[REGS_SYSCALL_ARG5] = args[4];
+        regs[REGS_SYSCALL_ARG6] = args[5];
+        n = ptrace_setregs(pid, regs);
+        if(n < 0){
+                printk("run_syscall_stub : PTRACE_SETREGS failed, "
+                       "errno = %d\n", n);
+                return(n);
+        }
+
+        wait_stub_done(pid, 0, "run_syscall_stub");
+
+        return(*((unsigned long *) mm_idp->stack));
 }
 
-int unmap(int fd, void *addr, unsigned long len)
+int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
+        int r, int w, int x, int phys_fd, unsigned long long offset)
 {
-       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 prot, n;
+
+        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+                (x ? PROT_EXEC : 0);
+
+        if(proc_mm){
+                struct proc_mm_op map;
+                int fd = mm_idp->u.mm_fd;
+                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);
+        }
+        else {
+                long res;
+                unsigned long args[] = { virt, len, prot,
+                                         MAP_SHARED | MAP_FIXED, phys_fd,
+                                         MMAP_OFFSET(offset) };
+
+                res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
+                if((void *) res == MAP_FAILED)
+                        printk("mmap stub failed, errno = %d\n", res);
+        }
+
+        return 0;
 }
 
-int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 
-           int x, int must_succeed)
+int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
 {
-       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);
-       }
+        int n;
+
+        if(proc_mm){
+                struct proc_mm_op unmap;
+                int fd = mm_idp->u.mm_fd;
+                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);
+                }
+        }
+        else {
+                int res;
+                unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+                                         0 };
+
+                res = run_syscall_stub(mm_idp, __NR_munmap, args);
+                if(res < 0)
+                        printk("munmap stub failed, errno = %d\n", res);
+        }
+
+        return(0);
+}
 
-       return(0);
+int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
+           int r, int w, int x)
+{
+        struct proc_mm_op protect;
+        int prot, n;
+
+        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+                (x ? PROT_EXEC : 0);
+
+        if(proc_mm){
+                int fd = mm_idp->u.mm_fd;
+                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))
+                        panic("protect failed, err = %d", -n);
+        }
+        else {
+                int res;
+                unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+                res = run_syscall_stub(mm_idp, __NR_mprotect, args);
+                if(res < 0)
+                        panic("mprotect stub failed, errno = %d\n", res);
+        }
+
+        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:
- */
 
  * Licensed under the GPL
  */
 
+#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/list.h"
 #include "linux/spinlock.h"
 #include "linux/slab.h"
+#include "linux/errno.h"
+#include "linux/mm.h"
 #include "asm/current.h"
 #include "asm/segment.h"
 #include "asm/mmu.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
 #include "os.h"
 #include "skas.h"
 
+extern int __syscall_stub_start;
+
+static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
+                        unsigned long kernel)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       spin_lock(&mm->page_table_lock);
+       pgd = pgd_offset(mm, proc);
+       pud = pud_alloc(mm, pgd, proc);
+       if (!pud)
+               goto out;
+
+       pmd = pmd_alloc(mm, pud, proc);
+       if (!pmd)
+               goto out_pmd;
+
+       pte = pte_alloc_map(mm, pmd, proc);
+       if (!pte)
+               goto out_pte;
+
+       /* There's an interaction between the skas0 stub pages, stack
+        * randomization, and the BUG at the end of exit_mmap.  exit_mmap
+         * checks that the number of page tables freed is the same as had
+         * been allocated.  If the stack is on the last page table page,
+        * then the stack pte page will be freed, and if not, it won't.  To
+        * avoid having to know where the stack is, or if the process mapped
+        * something at the top of its address space for some other reason,
+        * we set TASK_SIZE to end at the start of the last page table.
+        * This keeps exit_mmap off the last page, but introduces a leak
+        * of that page.  So, we hang onto it here and free it in
+        * destroy_context_skas.
+        */
+
+        mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+
+       *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+       *pte = pte_mkexec(*pte);
+       *pte = pte_wrprotect(*pte);
+       spin_unlock(&mm->page_table_lock);
+       return(0);
+
+ out_pmd:
+       pud_free(pud);
+ out_pte:
+       pmd_free(pmd);
+ out:
+       spin_unlock(&mm->page_table_lock);
+       return(-ENOMEM);
+}
+
 int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
 {
-       int from;
+       struct mm_struct *cur_mm = current->mm;
+       struct mm_id *mm_id = &mm->context.skas.id;
+       unsigned long stack;
+       int from, ret;
 
-       if((current->mm != NULL) && (current->mm != &init_mm))
-               from = current->mm->context.skas.mm_fd;
-       else from = -1;
+       if(proc_mm){
+               if((cur_mm != NULL) && (cur_mm != &init_mm))
+                       from = cur_mm->context.skas.id.u.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);
+               ret = new_mm(from);
+               if(ret < 0){
+                       printk("init_new_context_skas - new_mm failed, "
+                              "errno = %d\n", ret);
+                       return ret;
+               }
+               mm_id->u.mm_fd = ret;
        }
+       else {
+               /* This zeros the entry that pgd_alloc didn't, needed since
+                * we are about to reinitialize it, and want mm.nr_ptes to
+                * be accurate.
+                */
+               mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
 
-       return(0);
+               ret = init_stub_pte(mm, CONFIG_STUB_CODE,
+                                   (unsigned long) &__syscall_stub_start);
+               if(ret)
+                       goto out;
+
+               ret = -ENOMEM;
+               stack = get_zeroed_page(GFP_KERNEL);
+               if(stack == 0)
+                       goto out;
+               mm_id->stack = stack;
+
+               ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
+               if(ret)
+                       goto out_free;
+
+               mm->nr_ptes--;
+               mm_id->u.pid = start_userspace(stack);
+       }
+
+       return 0;
+
+ out_free:
+       free_page(mm_id->stack);
+ out:
+       return ret;
 }
 
 void destroy_context_skas(struct mm_struct *mm)
 {
-       os_close_file(mm->context.skas.mm_fd);
-}
+       struct mmu_context_skas *mmu = &mm->context.skas;
 
-/*
- * 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:
- */
+       if(proc_mm)
+               os_close_file(mmu->id.u.mm_fd);
+       else {
+               os_kill_ptraced_process(mmu->id.u.pid, 1);
+               free_page(mmu->id.stack);
+               free_page(mmu->last_page_table);
+       }
+}
 
 /* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <asm/unistd.h>
+#include <asm/types.h>
 #include "user.h"
 #include "ptrace_user.h"
 #include "time_user.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "skas.h"
+#include "mm_id.h"
 #include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
 #include "os.h"
 #include "proc_mm.h"
 #include "skas_ptrace.h"
 #include "chan_user.h"
 #include "signal_user.h"
 #include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
 #include "process.h"
 
 int is_skas_winch(int pid, int fd, void *data)
        return(1);
 }
 
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
+void wait_stub_done(int pid, int sig, char * fname)
 {
-       int err;
-
-        err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
-       if(err)
-                panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
-                      "errno = %d\n", errno);
+        int n, status, err;
+
+        do {
+                if ( sig != -1 ) {
+                        err = ptrace(PTRACE_CONT, pid, 0, sig);
+                        if(err)
+                                panic("%s : continue failed, errno = %d\n",
+                                      fname, errno);
+                }
+                sig = 0;
+
+                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+        } while((n >= 0) && WIFSTOPPED(status) &&
+                (WSTOPSIG(status) == SIGVTALRM));
+
+        if((n < 0) || !WIFSTOPPED(status) ||
+           (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
+                panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+                      "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+                      fname, pid, n, errno, status);
+        }
+}
 
-        /* Special handling for i386, which has different structs */
-        if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
-                memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
-                       sizeof(struct faultinfo) -
-                       sizeof(struct ptrace_faultinfo));
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
+{
+        int err;
+
+        if(ptrace_faultinfo){
+                err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+                if(err)
+                        panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+                              "errno = %d\n", errno);
+
+                /* Special handling for i386, which has different structs */
+                if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+                        memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+                               sizeof(struct faultinfo) -
+                               sizeof(struct ptrace_faultinfo));
+        }
+        else {
+                wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+                /* faultinfo is prepared by the stub-segv-handler at start of
+                 * the stub stack page. We just have to copy it.
+                 */
+                memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+        }
 }
 
 static void handle_segv(int pid, union uml_pt_regs * regs)
        handle_syscall(regs);
 }
 
-static int userspace_tramp(void *arg)
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
 {
-       init_new_thread_signals(0);
-       enable_timer();
+       void *addr;
+
        ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+       init_new_thread_signals(1);
+       enable_timer();
+
+       if(!proc_mm){
+               /* This has a pte, but it can't be mapped in with the usual
+                * tlb_flush mechanism because this is part of that mechanism
+                */
+               int fd;
+               __u64 offset;
+
+               fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+               addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+                             PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+               if(addr == MAP_FAILED){
+                       printk("mapping mmap stub failed, errno = %d\n",
+                              errno);
+                       exit(1);
+               }
+
+               if(stack != NULL){
+                       fd = phys_mapping(to_phys(stack), &offset);
+                       addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+                                   PROT_READ | PROT_WRITE,
+                                   MAP_FIXED | MAP_SHARED, fd, offset);
+                       if(addr == MAP_FAILED){
+                               printk("mapping segfault stack failed, "
+                                      "errno = %d\n", errno);
+                               exit(1);
+                       }
+               }
+       }
+       if(!ptrace_faultinfo && (stack != NULL)){
+               unsigned long v = UML_CONFIG_STUB_CODE +
+                                 (unsigned long) stub_segv_handler -
+                                 (unsigned long) &__syscall_stub_start;
+
+               set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+               set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+                           SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+                           SIGUSR1, -1);
+       }
+
        os_stop_process(os_getpid());
        return(0);
 }
 #define NR_CPUS 1
 int userspace_pid[NR_CPUS];
 
-void start_userspace(int cpu)
+int start_userspace(unsigned long stub_stack)
 {
        void *stack;
        unsigned long sp;
-       int pid, status, n;
+       int pid, status, n, flags;
 
        stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
                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);
+       flags = CLONE_FILES | SIGCHLD;
+       if(proc_mm) flags |= CLONE_VM;
+       pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
        if(pid < 0)
                panic("start_userspace : clone failed, errno = %d", errno);
 
        if(munmap(stack, PAGE_SIZE) < 0)
                panic("start_userspace : munmap failed, errno = %d\n", errno);
 
-       userspace_pid[cpu] = pid;
+       return(pid);
 }
 
 void userspace(union uml_pt_regs *regs)
                if(WIFSTOPPED(status)){
                        switch(WSTOPSIG(status)){
                        case SIGSEGV:
-                                handle_segv(pid, regs);
+                                if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+                                        user_signal(SIGSEGV, regs, pid);
+                                else handle_segv(pid, regs);
                                break;
                        case SIGTRAP + 0x80:
                                handle_trap(pid, regs, local_using_sysemu);
                                printk("userspace - child stopped with signal "
                                       "%d\n", WSTOPSIG(status));
                        }
+                       pid = userspace_pid[0];
                        interrupt_end();
 
                        /* Avoid -ERESTARTSYS handling in host */
        siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
 }
 
-void switch_mm_skas(int mm_fd)
+void switch_mm_skas(struct mm_id *mm_idp)
 {
        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);
+       if(proc_mm){
+               err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+                            mm_idp->u.mm_fd);
+               if(err)
+                       panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+                             "errno = %d\n", errno);
+       }
+       else userspace_pid[0] = mm_idp->u.pid;
 }
 
 /*
 
        return(0);
 }
 
+extern int userspace_pid[];
+
 int start_uml_skas(void)
 {
-       start_userspace(0);
+       if(proc_mm)
+               userspace_pid[0] = start_userspace(0);
 
        init_new_thread_signals(1);
 
 #warning Need to look up userspace_pid by cpu
        return(userspace_pid[0]);
 }
+
+void kill_off_processes_skas(void)
+{
+       if(proc_mm)
+#warning need to loop over userspace_pids in kill_off_processes_skas
+               os_kill_ptraced_process(userspace_pid[0], 1);
+       else {
+               struct task_struct *p;
+               int pid, me;
+
+               me = os_getpid();
+               for_each_process(p){
+                       if(p->mm == NULL)
+                               continue;
+
+                       pid = p->mm->context.skas.id.u.pid;
+                       os_kill_ptraced_process(pid, 1);
+               }
+       }
+}
+
+unsigned long current_stub_stack(void)
+{
+       if(current->mm == NULL)
+               return(0);
+
+       return(current->mm->context.skas.id.stack);
+}
 
 
 #include "linux/stddef.h"
 #include "linux/sched.h"
+#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(int fd, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
 {
        struct host_vm_op *op;
        int i;
                op = &ops[i];
                switch(op->type){
                case MMAP:
-                       map(fd, op->u.mmap.addr, op->u.mmap.len,
+                        map(&mmu->skas.id, 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,
+                        unmap(&mmu->skas.id, (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);
+                        protect(&mmu->skas.id, 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);
        }
 }
 
+extern int proc_mm;
+
 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;
+        if(!proc_mm && (end_addr > CONFIG_STUB_START))
+                end_addr = CONFIG_STUB_START;
 
-        fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+        fix_range_common(mm, start_addr, end_addr, force, do_ops);
 }
 
 void __flush_tlb_one_skas(unsigned long addr)
 
 void flush_tlb_mm_skas(struct mm_struct *mm)
 {
+       unsigned long end;
+
        /* 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);
+       end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(mm, 0, end, 0);
 }
 
 void force_flush_all_skas(void)
 {
-        fix_range(current->mm, 0, host_task_size, 1);
+       unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(current->mm, 0, end, 1);
 }
 
 #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))
+                      unsigned long end_addr, int force,
+                      void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                     int))
 {
         pgd_t *npgd;
         pud_t *npud;
         pmd_t *npmd;
         pte_t *npte;
+        union mm_context *mmu = &mm->context;
         unsigned long addr, end;
         int r, w, x;
         struct host_vm_op ops[16];
                                 end = end_addr;
                         if(force || pgd_newpage(*npgd)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pgd_mkuptodate(*npgd);
                         }
                                 end = end_addr;
                         if(force || pud_newpage(*npud)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pud_mkuptodate(*npud);
                         }
                                 end = end_addr;
                         if(force || pmd_newpage(*npmd)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pmd_mkuptodate(*npmd);
                         }
                                 op_index = add_mmap(addr,
                                                     pte_val(*npte) & PAGE_MASK,
                                                     PAGE_SIZE, r, w, x, ops,
-                                                    op_index, last_op, data,
+                                                    op_index, last_op, mmu,
                                                     do_ops);
                         else op_index = add_munmap(addr, PAGE_SIZE, ops,
-                                                   op_index, last_op, data,
+                                                   op_index, last_op, mmu,
                                                    do_ops);
                 }
                 else if(pte_newprot(*npte))
                         op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
-                                                op_index, last_op, data,
+                                                op_index, last_op, mmu,
                                                 do_ops);
 
                 *npte = pte_mkuptodate(*npte);
                 addr += PAGE_SIZE;
         }
-        (*do_ops)(data, ops, op_index);
+        (*do_ops)(mmu, ops, op_index);
 }
 
 int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
         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));
 }
 
 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))
+             int r, int w, int x, struct host_vm_op *ops, int index,
+             int last_filled, union mm_context *mmu,
+             void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
         __u64 offset;
        struct host_vm_op *last;
        }
 
        if(index == last_filled){
-               (*do_ops)(data, ops, last_filled);
+               (*do_ops)(mmu, ops, last_filled);
                index = -1;
        }
 
 }
 
 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))
+              int index, int last_filled, union mm_context *mmu,
+              void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
        struct host_vm_op *last;
 
        }
 
        if(index == last_filled){
-               (*do_ops)(data, ops, last_filled);
+               (*do_ops)(mmu, ops, last_filled);
                index = -1;
        }
 
 }
 
 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 *ops, int index, int last_filled,
+                 union mm_context *mmu,
+                 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
        struct host_vm_op *last;
 
        }
 
        if(index == last_filled){
-               (*do_ops)(data, ops, last_filled);
+               (*do_ops)(mmu, ops, last_filled);
                index = -1;
        }
 
                                                      .x        = x } } });
        return(index);
 }
+
+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());
+}
+
 
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(int unused, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
 {
        struct host_vm_op *op;
        int i;
                 panic("fix_range fixing wrong address space, current = 0x%p",
                       current);
 
-        fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+        fix_range_common(mm, start_addr, end_addr, force, do_ops);
 }
 
 atomic_t vmchange_seq = ATOMIC_INIT(1);
 
        _einittext = .;
   }
   . = ALIGN(4096);
+
   .text      :
   {
     *(.text)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
     *(.gnu.linkonce.t*)
+
+    . = ALIGN(4096);
+    __syscall_stub_start = .;
+    *(.__syscall_stub*)
+    __syscall_stub_end = .;
+    . = ALIGN(4096);
   }
 
   #include "asm/common.lds.S"
 
                      err);
 }
 
+void get_safe_registers(unsigned long *regs)
+{
+       memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
 
                      err);
 }
 
+void get_safe_registers(unsigned long *regs)
+{
+       memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
 
 endef
 
 
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+       $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
 quiet_cmd_make_link = SYMLINK $@
 cmd_make_link       = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
 
 
 obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-       ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
-       sys_call_table.o
+       ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+       syscalls.o sysrq.o sys_call_table.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 obj-$(CONFIG_MODULES) += module.o
 highmem.c-dir = mm
 module.c-dir = kernel
 
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
 subdir- := util
 
 include arch/um/scripts/Makefile.unmap
 
--- /dev/null
+#include "uml-config.h"
+
+       .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+       int     $0x80
+       mov     %eax, UML_CONFIG_STUB_DATA
+       int3
 
--- /dev/null
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+       struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+       GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+                             sc);
+
+       __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+       __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+               "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+       /* Pop the frame pointer and return address since we need to leave
+        * the stack in its original form when we do the sigreturn here, by
+        * hand.
+        */
+       __asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
+               "int $0x80" : : "g" (__NR_sigreturn));
+}
 
 
 #XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
-       ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
-       syscalls.o sysrq.o thunk.o syscall_table.o
+       ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+       stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
 
 obj-y := ksyms.o
 obj-$(CONFIG_MODULES) += module.o um_module.o
 thunk.S-dir = lib
 module.c-dir = kernel
 
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
 subdir- := util
 
 include arch/um/scripts/Makefile.unmap
 
--- /dev/null
+#include "uml-config.h"
+
+       .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+       syscall
+       /* We don't have 64-bit constants, so this constructs the address
+        * we need.
+        */
+       movq    $(UML_CONFIG_STUB_DATA >> 32), %rbx
+       salq    $32, %rbx
+       movq    $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
+       or      %rcx, %rbx
+       movq    %rax, (%rbx)
+       int3
 
--- /dev/null
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <linux/compiler.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+       struct ucontext *uc;
+
+       __asm__("movq %%rdx, %0" : "=g" (uc) :);
+        GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+                              &uc->uc_mcontext);
+
+       __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
+       __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
+               "syscall": : "g" (__NR_kill), "g" (SIGUSR1));
+       /* Two popqs to restore the stack to the state just before entering
+        * the handler, one pops the return address, the other pops the frame
+        * pointer.
+        */
+       __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
+               (__NR_rt_sigreturn));
+}
 
 #define __UM_MMU_CONTEXT_H
 
 #include "linux/sched.h"
+#include "linux/config.h"
 #include "choose-mode.h"
+#include "um_mmu.h"
 
 #define get_mmu_context(task) do ; while(0)
 #define activate_context(tsk) do ; while(0)
 {
 }
 
-extern void switch_mm_skas(int mm_fd);
-
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
                             struct task_struct *tsk)
 {
                cpu_set(cpu, next->cpu_vm_mask);
                if(next != &init_mm)
                        CHOOSE_MODE((void) 0, 
-                                   switch_mm_skas(next->context.skas.mm_fd));
+                                   switch_mm_skas(&next->context.skas.id));
        }
 }