Whamcloud - gitweb
- uml for 2.4.18-chaos and series file
authoralex <alex>
Wed, 10 Sep 2003 06:06:40 +0000 (06:06 +0000)
committeralex <alex>
Wed, 10 Sep 2003 06:06:40 +0000 (06:06 +0000)
lustre/kernel_patches/patches/kmap_log_init-fix-2.4.18-chaos.patch [new file with mode: 0644]
lustre/kernel_patches/patches/uml-patch-2.4.18-chaos-53.patch [new file with mode: 0644]
lustre/kernel_patches/pc/kmap_log_init-fix-2.4.18-chaos.pc [new file with mode: 0644]
lustre/kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc [new file with mode: 0644]
lustre/kernel_patches/series/chaos-2.4.18-uml [new file with mode: 0644]

diff --git a/lustre/kernel_patches/patches/kmap_log_init-fix-2.4.18-chaos.patch b/lustre/kernel_patches/patches/kmap_log_init-fix-2.4.18-chaos.patch
new file mode 100644 (file)
index 0000000..8ed8df7
--- /dev/null
@@ -0,0 +1,19 @@
+ init/main.c |    4 +++-
+ 1 files changed, 3 insertions(+), 1 deletion(-)
+
+--- linux-2.4.18-chaos-uml/init/main.c~kmap_log_init-fix-2.4.18-chaos  2003-07-28 17:52:20.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/init/main.c  2003-09-09 16:57:34.000000000 +0400
+@@ -448,8 +448,10 @@ asmlinkage void __init start_kernel(void
+        */
+       if (num_mappedpages == 0)
+               num_mappedpages = num_physpages;
+-  
++ 
++#if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL)
+       kmap_log_init();
++#endif
+       fork_init(num_mappedpages);
+       proc_caches_init();
+       vfs_caches_init(num_physpages);
+
+_
diff --git a/lustre/kernel_patches/patches/uml-patch-2.4.18-chaos-53.patch b/lustre/kernel_patches/patches/uml-patch-2.4.18-chaos-53.patch
new file mode 100644 (file)
index 0000000..65ba399
--- /dev/null
@@ -0,0 +1,31159 @@
+ arch/um/Makefile                          |  136 ++++
+ arch/um/Makefile-i386                     |   30 
+ arch/um/Makefile-ia64                     |    1 
+ arch/um/Makefile-os-Linux                 |    7 
+ arch/um/Makefile-ppc                      |    9 
+ arch/um/boot/Makefile                     |    3 
+ arch/um/config.in                         |   86 ++
+ arch/um/config.release                    |  335 ++++++++++
+ arch/um/config_block.in                   |   16 
+ arch/um/config_char.in                    |   37 +
+ arch/um/config_net.in                     |   45 +
+ arch/um/config_scsi.in                    |   30 
+ arch/um/defconfig                         |  377 ++++++++++++
+ arch/um/drivers/Makefile                  |   84 ++
+ arch/um/drivers/chan_kern.c               |  447 ++++++++++++++
+ arch/um/drivers/chan_user.c               |  236 +++++++
+ arch/um/drivers/daemon.h                  |   35 +
+ arch/um/drivers/daemon_kern.c             |  130 ++++
+ arch/um/drivers/daemon_kern.h             |    8 
+ arch/um/drivers/daemon_user.c             |  194 ++++++
+ arch/um/drivers/fd.c                      |   92 ++
+ arch/um/drivers/harddog_kern.c            |  192 ++++++
+ arch/um/drivers/harddog_user.c            |  134 ++++
+ arch/um/drivers/hostaudio_kern.c          |  264 ++++++++
+ arch/um/drivers/hostaudio_user.c          |  149 ++++
+ arch/um/drivers/line.c                    |  479 +++++++++++++++
+ arch/um/drivers/mcast.h                   |   32 +
+ arch/um/drivers/mcast_kern.c              |  159 +++++
+ arch/um/drivers/mcast_kern.h              |    8 
+ arch/um/drivers/mcast_user.c              |  175 +++++
+ arch/um/drivers/mconsole_kern.c           |  373 +++++++++++
+ arch/um/drivers/mconsole_user.c           |  206 ++++++
+ arch/um/drivers/mmapper_kern.c            |  147 ++++
+ arch/um/drivers/net_kern.c                |  729 +++++++++++++++++++++++
+ arch/um/drivers/net_user.c                |  232 +++++++
+ arch/um/drivers/null.c                    |   53 +
+ arch/um/drivers/port.h                    |   30 
+ arch/um/drivers/port_kern.c               |  254 ++++++++
+ arch/um/drivers/port_user.c               |  191 ++++++
+ arch/um/drivers/pty.c                     |  156 ++++
+ arch/um/drivers/slip.h                    |   34 +
+ arch/um/drivers/slip_kern.c               |  115 +++
+ arch/um/drivers/slip_kern.h               |    8 
+ arch/um/drivers/slip_user.c               |  333 ++++++++++
+ arch/um/drivers/ssl.c                     |  226 +++++++
+ arch/um/drivers/ssl.h                     |   23 
+ arch/um/drivers/stdio_console.c           |  211 ++++++
+ arch/um/drivers/stdio_console.h           |   21 
+ arch/um/drivers/tty.c                     |   82 ++
+ arch/um/drivers/ubd_kern.c                |  941 ++++++++++++++++++++++++++++++
+ arch/um/drivers/ubd_user.c                |  617 +++++++++++++++++++
+ arch/um/drivers/xterm.c                   |  178 +++++
+ arch/um/fs/Makefile                       |   23 
+ arch/um/fs/hostfs/Makefile                |   24 
+ arch/um/fs/hostfs/hostfs.h                |   69 ++
+ arch/um/fs/hostfs/hostfs_kern.c           |  807 +++++++++++++++++++++++++
+ arch/um/fs/hostfs/hostfs_user.c           |  336 ++++++++++
+ arch/um/fs/hppfs/Makefile                 |   10 
+ arch/um/fs/hppfs/hppfs_kern.c             |  672 +++++++++++++++++++++
+ arch/um/include/2_5compat.h               |  109 +++
+ arch/um/include/Makefile                  |    7 
+ arch/um/include/chan_kern.h               |   53 +
+ arch/um/include/chan_user.h               |   65 ++
+ arch/um/include/debug.h                   |   26 
+ arch/um/include/frame.h                   |   51 +
+ arch/um/include/frame_kern.h              |   34 +
+ arch/um/include/frame_user.h              |   23 
+ arch/um/include/helper.h                  |   27 
+ arch/um/include/hostaudio.h               |   48 +
+ arch/um/include/init.h                    |  114 +++
+ arch/um/include/initrd.h                  |   22 
+ arch/um/include/irq_user.h                |   33 +
+ arch/um/include/kern.h                    |   47 +
+ arch/um/include/kern_util.h               |  136 ++++
+ arch/um/include/line.h                    |  102 +++
+ arch/um/include/mconsole.h                |   92 ++
+ arch/um/include/mconsole_kern.h           |   48 +
+ arch/um/include/mem.h                     |   28 
+ arch/um/include/mem_user.h                |   88 ++
+ arch/um/include/net_kern.h                |   75 ++
+ arch/um/include/net_user.h                |   57 +
+ arch/um/include/os.h                      |  121 +++
+ arch/um/include/process.h                 |   25 
+ arch/um/include/ptrace_user.h             |   18 
+ arch/um/include/sigcontext.h              |   27 
+ arch/um/include/sigio.h                   |   26 
+ arch/um/include/signal_kern.h             |   26 
+ arch/um/include/signal_user.h             |   26 
+ arch/um/include/syscall_user.h            |   26 
+ arch/um/include/sysdep-i386/frame.h       |   28 
+ arch/um/include/sysdep-i386/frame_kern.h  |   57 +
+ arch/um/include/sysdep-i386/frame_user.h  |   82 ++
+ arch/um/include/sysdep-i386/ptrace.h      |  115 +++
+ arch/um/include/sysdep-i386/ptrace_user.h |   62 +
+ arch/um/include/sysdep-i386/sigcontext.h  |   52 +
+ arch/um/include/sysdep-i386/syscalls.h    |   59 +
+ arch/um/include/sysdep-ia64/ptrace.h      |   26 
+ arch/um/include/sysdep-ia64/sigcontext.h  |   20 
+ arch/um/include/sysdep-ia64/syscalls.h    |   20 
+ arch/um/include/sysdep-ppc/ptrace.h       |  104 +++
+ arch/um/include/sysdep-ppc/sigcontext.h   |   62 +
+ arch/um/include/sysdep-ppc/syscalls.h     |   50 +
+ arch/um/include/sysrq.h                   |    6 
+ arch/um/include/tlb.h                     |   23 
+ arch/um/include/ubd_user.h                |   78 ++
+ arch/um/include/umid.h                    |   17 
+ arch/um/include/umn.h                     |   27 
+ arch/um/include/user.h                    |   29 
+ arch/um/include/user_util.h               |  126 ++++
+ arch/um/kernel/Makefile                   |   84 ++
+ arch/um/kernel/config.c.in                |   34 +
+ arch/um/kernel/exec_kern.c                |  124 +++
+ arch/um/kernel/exec_user.c                |   49 +
+ arch/um/kernel/exitcode.c                 |   70 ++
+ arch/um/kernel/frame.c                    |  293 +++++++++
+ arch/um/kernel/frame_kern.c               |  131 ++++
+ arch/um/kernel/gmon_syms.c                |   20 
+ arch/um/kernel/gprof_syms.c               |   20 
+ arch/um/kernel/helper.c                   |  146 ++++
+ arch/um/kernel/init_task.c                |   61 +
+ arch/um/kernel/initrd_kern.c              |   58 +
+ arch/um/kernel/initrd_user.c              |   43 +
+ arch/um/kernel/irq.c                      |  813 +++++++++++++++++++++++++
+ arch/um/kernel/irq_user.c                 |  357 +++++++++++
+ arch/um/kernel/ksyms.c                    |   51 +
+ arch/um/kernel/mem.c                      |  605 +++++++++++++++++++
+ arch/um/kernel/mem_user.c                 |  274 ++++++++
+ arch/um/kernel/mprot.h                    |    6 
+ arch/um/kernel/process.c                  |  253 ++++++++
+ arch/um/kernel/process_kern.c             |  765 ++++++++++++++++++++++++
+ arch/um/kernel/ptrace.c                   |  266 ++++++++
+ arch/um/kernel/reboot.c                   |   62 +
+ arch/um/kernel/resource.c                 |   23 
+ arch/um/kernel/setup.c                    |   19 
+ arch/um/kernel/sigio_kern.c               |   43 +
+ arch/um/kernel/sigio_user.c               |  413 +++++++++++++
+ arch/um/kernel/signal_kern.c              |  368 +++++++++++
+ arch/um/kernel/signal_user.c              |  138 ++++
+ arch/um/kernel/smp.c                      |  302 +++++++++
+ arch/um/kernel/sys_call_table.c           |  470 ++++++++++++++
+ arch/um/kernel/syscall_kern.c             |  446 ++++++++++++++
+ arch/um/kernel/syscall_user.c             |  116 +++
+ arch/um/kernel/sysrq.c                    |   98 +++
+ arch/um/kernel/time.c                     |  121 +++
+ arch/um/kernel/time_kern.c                |  141 ++++
+ arch/um/kernel/tlb.c                      |  251 ++++++++
+ arch/um/kernel/trap_kern.c                |  407 ++++++++++++
+ arch/um/kernel/trap_user.c                |  568 ++++++++++++++++++
+ arch/um/kernel/tty_log.c                  |  130 ++++
+ arch/um/kernel/uaccess_user.c             |  126 ++++
+ arch/um/kernel/um_arch.c                  |  388 ++++++++++++
+ arch/um/kernel/umid.c                     |  302 +++++++++
+ arch/um/kernel/unmap.c                    |   34 +
+ arch/um/kernel/user_syms.c                |  116 +++
+ arch/um/kernel/user_util.c                |  275 ++++++++
+ arch/um/link.ld.in                        |  144 ++++
+ arch/um/main.c                            |  217 ++++++
+ arch/um/os-Linux/Makefile                 |   17 
+ arch/um/os-Linux/drivers/Makefile         |   31 
+ arch/um/os-Linux/drivers/etap.h           |   27 
+ arch/um/os-Linux/drivers/etap_kern.h      |   24 
+ arch/um/os-Linux/drivers/ethertap_kern.c  |  137 ++++
+ arch/um/os-Linux/drivers/ethertap_user.c  |  238 +++++++
+ arch/um/os-Linux/drivers/tuntap.h         |   34 +
+ arch/um/os-Linux/drivers/tuntap_kern.c    |  119 +++
+ arch/um/os-Linux/drivers/tuntap_kern.h    |   24 
+ arch/um/os-Linux/drivers/tuntap_user.c    |  223 +++++++
+ arch/um/os-Linux/file.c                   |  344 ++++++++++
+ arch/um/os-Linux/include/file.h           |   22 
+ arch/um/os-Linux/process.c                |  102 +++
+ arch/um/os-Linux/tty.c                    |   61 +
+ arch/um/ptproxy/Makefile                  |   26 
+ arch/um/ptproxy/proxy.c                   |  371 +++++++++++
+ arch/um/ptproxy/ptproxy.h                 |   61 +
+ arch/um/ptproxy/ptrace.c                  |  238 +++++++
+ arch/um/ptproxy/sysdep.c                  |   71 ++
+ arch/um/ptproxy/sysdep.h                  |   25 
+ arch/um/ptproxy/wait.c                    |   86 ++
+ arch/um/ptproxy/wait.h                    |   15 
+ arch/um/sys-i386/Makefile                 |   42 +
+ arch/um/sys-i386/bugs.c                   |  156 ++++
+ arch/um/sys-i386/fault.c                  |   34 +
+ arch/um/sys-i386/ksyms.c                  |   16 
+ arch/um/sys-i386/ldt.c                    |   25 
+ arch/um/sys-i386/ptrace.c                 |  326 ++++++++++
+ arch/um/sys-i386/ptrace_user.c            |  116 +++
+ arch/um/sys-i386/sigcontext.c             |  116 +++
+ arch/um/sys-i386/syscalls.c               |   68 ++
+ arch/um/sys-i386/sysrq.c                  |   30 
+ arch/um/sys-i386/util/Makefile            |   17 
+ arch/um/sys-i386/util/mk_sc.c             |   51 +
+ arch/um/sys-i386/util/mk_thread_kern.c    |    7 
+ arch/um/sys-i386/util/mk_thread_user.c    |   12 
+ arch/um/sys-ia64/Makefile                 |   26 
+ arch/um/sys-ppc/Makefile                  |   80 ++
+ arch/um/sys-ppc/misc.S                    |  116 +++
+ arch/um/sys-ppc/miscthings.c              |   56 +
+ arch/um/sys-ppc/ptrace.c                  |   28 
+ arch/um/sys-ppc/ptrace_user.c             |   40 +
+ arch/um/sys-ppc/sigcontext.c              |   15 
+ arch/um/sys-ppc/sysrq.c                   |   43 +
+ arch/um/util/Makefile                     |   15 
+ arch/um/util/mk_task_kern.c               |   17 
+ arch/um/util/mk_task_user.c               |   30 
+ include/asm-i386/system.h                 |    5 
+ include/asm-um/a.out.h                    |   18 
+ include/asm-um/arch-signal-i386.h         |   24 
+ include/asm-um/archparam-i386.h           |   80 ++
+ include/asm-um/archparam-ppc.h            |   41 +
+ include/asm-um/atomic.h                   |    6 
+ include/asm-um/bitops.h                   |    6 
+ include/asm-um/boot.h                     |    6 
+ include/asm-um/bugs.h                     |    6 
+ include/asm-um/byteorder.h                |    6 
+ include/asm-um/cache.h                    |    6 
+ include/asm-um/checksum.h                 |    6 
+ include/asm-um/cobalt.h                   |    6 
+ include/asm-um/current.h                  |   33 +
+ include/asm-um/delay.h                    |    7 
+ include/asm-um/desc.h                     |    6 
+ include/asm-um/div64.h                    |    6 
+ include/asm-um/dma.h                      |   10 
+ include/asm-um/elf.h                      |   18 
+ include/asm-um/errno.h                    |    6 
+ include/asm-um/fcntl.h                    |    6 
+ include/asm-um/floppy.h                   |    6 
+ include/asm-um/hardirq.h                  |    6 
+ include/asm-um/hdreg.h                    |    6 
+ include/asm-um/highmem.h                  |    6 
+ include/asm-um/hw_irq.h                   |   10 
+ include/asm-um/ide.h                      |    6 
+ include/asm-um/init.h                     |   11 
+ include/asm-um/io.h                       |   25 
+ include/asm-um/ioctl.h                    |    6 
+ include/asm-um/ioctls.h                   |    6 
+ include/asm-um/ipc.h                      |    6 
+ include/asm-um/ipcbuf.h                   |    6 
+ include/asm-um/irq.h                      |   35 +
+ include/asm-um/keyboard.h                 |    6 
+ include/asm-um/linux_logo.h               |    6 
+ include/asm-um/locks.h                    |    6 
+ include/asm-um/mca_dma.h                  |    6 
+ include/asm-um/mman.h                     |    6 
+ include/asm-um/mmu.h                      |    6 
+ include/asm-um/mmu_context.h              |   25 
+ include/asm-um/module.h                   |    6 
+ include/asm-um/msgbuf.h                   |    6 
+ include/asm-um/mtrr.h                     |    6 
+ include/asm-um/namei.h                    |    6 
+ include/asm-um/page.h                     |   49 +
+ include/asm-um/page_offset.h              |    1 
+ include/asm-um/param.h                    |   26 
+ include/asm-um/pci.h                      |    6 
+ include/asm-um/perfctr.h                  |   17 
+ include/asm-um/pgalloc.h                  |  144 ++++
+ include/asm-um/pgtable.h                  |  408 +++++++++++++
+ include/asm-um/poll.h                     |    6 
+ include/asm-um/posix_types.h              |    6 
+ include/asm-um/processor-generic.h        |  170 +++++
+ include/asm-um/processor-i386.h           |   35 +
+ include/asm-um/processor-ppc.h            |   15 
+ include/asm-um/ptrace-generic.h           |   71 ++
+ include/asm-um/ptrace-i386.h              |   45 +
+ include/asm-um/resource.h                 |    6 
+ include/asm-um/rmap.h                     |    8 
+ include/asm-um/rwlock.h                   |    6 
+ include/asm-um/rwsem.h                    |   10 
+ include/asm-um/scatterlist.h              |    6 
+ include/asm-um/segment.h                  |    4 
+ include/asm-um/semaphore.h                |    6 
+ include/asm-um/sembuf.h                   |    6 
+ include/asm-um/serial.h                   |    6 
+ include/asm-um/shmbuf.h                   |    6 
+ include/asm-um/shmparam.h                 |    6 
+ include/asm-um/sigcontext-generic.h       |    6 
+ include/asm-um/sigcontext-i386.h          |    6 
+ include/asm-um/sigcontext-ppc.h           |   10 
+ include/asm-um/siginfo.h                  |    6 
+ include/asm-um/signal.h                   |   22 
+ include/asm-um/smp.h                      |   19 
+ include/asm-um/smplock.h                  |    6 
+ include/asm-um/socket.h                   |    6 
+ include/asm-um/sockios.h                  |    6 
+ include/asm-um/softirq.h                  |   13 
+ include/asm-um/spinlock.h                 |   10 
+ include/asm-um/stat.h                     |    6 
+ include/asm-um/statfs.h                   |    6 
+ include/asm-um/string.h                   |    7 
+ include/asm-um/suspend.h                  |    4 
+ include/asm-um/syscall.h                  |   11 
+ include/asm-um/system-generic.h           |   49 +
+ include/asm-um/system-i386.h              |    6 
+ include/asm-um/system-ppc.h               |   12 
+ include/asm-um/termbits.h                 |    6 
+ include/asm-um/termios.h                  |    6 
+ include/asm-um/timex.h                    |   15 
+ include/asm-um/tlb.h                      |    1 
+ include/asm-um/types.h                    |    6 
+ include/asm-um/uaccess.h                  |  193 ++++++
+ include/asm-um/unaligned.h                |    6 
+ include/asm-um/unistd.h                   |  120 +++
+ include/asm-um/user.h                     |    6 
+ include/asm-um/vga.h                      |    6 
+ include/linux/fs.h                        |    4 
+ include/linux/raid/md_compatible.h        |    2 
+ include/linux/syscall.h                   |    5 
+ kernel/ksyms.c                            |    2 
+ kernel/ptrace.c                           |    2 
+ 308 files changed, 29845 insertions(+), 16 deletions(-)
+
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/boot/Makefile        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,3 @@
++dep:
++
++clean:
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config_block.in      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,16 @@
++mainmenu_option next_comment
++comment 'Block Devices'
++
++bool 'Virtual block device' CONFIG_BLK_DEV_UBD
++dep_bool '  Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD
++tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
++dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
++tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
++if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
++      int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
++fi
++dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
++
++tristate 'Example IO memory driver' CONFIG_MMAPPER
++
++endmenu
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config_char.in       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,37 @@
++mainmenu_option next_comment
++comment 'Character Devices'
++
++define_bool CONFIG_STDIO_CONSOLE y
++
++bool 'Virtual serial line' CONFIG_SSL
++
++bool 'file descriptor channel support' CONFIG_FD_CHAN
++bool 'null channel support' CONFIG_NULL_CHAN
++bool 'port channel support' CONFIG_PORT_CHAN
++bool 'pty channel support' CONFIG_PTY_CHAN
++bool 'tty channel support' CONFIG_TTY_CHAN
++bool 'xterm channel support' CONFIG_XTERM_CHAN
++string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \
++            "fd:0,fd:1"
++string 'Default console channel initialization' CONFIG_CON_CHAN "xterm"
++string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty"
++
++
++bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
++if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
++   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
++fi
++
++bool 'Watchdog Timer Support' CONFIG_WATCHDOG
++dep_bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \
++      $CONFIG_WATCHDOG
++dep_tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG
++dep_tristate '  UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG
++
++tristate 'Sound support' CONFIG_UML_SOUND
++define_tristate CONFIG_SOUND $CONFIG_UML_SOUND
++define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND
++
++bool 'Enable tty logging' CONFIG_TTY_LOG
++
++endmenu
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config.in    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,86 @@
++define_bool CONFIG_USERMODE y
++
++mainmenu_name "Linux/Usermode Kernel Configuration"
++
++define_bool CONFIG_ISA n
++define_bool CONFIG_SBUS n
++define_bool CONFIG_PCI n
++
++define_bool CONFIG_UID16 y
++
++define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
++
++mainmenu_option next_comment
++comment 'Code maturity level options'
++bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
++endmenu
++
++mainmenu_option next_comment
++comment 'General Setup'
++bool 'Networking support' CONFIG_NET
++bool 'System V IPC' CONFIG_SYSVIPC
++bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
++bool 'Sysctl support' CONFIG_SYSCTL
++tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
++tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
++tristate 'Host filesystem' CONFIG_HOSTFS
++tristate 'Honeypot proc filesystem' CONFIG_HPPFS
++bool 'Management console' CONFIG_MCONSOLE
++dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
++bool '2G/2G host address space split' CONFIG_HOST_2G_2G
++bool 'Symmetric multi-processing support' CONFIG_UML_SMP
++define_bool CONFIG_SMP $CONFIG_UML_SMP
++int 'Nesting level' CONFIG_NEST_LEVEL 0
++int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
++endmenu
++
++mainmenu_option next_comment
++comment 'Loadable module support'
++bool 'Enable loadable module support' CONFIG_MODULES
++if [ "$CONFIG_MODULES" = "y" ]; then
++# MODVERSIONS does not yet work in this architecture
++#   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
++    bool '  Kernel module loader' CONFIG_KMOD
++fi
++endmenu
++
++source arch/um/config_char.in
++
++source arch/um/config_block.in
++
++define_bool CONFIG_NETDEVICES $CONFIG_NET
++
++if [ "$CONFIG_NET" = "y" ]; then
++   source arch/um/config_net.in
++   source net/Config.in
++fi
++
++source fs/Config.in
++
++mainmenu_option next_comment
++comment 'SCSI support'
++
++tristate 'SCSI support' CONFIG_SCSI
++
++if [ "$CONFIG_SCSI" != "n" ]; then
++   source arch/um/config_scsi.in
++fi
++endmenu
++
++source drivers/md/Config.in
++
++source drivers/mtd/Config.in
++
++mainmenu_option next_comment
++comment 'Kernel hacking'
++bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
++bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM
++if [ "$CONFIG_XTERM_CHAN" = "y" ]; then
++   dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM
++else 
++   define_bool CONFIG_PT_PROXY n
++fi
++dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM
++dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM
++endmenu
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config_net.in        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,45 @@
++mainmenu_option next_comment
++comment 'Network Devices'
++
++# UML virtual driver
++bool 'Virtual network device' CONFIG_UML_NET
++
++dep_bool '  Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET
++dep_bool '  TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET
++dep_bool '  SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
++dep_bool '  Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
++dep_bool '  Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
++
++# Below are hardware-independent drivers mirrored from
++# drivers/net/Config.in. It would be nice if Linux
++# had HW independent drivers separated from the other
++# but it does not. Until then each non-ISA/PCI arch
++# needs to provide it's own menu of network drivers
++
++tristate 'Dummy net driver support' CONFIG_DUMMY
++tristate 'Bonding driver support' CONFIG_BONDING
++tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
++tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   if [ "$CONFIG_NETLINK" = "y" ]; then
++      tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
++   fi
++fi
++
++tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
++if [ ! "$CONFIG_PPP" = "n" ]; then
++   dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
++   dep_bool '  PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
++   dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
++   dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
++   dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
++   dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
++   dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL
++fi
++
++tristate 'SLIP (serial line) support' CONFIG_SLIP
++dep_bool '  CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP
++dep_bool '  Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP
++dep_bool '  Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP
++
++endmenu
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config.release       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,335 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_USERMODE=y
++# CONFIG_ISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_PCI is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# General Setup
++#
++CONFIG_STDIO_CONSOLE=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++CONFIG_SSL=y
++CONFIG_HOSTFS=y
++CONFIG_MCONSOLE=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_HOST_2G_2G is not set
++# CONFIG_UML_SMP is not set
++# CONFIG_SMP is not set
++CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
++CONFIG_CON_CHAN="xterm"
++CONFIG_SSL_CHAN="pty"
++CONFIG_NEST_LEVEL=0
++CONFIG_KERNEL_HALF_GIGS=1
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_KMOD=y
++
++#
++# Devices
++#
++CONFIG_BLK_DEV_UBD=y
++# CONFIG_BLK_DEV_UBD_SYNC is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_NBD=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_MMAPPER is not set
++CONFIG_UML_SOUND=y
++CONFIG_SOUND=y
++CONFIG_HOSTAUDIO=y
++# CONFIG_UML_WATCHDOG is not set
++# CONFIG_TTY_LOG is not set
++CONFIG_FD_CHAN=y
++# CONFIG_NULL_CHAN is not set
++CONFIG_PORT_CHAN=y
++CONFIG_PTY_CHAN=y
++CONFIG_TTY_CHAN=y
++CONFIG_XTERM_CHAN=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#  
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network device support
++#
++CONFIG_UML_NET=y
++CONFIG_UML_NET_ETHERTAP=y
++CONFIG_UML_NET_TUNTAP=y
++CONFIG_UML_NET_SLIP=y
++CONFIG_UML_NET_DAEMON=y
++CONFIG_UML_NET_MCAST=y
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++CONFIG_DUMMY=y
++CONFIG_BONDING=m
++CONFIG_EQUALIZER=m
++CONFIG_TUN=y
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++# CONFIG_NET_ETHERNET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++CONFIG_PLIP=m
++CONFIG_PPP=m
++CONFIG_PPP_MULTILINK=y
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_ASYNC is not set
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPPOE=m
++CONFIG_SLIP=m
++CONFIG_SLIP_COMPRESSED=y
++CONFIG_SLIP_SMART=y
++# CONFIG_SLIP_MODE_SLIP6 is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++CONFIG_SHAPER=m
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# File systems
++#
++CONFIG_QUOTA=y
++CONFIG_AUTOFS_FS=m
++CONFIG_AUTOFS4_FS=m
++CONFIG_REISERFS_FS=m
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_ADFS_FS=m
++# CONFIG_ADFS_FS_RW is not set
++CONFIG_AFFS_FS=m
++CONFIG_HFS_FS=m
++CONFIG_BFS_FS=m
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_UMSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_EFS_FS=m
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++CONFIG_CRAMFS=m
++CONFIG_TMPFS=y
++CONFIG_RAMFS=m
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_MINIX_FS=m
++CONFIG_VXFS_FS=m
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++CONFIG_HPFS_FS=m
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++CONFIG_QNX4FS_FS=m
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=m
++CONFIG_EXT2_FS=y
++CONFIG_SYSV_FS=m
++CONFIG_UDF_FS=m
++# CONFIG_UDF_RW is not set
++CONFIG_UFS_FS=m
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_ROOT_NFS is not set
++CONFIG_NFSD=y
++CONFIG_NFSD_V3=y
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++CONFIG_ZLIB_FS_INFLATE=m
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUGSYM is not set
++# CONFIG_PT_PROXY is not set
++# CONFIG_GPROF is not set
++# CONFIG_GCOV is not set
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/config_scsi.in       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,30 @@
++comment 'SCSI support type (disk, tape, CD-ROM)'
++
++dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
++
++if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
++   int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
++fi
++
++dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
++
++dep_tristate '  SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
++
++if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
++   bool '    Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
++   int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
++fi
++dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
++
++comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
++
++#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   bool '  Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES
++#fi
++
++bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
++  
++bool '  Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
++bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
++
++dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/defconfig    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,377 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_USERMODE=y
++# CONFIG_ISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_PCI is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# General Setup
++#
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++CONFIG_HOSTFS=y
++CONFIG_HPPFS=y
++CONFIG_MCONSOLE=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_HOST_2G_2G is not set
++# CONFIG_UML_SMP is not set
++# CONFIG_SMP is not set
++CONFIG_NEST_LEVEL=0
++CONFIG_KERNEL_HALF_GIGS=1
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_KMOD is not set
++
++#
++# Character Devices
++#
++CONFIG_STDIO_CONSOLE=y
++CONFIG_SSL=y
++CONFIG_FD_CHAN=y
++CONFIG_NULL_CHAN=y
++CONFIG_PORT_CHAN=y
++CONFIG_PTY_CHAN=y
++CONFIG_TTY_CHAN=y
++CONFIG_XTERM_CHAN=y
++CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
++CONFIG_CON_CHAN="xterm"
++CONFIG_SSL_CHAN="pty"
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++# CONFIG_WATCHDOG is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_UML_WATCHDOG is not set
++CONFIG_UML_SOUND=y
++CONFIG_SOUND=y
++CONFIG_HOSTAUDIO=y
++# CONFIG_TTY_LOG is not set
++
++#
++# Block Devices
++#
++CONFIG_BLK_DEV_UBD=y
++# CONFIG_BLK_DEV_UBD_SYNC is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_NBD=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_MMAPPER is not set
++CONFIG_NETDEVICES=y
++
++#
++# Network Devices
++#
++CONFIG_UML_NET=y
++CONFIG_UML_NET_ETHERTAP=y
++CONFIG_UML_NET_TUNTAP=y
++CONFIG_UML_NET_SLIP=y
++CONFIG_UML_NET_DAEMON=y
++CONFIG_UML_NET_MCAST=y
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
++CONFIG_PPP=y
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_ASYNC is not set
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_PPP_DEFLATE is not set
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPPOE is not set
++CONFIG_SLIP=y
++# CONFIG_SLIP_COMPRESSED is not set
++# CONFIG_SLIP_SMART is not set
++# CONFIG_SLIP_MODE_SLIP6 is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#  
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# File systems
++#
++CONFIG_QUOTA=y
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_UMSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS_FS=y
++CONFIG_JFFS_FS_VERBOSE=0
++CONFIG_JFFS_PROC_FS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++# CONFIG_RAMFS is not set
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++# CONFIG_NFS_FS is not set
++# CONFIG_NFS_V3 is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_SUNRPC is not set
++# CONFIG_LOCKD is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++CONFIG_SCSI_DEBUG=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_PARTITIONS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++# CONFIG_MTD_GEN_PROBE is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLKMTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_DEBUGSYM=y
++CONFIG_PT_PROXY=y
++# CONFIG_GPROF is not set
++# CONFIG_GCOV is not set
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/chan_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,447 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <asm/irq.h>
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "sigio.h"
++#include "line.h"
++
++static void *not_configged_init(char *str, int device, struct chan_opts *opts)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(NULL);
++}
++
++static int not_configged_open(int input, int output, int primary, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-ENODEV);
++}
++
++static void not_configged_close(int fd, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++}
++
++static int not_configged_read(int fd, char *c_out, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_write(int fd, const char *buf, int len, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_console_write(int fd, const char *buf, int len,
++                                     void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_window_size(int fd, void *data, unsigned short *rows,
++                                   unsigned short *cols)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-ENODEV);
++}
++
++static void not_configged_free(void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++}
++
++static struct chan_ops not_configged_ops = {
++      init:           not_configged_init,
++      open:           not_configged_open,
++      close:          not_configged_close,
++      read:           not_configged_read,
++      write:          not_configged_write,
++      console_write:  not_configged_console_write,
++      window_size:    not_configged_window_size,
++      free:           not_configged_free,
++      winch:          0,
++};
++
++static void tty_receive_char(struct tty_struct *tty, char ch)
++{
++      if(tty == NULL) return;
++
++      if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
++              if(ch == STOP_CHAR(tty)){
++                      stop_tty(tty);
++                      return;
++              }
++              else if(ch == START_CHAR(tty)){
++                      start_tty(tty);
++                      return;
++              }
++      }
++
++      if((tty->flip.flag_buf_ptr == NULL) || 
++         (tty->flip.char_buf_ptr == NULL))
++              return;
++      tty_insert_flip_char(tty, ch, TTY_NORMAL);
++}
++
++static int open_one_chan(struct chan *chan, int input, int output, int primary)
++{
++      int fd;
++
++      if(chan->opened) return(0);
++      if(chan->ops->open == NULL) fd = 0;
++      else fd = (*chan->ops->open)(input, output, primary, chan->data);
++      if(fd < 0) return(fd);
++      chan->fd = fd;
++
++      chan->opened = 1;
++      return(0);
++}
++
++int open_chan(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int ret, err = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              ret = open_one_chan(chan, chan->input, chan->output,
++                                  chan->primary);
++              if(chan->primary) err = ret;
++      }
++      return(err);
++}
++
++void chan_enable_winch(struct list_head *chans, void *line)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary && chan->output && chan->ops->winch){
++                      register_winch(chan->fd, line);
++                      return;
++              }
++      }
++}
++
++void enable_chan(struct list_head *chans, void *data)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->opened) continue;
++
++              line_setup_irq(chan->fd, chan->input, chan->output, data);
++      }
++}
++
++void close_chan(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      /* Close in reverse order as open in case more than one of them
++       * refers to the same device and they save and restore that device's
++       * state.  Then, the first one opened will have the original state,
++       * so it must be the last closed.
++       */
++        for(ele = chans->prev; ele != chans; ele = ele->prev){
++                chan = list_entry(ele, struct chan, list);
++              if(!chan->opened) continue;
++              if(chan->ops->close != NULL)
++                      (*chan->ops->close)(chan->fd, chan->data);
++              chan->opened = 0;
++              chan->fd = -1;
++      }
++}
++
++int write_chan(struct list_head *chans, const char *buf, int len, 
++             int write_irq)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int n, ret = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->output || (chan->ops->write == NULL)) continue;
++              n = chan->ops->write(chan->fd, buf, len, chan->data);
++              if(chan->primary){
++                      ret = n;
++                      if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
++                              reactivate_fd(chan->fd, write_irq);
++                              if(ret == -EAGAIN) ret = 0;
++                      }
++              }
++      }
++      return(ret);
++}
++
++int console_write_chan(struct list_head *chans, const char *buf, int len)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int n, ret = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->output || (chan->ops->console_write == NULL))
++                      continue;
++              n = chan->ops->console_write(chan->fd, buf, len, chan->data);
++              if(chan->primary) ret = n;
++      }
++      return(ret);
++}
++
++int chan_window_size(struct list_head *chans, unsigned short *rows_out,
++                    unsigned short *cols_out)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary){
++                      if(chan->ops->window_size == NULL) return(0);
++                      return(chan->ops->window_size(chan->fd, chan->data,
++                                                    rows_out, cols_out));
++              }
++      }
++      return(0);
++}
++
++void free_one_chan(struct chan *chan)
++{
++      list_del(&chan->list);
++      if(chan->ops->free != NULL)
++              (*chan->ops->free)(chan->data);
++      free_irq_by_fd(chan->fd);
++      if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
++      kfree(chan);
++}
++
++void free_chan(struct list_head *chans)
++{
++      struct list_head *ele, *next;
++      struct chan *chan;
++
++      list_for_each_safe(ele, next, chans){
++              chan = list_entry(ele, struct chan, list);
++              free_one_chan(chan);
++      }
++}
++
++struct chan_type {
++      char *key;
++      struct chan_ops *ops;
++};
++
++struct chan_type chan_table[] = {
++#ifdef CONFIG_FD_CHAN
++      { "fd", &fd_ops },
++#else
++      { "fd", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_NULL_CHAN
++      { "null", &null_ops },
++#else
++      { "null", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_PORT_CHAN
++      { "port", &port_ops },
++#else
++      { "port", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_PTY_CHAN
++      { "pty", &pty_ops },
++      { "pts", &pts_ops },
++#else
++      { "pty", &not_configged_ops },
++      { "pts", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_TTY_CHAN
++      { "tty", &tty_ops },
++#else
++      { "tty", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_XTERM_CHAN
++      { "xterm", &xterm_ops },
++#else
++      { "xterm", &not_configged_ops },
++#endif
++};
++
++static struct chan *parse_chan(char *str, int pri, int device, 
++                             struct chan_opts *opts)
++{
++      struct chan_type *entry;
++      struct chan_ops *ops;
++      struct chan *chan;
++      void *data;
++      int i;
++
++      ops = NULL;
++      data = NULL;
++      for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
++              entry = &chan_table[i];
++              if(!strncmp(str, entry->key, strlen(entry->key))){
++                      ops = entry->ops;
++                      str += strlen(entry->key);
++                      break;
++              }
++      }
++      if(ops == NULL){
++              printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", 
++                     str);
++              return(NULL);
++      }
++      if(ops->init == NULL) return(NULL); 
++      data = (*ops->init)(str, device, opts);
++      if(data == NULL) return(NULL);
++
++      chan = kmalloc(sizeof(*chan), GFP_KERNEL);
++      if(chan == NULL) return(NULL);
++      *chan = ((struct chan) { list :         LIST_HEAD_INIT(chan->list),
++                               primary :      1,
++                               input :        0,
++                               output :       0,
++                               opened :       0,
++                               fd :           -1,
++                               pri :          pri,
++                               ops :          ops,
++                               data :         data });
++      return(chan);
++}
++
++int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
++                  struct chan_opts *opts)
++{
++      struct chan *new, *chan;
++      char *in, *out;
++
++      if(!list_empty(chans)){
++              chan = list_entry(chans->next, struct chan, list);
++              if(chan->pri >= pri) return(0);
++              free_chan(chans);
++              INIT_LIST_HEAD(chans);
++      }
++
++      if((out = strchr(str, ',')) != NULL){
++              in = str;
++              *out = '\0';
++              out++;
++              new = parse_chan(in, pri, device, opts);
++              if(new == NULL) return(-1);
++              new->input = 1;
++              list_add(&new->list, chans);
++
++              new = parse_chan(out, pri, device, opts);
++              if(new == NULL) return(-1);
++              list_add(&new->list, chans);
++              new->output = 1;
++      }
++      else {
++              new = parse_chan(str, pri, device, opts);
++              if(new == NULL) return(-1);
++              list_add(&new->list, chans);
++              new->input = 1;
++              new->output = 1;
++      }
++      return(0);
++}
++
++int chan_out_fd(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary && chan->output)
++                      return(chan->fd);
++      }
++      return(-1);
++}
++
++void chan_interrupt(struct list_head *chans, struct tq_struct *task,
++                  struct tty_struct *tty, int irq, void *dev)
++{
++      struct list_head *ele, *next;
++      struct chan *chan;
++      int err;
++      char c;
++
++      list_for_each_safe(ele, next, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->input || (chan->ops->read == NULL)) continue;
++              do {
++                      if((tty != NULL) && 
++                         (tty->flip.count >= TTY_FLIPBUF_SIZE)){
++                              queue_task(task, &tq_timer);
++                              goto out;
++                      }
++                      err = chan->ops->read(chan->fd, &c, chan->data);
++                      if(err > 0) tty_receive_char(tty, c);
++              } while(err > 0);
++              if(err == 0) reactivate_fd(chan->fd, irq);
++              if(err == -EIO){
++                      if(chan->primary){
++                              if(tty != NULL) tty_hangup(tty);
++                              line_disable(dev, irq);
++                              close_chan(chans);
++                              free_chan(chans);
++                              return;
++                      }
++                      else {
++                              if(chan->ops->close != NULL)
++                                      chan->ops->close(chan->fd, chan->data);
++                              free_one_chan(chan);
++                      }
++              }
++      }
++ out:
++      if(tty) tty_flip_buffer_push(tty);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/chan_user.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,236 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <termios.h>
++#include <fcntl.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/ioctl.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "user_util.h"
++#include "chan_user.h"
++#include "user.h"
++#include "helper.h"
++#include "os.h"
++
++void generic_close(int fd, void *unused)
++{
++      close(fd);
++}
++
++int generic_read(int fd, char *c_out, void *unused)
++{
++      int n;
++
++      n = read(fd, c_out, sizeof(*c_out));
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-EIO);
++      return(1);
++}
++
++int generic_write(int fd, const char *buf, int n, void *unused)
++{
++      int count;
++
++      count = write(fd, buf, n);
++      if(count < 0) return(-errno);
++      return(count);
++}
++
++int generic_console_write(int fd, const char *buf, int n, void *unused)
++{
++      struct termios save, new;
++      int err;
++
++      if(isatty(fd)){
++              tcgetattr(fd, &save);
++              new = save;
++              new.c_oflag |= OPOST;
++              tcsetattr(fd, TCSAFLUSH, &new);
++      }
++      err = generic_write(fd, buf, n, NULL);
++      if(isatty(fd)) tcsetattr(fd, TCSAFLUSH, &save);
++      return(err);
++}
++
++int generic_window_size(int fd, void *unused, unsigned short *rows_out,
++                      unsigned short *cols_out)
++{
++      struct winsize size;
++      int ret = 0;
++
++      if(ioctl(fd, TIOCGWINSZ, &size) == 0){
++              ret = ((*rows_out != size.ws_row) || 
++                     (*cols_out != size.ws_col));
++              *rows_out = size.ws_row;
++              *cols_out = size.ws_col;
++      }
++      return(ret);
++}
++
++void generic_free(void *data)
++{
++      kfree(data);
++}
++
++static void winch_handler(int sig)
++{
++}
++
++struct winch_data {
++      int pty_fd;
++      int pipe_fd;
++      int close_me;
++};
++
++static int winch_thread(void *arg)
++{
++      struct winch_data *data = arg;
++      sigset_t sigs;
++      int pty_fd, pipe_fd;
++      char c = 1;
++
++      close(data->close_me);
++      pty_fd = data->pty_fd;
++      pipe_fd = data->pipe_fd;
++      if(write(pipe_fd, &c, sizeof(c)) != sizeof(c))
++              printk("winch_thread : failed to write synchronization "
++                     "byte, errno = %d\n", errno);
++
++      signal(SIGWINCH, winch_handler);
++      sigfillset(&sigs);
++      sigdelset(&sigs, SIGWINCH);
++      if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
++              printk("winch_thread : sigprocmask failed, errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      if(setsid() < 0){
++              printk("winch_thread : setsid failed, errno = %d\n", errno);
++              exit(1);
++      }
++
++      if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){
++              printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno);
++              exit(1);
++      }
++      if(tcsetpgrp(pty_fd, os_getpid()) < 0){
++              printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
++              exit(1);
++      }
++
++      if(read(pipe_fd, &c, sizeof(c)) != sizeof(c))
++              printk("winch_thread : failed to read synchronization byte, "
++                     "errno = %d\n", errno);
++
++      while(1){
++              pause();
++
++              if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){
++                      printk("winch_thread : write failed, errno = %d\n",
++                             errno);
++              }
++      }
++}
++
++static int tracer_winch[2];
++
++static void tracer_winch_handler(int sig)
++{
++      char c = 1;
++
++      if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
++              printk("tracer_winch_handler - write failed, errno = %d\n",
++                     errno);
++}
++
++void setup_tracer_winch(void)
++{
++      int err;
++
++      err = os_pipe(tracer_winch, 1, 1);
++      if(err){
++              printk("setup_tracer_winch : os_pipe failed, errno = %d\n", 
++                     -err);
++              return;
++      }
++      signal(SIGWINCH, tracer_winch_handler);
++}
++
++static int winch_tramp(int fd, void *device_data, int *fd_out)
++{
++      struct winch_data data;
++      unsigned long stack;
++      int fds[2], pid, n, err;
++      char c;
++
++      err = os_pipe(fds, 1, 1);
++      if(err){
++              printk("winch_tramp : os_pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++
++      data = ((struct winch_data) { pty_fd :          fd,
++                                    pipe_fd :         fds[1],
++                                    close_me :        fds[0] } );
++      pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
++      if(pid < 0){
++              printk("fork of winch_thread failed - errno = %d\n", errno);
++              return(pid);
++      }
++
++      close(fds[1]);
++      *fd_out = fds[0];
++      n = read(fds[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("winch_tramp : failed to read synchronization byte\n");
++              printk("read returned %d, errno = %d\n", n, errno);
++              printk("fd %d will not support SIGWINCH\n", fd);
++              *fd_out = -1;
++      }
++      return(pid);
++}
++
++void register_winch(int fd, void *device_data)
++{
++      int pid, thread, thread_fd;
++      char c = 1;
++
++      if(!isatty(fd)) return;
++
++      pid = tcgetpgrp(fd);
++      if(pid == tracing_pid)
++              register_winch_irq(tracer_winch[0], fd, -1, device_data);
++      else if(pid == -1){
++              thread = winch_tramp(fd, device_data, &thread_fd);
++              if(fd != -1){
++                      register_winch_irq(thread_fd, fd, thread, device_data);
++
++                      if(write(thread_fd, &c, sizeof(c)) != sizeof(c))
++                              printk("register_winch : failed to write "
++                                     "synchronization byte\n");
++              }
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/daemon.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,35 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++#define SWITCH_VERSION 3
++
++struct daemon_data {
++      char *sock_type;
++      char *ctl_sock;
++      void *ctl_addr;
++      void *data_addr;
++      void *local_addr;
++      int fd;
++      int control;
++      void *dev;
++};
++
++extern struct net_user_info daemon_user_info;
++
++extern int daemon_user_write(int fd, void *buf, int len, 
++                           struct daemon_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/daemon_kern.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,130 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/kernel.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "daemon.h"
++#include "daemon_kern.h"
++
++struct daemon_data daemon_priv[MAX_UML_NETDEV] = {
++      [ 0 ... MAX_UML_NETDEV - 1 ] =
++      {
++              sock_type :     "unix",
++              ctl_sock :      "/tmp/uml.ctl",
++              ctl_addr :      NULL,
++              data_addr :     NULL,
++              local_addr :    NULL,
++              fd :            -1,
++              control :       -1,
++              dev :           NULL,
++      }
++};
++
++struct net_device *daemon_init(int private_size, int index)
++{
++      struct net_device *dev;
++      struct uml_net_private *pri;
++      struct daemon_data *dpri;
++
++      dev = init_etherdev(NULL, private_size);
++      if(dev == NULL) return(NULL);
++      pri = dev->priv;
++      dpri = (struct daemon_data *) pri->user;
++      *dpri = daemon_priv[index];
++      printk("daemon backend (uml_switch version %d) - %s:%s", 
++             SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
++      printk("\n");
++      return(dev);
++}
++
++static unsigned short daemon_protocol(struct sk_buff *skb)
++{
++      return(eth_type_trans(skb, skb->dev));
++}
++
++static int daemon_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_recvfrom(fd, (*skb)->mac.raw, 
++                          (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int daemon_write(int fd, struct sk_buff **skb,
++                      struct uml_net_private *lp)
++{
++      return(daemon_user_write(fd, (*skb)->data, (*skb)->len, 
++                               (struct daemon_data *) &lp->user));
++}
++
++static struct net_kern_info daemon_kern_info = {
++      init:                   daemon_init,
++      protocol:               daemon_protocol,
++      read:                   daemon_read,
++      write:                  daemon_write,
++};
++
++static int daemon_count = 0;
++
++int daemon_setup(char *str, struct uml_net *dev)
++{
++      int err, n = daemon_count;
++
++      dev->user = &daemon_user_info;
++      dev->kern = &daemon_kern_info;
++      dev->private_size = sizeof(struct daemon_data);
++      dev->transport_index = daemon_count++;
++      if(*str != ',') return(0);
++      str++;
++      if(*str != ','){
++              err = setup_etheraddr(str, dev->mac);
++              if(!err) dev->have_mac = 1;
++      }
++      str = strchr(str, ',');
++      if(str == NULL) return(0);
++      *str++ = '\0';
++      if(*str != ',') daemon_priv[n].sock_type = str;
++      str = strchr(str, ',');
++      if(str == NULL) return(0);
++      *str++ = '\0';
++      if(*str != ',') daemon_priv[n].ctl_sock = str;
++      str = strchr(str, ',');
++      if(str == NULL) return(0);
++      *str = '\0';
++      printk(KERN_WARNING "daemon_setup : Ignoring data socket "
++             "specification\n");
++      return(0);
++}
++
++static struct transport daemon_transport = {
++      list :  LIST_HEAD_INIT(daemon_transport.list),
++      name :  "daemon",
++      setup : daemon_setup
++};
++
++static int register_daemon(void)
++{
++      register_transport(&daemon_transport);
++      return(1);
++}
++
++__initcall(register_daemon);
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/daemon_kern.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,8 @@
++#ifndef __UM_DAEMON_KERN_H
++#define __UM_DAEMON_KERN_H
++
++#include "net_kern.h"
++
++extern int daemon_setup(char *arg, struct uml_net *dev);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/daemon_user.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,194 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include "net_user.h"
++#include "daemon.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++enum request_type { REQ_NEW_CONTROL };
++
++#define SWITCH_MAGIC 0xfeedface
++
++struct request_v3 {
++      unsigned long magic;
++      int version;
++      enum request_type type;
++      struct sockaddr_un sock;
++};
++
++static struct sockaddr_un *new_addr(void *name, int len)
++{
++      struct sockaddr_un *sun;
++
++      sun = um_kmalloc(sizeof(struct sockaddr_un));
++      if(sun == NULL){
++              printk("new_addr: allocation of sockaddr_un failed\n");
++              return(NULL);
++      }
++      sun->sun_family = AF_UNIX;
++      memcpy(sun->sun_path, name, len);
++      return(sun);
++}
++
++static int connect_to_switch(struct daemon_data *pri)
++{
++      struct sockaddr_un *ctl_addr = pri->ctl_addr;
++      struct sockaddr_un *local_addr = pri->local_addr;
++      struct sockaddr_un *sun;
++      struct request_v3 req;
++      int fd, n, err;
++
++      if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
++              printk("daemon_open : control socket failed, errno = %d\n", 
++                     errno);          
++              return(-errno);
++      }
++
++      if(connect(pri->control, (struct sockaddr *) ctl_addr, 
++                 sizeof(*ctl_addr)) < 0){
++              printk("daemon_open : control connect failed, errno = %d\n",
++                     errno);
++              err = -errno;
++              goto out;
++      }
++
++      if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
++              printk("daemon_open : data socket failed, errno = %d\n", 
++                     errno);
++              err = -errno;
++              goto out;
++      }
++      if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
++              printk("daemon_open : data bind failed, errno = %d\n", 
++                     errno);
++              err = -errno;
++              goto out_close;
++      }
++
++      sun = um_kmalloc(sizeof(struct sockaddr_un));
++      if(sun == NULL){
++              printk("new_addr: allocation of sockaddr_un failed\n");
++              err = -ENOMEM;
++              goto out_close;
++      }
++
++      req.magic = SWITCH_MAGIC;
++      req.version = SWITCH_VERSION;
++      req.type = REQ_NEW_CONTROL;
++      req.sock = *local_addr;
++      n = write(pri->control, &req, sizeof(req));
++      if(n != sizeof(req)){
++              printk("daemon_open : control setup request returned %d, "
++                     "errno = %d\n", n, errno);
++              err = -ENOTCONN;
++              goto out;               
++      }
++
++      n = read(pri->control, sun, sizeof(*sun));
++      if(n != sizeof(*sun)){
++              printk("daemon_open : read of data socket returned %d, "
++                     "errno = %d\n", n, errno);
++              err = -ENOTCONN;
++              goto out_close;         
++      }
++
++      pri->data_addr = sun;
++      return(fd);
++
++ out_close:
++      close(fd);
++ out:
++      close(pri->control);
++      return(err);
++}
++
++static void daemon_user_init(void *data, void *dev)
++{
++      struct daemon_data *pri = data;
++      struct timeval tv;
++      struct {
++              char zero;
++              int pid;
++              int usecs;
++      } name;
++
++      if(!strcmp(pri->sock_type, "unix"))
++              pri->ctl_addr = new_addr(pri->ctl_sock, 
++                                       strlen(pri->ctl_sock) + 1);
++      name.zero = 0;
++      name.pid = os_getpid();
++      gettimeofday(&tv, NULL);
++      name.usecs = tv.tv_usec;
++      pri->local_addr = new_addr(&name, sizeof(name));
++      pri->dev = dev;
++      pri->fd = connect_to_switch(pri);
++      if(pri->fd < 0){
++              kfree(pri->local_addr);
++              pri->local_addr = NULL;
++      }
++}
++
++static int daemon_open(void *data)
++{
++      struct daemon_data *pri = data;
++      return(pri->fd);
++}
++
++static void daemon_remove(void *data)
++{
++      struct daemon_data *pri = data;
++
++      close(pri->fd);
++      close(pri->control);
++      if(pri->data_addr != NULL) kfree(pri->data_addr);
++      if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
++      if(pri->local_addr != NULL) kfree(pri->local_addr);
++}
++
++int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
++{
++      struct sockaddr_un *data_addr = pri->data_addr;
++
++      return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
++}
++
++static int daemon_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info daemon_user_info = {
++      init:           daemon_user_init,
++      open:           daemon_open,
++      close:          NULL,
++      remove:         daemon_remove,
++      set_mtu:        daemon_set_mtu,
++      add_address:    NULL,
++      delete_address: NULL,
++      max_packet:     MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/fd.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,92 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <termios.h>
++#include "user.h"
++#include "user_util.h"
++#include "chan_user.h"
++
++struct fd_chan {
++      int fd;
++      int raw;
++      struct termios tt;
++};
++
++void *fd_init(char *str, int device, struct chan_opts *opts)
++{
++      struct fd_chan *data;
++      char *end;
++      int n;
++
++      if(*str != ':'){
++              printk("fd_init : channel type 'fd' must specify a file "
++                     "descriptor\n");
++              return(NULL);
++      }
++      str++;
++      n = strtoul(str, &end, 0);
++      if(*end != '\0'){
++              printk("fd_init : couldn't parse file descriptor '%s'\n", str);
++              return(NULL);
++      }
++      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      *data = ((struct fd_chan) { fd :        n,
++                                  raw :       opts->raw });
++      return(data);
++}
++
++int fd_open(int input, int output, int primary, void *d)
++{
++      struct fd_chan *data = d;
++
++      if(data->raw && isatty(data->fd)){
++              tcgetattr(data->fd, &data->tt);
++              raw(data->fd, 0);
++      }
++      return(data->fd);
++}
++
++void fd_close(int fd, void *d)
++{
++      struct fd_chan *data = d;
++
++      if(data->raw && isatty(fd)){
++              tcsetattr(fd, TCSAFLUSH, &data->tt);
++              data->raw = 0;
++      }
++}
++
++int fd_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct fd_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops fd_ops = {
++      init:           fd_init,
++      open:           fd_open,
++      close:          fd_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  fd_console_write,
++      window_size:    generic_window_size,
++      free:           generic_free,
++      winch:          1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/harddog_kern.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,192 @@
++/* UML hardware watchdog, shamelessly stolen from:
++ *
++ *    SoftDog 0.05:   A Software Watchdog Device
++ *
++ *    (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
++ *                            http://www.redhat.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.
++ *    
++ *    Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
++ *    warranty for any of this software. This material is provided 
++ *    "AS-IS" and at no charge.       
++ *
++ *    (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
++ *
++ *    Software only watchdog driver. Unlike its big brother the WDT501P
++ *    driver this won't always recover a failed machine.
++ *
++ *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
++ *    Modularised.
++ *    Added soft_margin; use upon insmod to change the timer delay.
++ *    NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
++ *        minors.
++ *
++ *  19980911 Alan Cox
++ *    Made SMP safe for 2.3.x
++ *
++ *  20011127 Joel Becker (jlbec@evilplan.org>
++ *    Added soft_noboot; Allows testing the softdog trigger without 
++ *    requiring a recompile.
++ *    Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
++ */
++ 
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include "helper.h"
++#include "mconsole.h"
++
++MODULE_LICENSE("GPL");
++
++static int timer_alive;
++
++static int harddog_in_fd = -1;
++static int harddog_out_fd = -1;
++
++/*
++ *    Allow only one person to hold it open
++ */
++ 
++extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
++
++static int harddog_open(struct inode *inode, struct file *file)
++{
++      int err;
++      char *sock = NULL;
++
++      if(timer_alive)
++              return -EBUSY;
++#ifdef CONFIG_HARDDOG_NOWAYOUT         
++      MOD_INC_USE_COUNT;
++#endif
++
++#ifdef CONFIG_MCONSOLE
++      sock = mconsole_notify_socket();
++#endif
++      err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
++      if(err) return(err);
++
++      timer_alive = 1;
++      return 0;
++}
++
++extern void stop_watchdog(int in_fd, int out_fd);
++
++static int harddog_release(struct inode *inode, struct file *file)
++{
++      /*
++       *      Shut off the timer.
++       */
++      lock_kernel();
++
++      stop_watchdog(harddog_in_fd, harddog_out_fd);
++      harddog_in_fd = -1;
++      harddog_out_fd = -1;
++
++      timer_alive=0;
++      unlock_kernel();
++      return 0;
++}
++
++extern int ping_watchdog(int fd);
++
++static ssize_t harddog_write(struct file *file, const char *data, size_t len,
++                           loff_t *ppos)
++{
++      /*  Can't seek (pwrite) on this device  */
++      if (ppos != &file->f_pos)
++              return -ESPIPE;
++
++      /*
++       *      Refresh the timer.
++       */
++      if(len)
++              return(ping_watchdog(harddog_out_fd));
++      return 0;
++}
++
++static int harddog_ioctl(struct inode *inode, struct file *file,
++                       unsigned int cmd, unsigned long arg)
++{
++      static struct watchdog_info ident = {
++              WDIOF_SETTIMEOUT,
++              0,
++              "UML Hardware Watchdog"
++      };
++      switch (cmd) {
++              default:
++                      return -ENOTTY;
++              case WDIOC_GETSUPPORT:
++                      if(copy_to_user((struct harddog_info *)arg, &ident,
++                                      sizeof(ident)))
++                              return -EFAULT;
++                      return 0;
++              case WDIOC_GETSTATUS:
++              case WDIOC_GETBOOTSTATUS:
++                      return put_user(0,(int *)arg);
++              case WDIOC_KEEPALIVE:
++                      return(ping_watchdog(harddog_out_fd));
++      }
++}
++
++static struct file_operations harddog_fops = {
++      owner:          THIS_MODULE,
++      write:          harddog_write,
++      ioctl:          harddog_ioctl,
++      open:           harddog_open,
++      release:        harddog_release,
++};
++
++static struct miscdevice harddog_miscdev = {
++      minor:          WATCHDOG_MINOR,
++      name:           "watchdog",
++      fops:           &harddog_fops,
++};
++
++static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
++
++static int __init harddog_init(void)
++{
++      int ret;
++
++      ret = misc_register(&harddog_miscdev);
++
++      if (ret)
++              return ret;
++
++      printk(banner);
++
++      return(0);
++}
++
++static void __exit harddog_exit(void)
++{
++      misc_deregister(&harddog_miscdev);
++}
++
++module_init(harddog_init);
++module_exit(harddog_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/harddog_user.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,134 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include "user_util.h"
++#include "user.h"
++#include "helper.h"
++#include "mconsole.h"
++#include "os.h"
++
++struct dog_data {
++      int stdin;
++      int stdout;
++      int close_me[2];
++};
++
++static void pre_exec(void *d)
++{
++      struct dog_data *data = d;
++
++      dup2(data->stdin, 0);
++      dup2(data->stdout, 1);
++      dup2(data->stdout, 2);
++      close(data->stdin);
++      close(data->stdout);
++      close(data->close_me[0]);
++      close(data->close_me[1]);
++}
++
++int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
++{
++      struct dog_data data;
++      int in_fds[2], out_fds[2], pid, n, err;
++      char pid_buf[sizeof("nnnnn\0")], c;
++      char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
++      char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, 
++                                NULL };
++      char **args = NULL;
++
++      err = os_pipe(in_fds, 1, 0);
++      if(err){
++              printk("harddog_open - os_pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++
++      err = os_pipe(out_fds, 1, 0);
++      if(err){
++              printk("harddog_open - os_pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++
++      data.stdin = out_fds[0];
++      data.stdout = in_fds[1];
++      data.close_me[0] = out_fds[1];
++      data.close_me[1] = in_fds[0];
++
++      if(sock != NULL){
++              mconsole_args[2] = sock;
++              args = mconsole_args;
++      }
++      else {
++              sprintf(pid_buf, "%d", tracing_pid);
++              args = pid_args;
++      }
++
++      pid = run_helper(pre_exec, &data, args, NULL);
++
++      close(out_fds[0]);
++      close(in_fds[1]);
++
++      if(pid < 0){
++              err = -pid;
++              printk("harddog_open - run_helper failed, errno = %d\n", err);
++              goto out;
++      }
++
++      n = read(in_fds[0], &c, sizeof(c));
++      if(n == 0){
++              printk("harddog_open - EOF on watchdog pipe\n");
++              helper_wait(pid);
++              err = -EIO;
++              goto out;
++      }
++      else if(n < 0){
++              printk("harddog_open - read of watchdog pipe failed, "
++                     "errno = %d\n", errno);
++              helper_wait(pid);
++              err = -errno;
++              goto out;
++      }
++      *in_fd_ret = in_fds[0];
++      *out_fd_ret = out_fds[1];
++      return(0);
++ out:
++      close(out_fds[1]);
++      close(in_fds[0]);
++      return(err);
++}
++
++void stop_watchdog(int in_fd, int out_fd)
++{
++      close(in_fd);
++      close(out_fd);
++}
++
++int ping_watchdog(int fd)
++{
++      int n;
++      char c = '\n';
++
++      n = write(fd, &c, sizeof(c));
++      if(n < sizeof(c)){
++              printk("ping_watchdog - write failed, errno = %d\n",
++                     errno);
++              return(-errno);
++      }
++      return 1;
++
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/hostaudio_kern.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,264 @@
++/* 
++ * Copyright (C) 2002 Steve Schmidtke 
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/module.h"
++#include "linux/version.h"
++#include "linux/init.h"
++#include "linux/slab.h"
++#include "linux/fs.h"
++#include "linux/sound.h"
++#include "linux/soundcard.h"
++#include "kern_util.h"
++#include "init.h"
++#include "hostaudio.h"
++
++char *dsp = HOSTAUDIO_DEV_DSP;
++char *mixer = HOSTAUDIO_DEV_MIXER;
++
++#ifndef MODULE
++static int set_dsp(char *name, int *add)
++{
++      dsp = uml_strdup(name);
++      return(0);
++}
++
++__uml_setup("dsp=", set_dsp,
++"dsp=<dsp device>\n"
++"    This is used to specify the host dsp device to the hostaudio driver.\n"
++"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
++);
++
++static int set_mixer(char *name, int *add)
++{
++      mixer = uml_strdup(name);
++      return(0);
++}
++
++__uml_setup("mixer=", set_mixer,
++"mixer=<mixer device>\n"
++"    This is used to specify the host mixer device to the hostaudio driver.\n"
++"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
++);
++#endif
++
++/* /dev/dsp file operations */
++
++static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
++                            loff_t *ppos)
++{
++        struct hostaudio_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostaudio: read called, count = %d\n", count);
++#endif
++
++        return(hostaudio_read_user(state, buffer, count, ppos));
++}
++
++static ssize_t hostaudio_write(struct file *file, const char *buffer, 
++                             size_t count, loff_t *ppos)
++{
++        struct hostaudio_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostaudio: write called, count = %d\n", count);
++#endif
++        return(hostaudio_write_user(state, buffer, count, ppos));
++}
++
++static unsigned int hostaudio_poll(struct file *file, 
++                                 struct poll_table_struct *wait)
++{
++        unsigned int mask = 0;
++
++#ifdef DEBUG
++        printk("hostaudio: poll called (unimplemented)\n");
++#endif
++
++        return(mask);
++}
++
++static int hostaudio_ioctl(struct inode *inode, struct file *file, 
++                         unsigned int cmd, unsigned long arg)
++{
++        struct hostaudio_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostaudio: ioctl called, cmd = %u\n", cmd);
++#endif
++
++        return(hostaudio_ioctl_user(state, cmd, arg));
++}
++
++static int hostaudio_open(struct inode *inode, struct file *file)
++{
++        struct hostaudio_state *state;
++        int r = 0, w = 0;
++        int ret;
++
++#ifdef DEBUG
++        printk("hostaudio: open called (host: %s)\n", dsp);
++#endif
++
++        state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
++        if(state == NULL) return(-ENOMEM);
++
++        if(file->f_mode & FMODE_READ) r = 1;
++        if(file->f_mode & FMODE_WRITE) w = 1;
++
++        ret = hostaudio_open_user(state, r, w, dsp);
++        if(ret < 0){
++              kfree(state);
++              return(ret);
++        }
++
++        file->private_data = state;
++        return(0);
++}
++
++static int hostaudio_release(struct inode *inode, struct file *file)
++{
++        struct hostaudio_state *state = file->private_data;
++        int ret;
++
++#ifdef DEBUG
++        printk("hostaudio: release called\n");
++#endif
++
++        ret = hostaudio_release_user(state);
++        kfree(state);
++
++        return(ret);
++}
++
++/* /dev/mixer file operations */
++
++static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, 
++                                unsigned int cmd, unsigned long arg)
++{
++        struct hostmixer_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostmixer: ioctl called\n");
++#endif
++
++        return(hostmixer_ioctl_mixdev_user(state, cmd, arg));
++}
++
++static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
++{
++        struct hostmixer_state *state;
++        int r = 0, w = 0;
++        int ret;
++
++#ifdef DEBUG
++        printk("hostmixer: open called (host: %s)\n", mixer);
++#endif
++
++        state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
++        if(state == NULL) return(-ENOMEM);
++
++        if(file->f_mode & FMODE_READ) r = 1;
++        if(file->f_mode & FMODE_WRITE) w = 1;
++
++        ret = hostmixer_open_mixdev_user(state, r, w, mixer);
++        
++        if(ret < 0){
++              kfree(state);
++              return(ret);
++        }
++
++        file->private_data = state;
++        return(0);
++}
++
++static int hostmixer_release(struct inode *inode, struct file *file)
++{
++        struct hostmixer_state *state = file->private_data;
++      int ret;
++
++#ifdef DEBUG
++        printk("hostmixer: release called\n");
++#endif
++
++        ret = hostmixer_release_mixdev_user(state);
++        kfree(state);
++
++        return(ret);
++}
++
++
++/* kernel module operations */
++
++static struct file_operations hostaudio_fops = {
++        owner:          THIS_MODULE,
++        llseek:         no_llseek,
++        read:           hostaudio_read,
++        write:          hostaudio_write,
++        poll:           hostaudio_poll,
++        ioctl:          hostaudio_ioctl,
++        mmap:           NULL,
++        open:           hostaudio_open,
++        release:        hostaudio_release,
++};
++
++static struct file_operations hostmixer_fops = {
++        owner:          THIS_MODULE,
++        llseek:         no_llseek,
++        ioctl:          hostmixer_ioctl_mixdev,
++        open:           hostmixer_open_mixdev,
++        release:        hostmixer_release,
++};
++
++struct {
++      int dev_audio;
++      int dev_mixer;
++} module_data;
++
++MODULE_AUTHOR("Steve Schmidtke");
++MODULE_DESCRIPTION("UML Audio Relay");
++MODULE_LICENSE("GPL");
++
++static int __init hostaudio_init_module(void)
++{
++        printk(KERN_INFO "UML Audio Relay\n");
++
++      module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
++        if(module_data.dev_audio < 0){
++                printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
++                return -ENODEV;
++        }
++
++      module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
++        if(module_data.dev_mixer < 0){
++                printk(KERN_ERR "hostmixer: couldn't register mixer "
++                     "device!\n");
++                unregister_sound_dsp(module_data.dev_audio);
++                return -ENODEV;
++        }
++
++        return 0;
++}
++
++static void __exit hostaudio_cleanup_module (void)
++{
++       unregister_sound_mixer(module_data.dev_mixer);
++       unregister_sound_dsp(module_data.dev_audio);
++}
++
++module_init(hostaudio_init_module);
++module_exit(hostaudio_cleanup_module);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/hostaudio_user.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,149 @@
++/* 
++ * Copyright (C) 2002 Steve Schmidtke 
++ * Licensed under the GPL
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/ioctl.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <errno.h>
++#include "hostaudio.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "os.h"
++
++/* /dev/dsp file operations */
++
++ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, 
++                          size_t count, loff_t *ppos)
++{
++      ssize_t ret;
++
++#ifdef DEBUG
++        printk("hostaudio: read_user called, count = %d\n", count);
++#endif
++
++        ret = read(state->fd, buffer, count);
++
++        if(ret < 0) return(-errno);
++        return(ret);
++}
++
++ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
++                           size_t count, loff_t *ppos)
++{
++      ssize_t ret;
++
++#ifdef DEBUG
++        printk("hostaudio: write_user called, count = %d\n", count);
++#endif
++
++        ret = write(state->fd, buffer, count);
++
++        if(ret < 0) return(-errno);
++        return(ret);
++}
++
++int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, 
++                       unsigned long arg)
++{
++      int ret;
++#ifdef DEBUG
++        printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
++#endif
++
++        ret = ioctl(state->fd, cmd, arg);
++      
++        if(ret < 0) return(-errno);
++        return(ret);
++}
++
++int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
++{
++#ifdef DEBUG
++        printk("hostaudio: open_user called\n");
++#endif
++
++        state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
++
++        if(state->fd >= 0) return(0);
++
++        printk("hostaudio_open_user failed to open '%s', errno = %d\n",
++             dsp, errno);
++        
++        return(-errno); 
++}
++
++int hostaudio_release_user(struct hostaudio_state *state)
++{
++#ifdef DEBUG
++        printk("hostaudio: release called\n");
++#endif
++        if(state->fd >= 0){
++              close(state->fd);
++              state->fd=-1;
++        }
++
++        return(0);
++}
++
++/* /dev/mixer file operations */
++
++int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
++                              unsigned int cmd, unsigned long arg)
++{
++      int ret;
++#ifdef DEBUG
++        printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
++#endif
++
++        ret = ioctl(state->fd, cmd, arg);
++      if(ret < 0) 
++              return(-errno);
++      return(ret);
++}
++
++int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
++                             char *mixer)
++{
++#ifdef DEBUG
++        printk("hostmixer: open_user called\n");
++#endif
++
++        state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
++
++        if(state->fd >= 0) return(0);
++
++        printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n",
++             mixer, errno);
++        
++        return(-errno); 
++}
++
++int hostmixer_release_mixdev_user(struct hostmixer_state *state)
++{
++#ifdef DEBUG
++        printk("hostmixer: release_user called\n");
++#endif
++
++        if(state->fd >= 0){
++              close(state->fd);
++              state->fd = -1;
++        }
++
++        return 0;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/line.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,479 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/list.h"
++#include "linux/devfs_fs_kernel.h"
++#include "asm/irq.h"
++#include "chan_kern.h"
++#include "irq_user.h"
++#include "line.h"
++#include "kern.h"
++#include "user_util.h"
++#include "os.h"
++
++#define LINE_BUFSIZE 4096
++
++void line_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct line *dev = data;
++
++      if(dev->count > 0) 
++              chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, 
++                             dev);
++}
++
++void line_timer_cb(void *arg)
++{
++      struct line *dev = arg;
++
++      line_interrupt(dev->driver->read_irq, dev, NULL);
++}
++
++void buffer_data(struct line *line, const char *buf, int len)
++{
++      int end;
++
++      if(line->buffer == NULL){
++              line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
++              if(line->buffer == NULL){
++                      printk("buffer_data - atomic allocation failed\n");
++                      return;
++              }
++              line->head = line->buffer;
++              line->tail = line->buffer;
++      }
++      end = line->buffer + LINE_BUFSIZE - line->tail;
++      if(len < end){
++              memcpy(line->tail, buf, len);
++              line->tail += len;
++      }
++      else {
++              memcpy(line->tail, buf, end);
++              buf += end;
++              len -= end;
++              memcpy(line->buffer, buf, len);
++              line->tail = line->buffer + len;
++      }
++}
++
++static int flush_buffer(struct line *line)
++{
++      int n, count;
++
++      if((line->buffer == NULL) || (line->head == line->tail)) return(1);
++
++      if(line->tail < line->head){
++              count = line->buffer + LINE_BUFSIZE - line->head;
++              n = write_chan(&line->chan_list, line->head, count,
++                             line->driver->write_irq);
++              if(n < 0) return(n);
++              if(n == count) line->head = line->buffer;
++              else {
++                      line->head += n;
++                      return(0);
++              }
++      }
++
++      count = line->tail - line->head;
++      n = write_chan(&line->chan_list, line->head, count, 
++                     line->driver->write_irq);
++      if(n < 0) return(n);
++
++      line->head += n;
++      return(line->head == line->tail);
++}
++
++int line_write(struct line *lines, struct tty_struct *tty, const char *buf, 
++             int len)
++{
++      struct line *line;
++      unsigned long flags;
++      int n, err, i;
++
++      if(tty->stopped) return 0;
++
++      i = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[i];
++
++      if(line->head != line->tail){
++              local_irq_save(flags);
++              buffer_data(line, buf, len);
++              err = flush_buffer(line);
++              local_irq_restore(flags);
++              if(err <= 0) return(len);
++      }
++      else {
++              n = write_chan(&line->chan_list, buf, len, 
++                             line->driver->write_irq);
++              if(n < 0) return(n);
++              if(n < len) buffer_data(line, buf + n, len - n);
++      }
++      return(len);
++}
++
++void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct line *dev = data;
++      struct tty_struct *tty = dev->tty;
++      int err;
++
++      err = flush_buffer(dev);
++      if(err == 0) return;
++      else if(err < 0){
++              dev->head = dev->buffer;
++              dev->tail = dev->buffer;
++      }
++
++      if(tty == NULL) return;
++
++      if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
++         (tty->ldisc.write_wakeup != NULL))
++              (tty->ldisc.write_wakeup)(tty);
++      
++      /* BLOCKING mode
++       * In blocking mode, everything sleeps on tty->write_wait.
++       * Sleeping in the console driver would break non-blocking
++       * writes.
++       */
++
++      if (waitqueue_active(&tty->write_wait))
++              wake_up_interruptible(&tty->write_wait);
++
++}
++
++int line_write_room(struct tty_struct *tty)
++{
++      struct line *dev = tty->driver_data;
++      int n;
++
++      if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
++
++      n = dev->head - dev->tail;
++      if(n <= 0) n = LINE_BUFSIZE + n;
++      return(n - 1);
++}
++
++int line_setup_irq(int fd, int input, int output, void *data)
++{
++      struct line *line = data;
++      struct line_driver *driver = line->driver;
++      int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
++
++      if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, 
++                                     line_interrupt, flags, 
++                                     driver->read_irq_name, line);
++      if(err) return(err);
++      if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, 
++                                      line_write_interrupt, flags, 
++                                      driver->write_irq_name, line);
++      line->have_irq = 1;
++      return(err);
++}
++
++void line_disable(struct line *line, int current_irq)
++{
++      if(!line->have_irq) return;
++
++      if(line->driver->read_irq == current_irq)
++              free_irq_later(line->driver->read_irq, line);
++      else
++              free_irq(line->driver->read_irq, line);
++
++      if(line->driver->write_irq == current_irq)
++              free_irq_later(line->driver->write_irq, line);
++      else
++              free_irq(line->driver->write_irq, line);
++
++      line->have_irq = 0;
++}
++
++int line_open(struct line *lines, struct tty_struct *tty,
++            struct chan_opts *opts)
++{
++      struct line *line;
++      int n, err = 0;
++
++      if(tty == NULL) n = 0;
++      else n = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[n];
++
++      down(&line->sem);
++      if(line->count == 0){
++              if(!line->valid){
++                      err = -ENODEV;
++                      goto out;
++              }
++              if(list_empty(&line->chan_list)){
++                      err = parse_chan_pair(line->init_str, &line->chan_list,
++                                            line->init_pri, n, opts);
++                      if(err) goto out;
++                      err = open_chan(&line->chan_list);
++                      if(err) goto out;
++              }
++              enable_chan(&line->chan_list, line);
++              INIT_TQUEUE(&line->task, line_timer_cb, line);
++      }
++
++      if(!line->sigio){
++              chan_enable_winch(&line->chan_list, line);
++              line->sigio = 1;
++      }
++
++      /* This is outside the if because the initial console is opened
++       * with tty == NULL
++       */
++      line->tty = tty;
++
++      if(tty != NULL){
++              tty->driver_data = line;
++              chan_window_size(&line->chan_list, &tty->winsize.ws_row, 
++                               &tty->winsize.ws_col);
++      }
++
++      line->count++;
++ out:
++      up(&line->sem);
++      return(err);
++}
++
++void line_close(struct line *lines, struct tty_struct *tty)
++{
++      struct line *line;
++      int n;
++
++      if(tty == NULL) n = 0;
++      else n = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[n];
++
++      line->count--;
++
++      /* I don't like this, but I can't think of anything better.  What's
++       * going on is that the tty is in the process of being closed for
++       * the last time.  Its count hasn't been dropped yet, so it's still
++       * at 1.  This may happen when line->count != 0 because of the initial
++       * console open (without a tty) bumping it up to 1.
++       */
++      if((line->tty != NULL) && (line->tty->count == 1))
++              line->tty = NULL;
++      if(line->count == 0)
++              line_disable(line, -1);
++}
++
++void close_lines(struct line *lines, int nlines)
++{
++      int i;
++
++      for(i = 0; i < nlines; i++)
++              close_chan(&lines[i].chan_list);
++}
++
++void line_setup(struct line *lines, int num, char *init)
++{
++      int i, n;
++      char *end;
++
++      if(*init == '=') n = -1;
++      else {
++              n = simple_strtoul(init, &end, 0);
++              if(*end != '='){
++                      printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
++                             init);
++                      return;
++              }
++              init = end;
++      }
++      init++;
++      if(n == -1){
++              for(i = 0; i < num; i++){
++                      if(lines[i].init_pri <= INIT_ALL){
++                              lines[i].init_pri = INIT_ALL;
++                              if(!strcmp(init, "none")) lines[i].valid = 0;
++                              else {
++                                      lines[i].init_str = init;
++                                      lines[i].valid = 1;
++                              }
++                      }
++              }
++      }
++      else if(lines[n].init_pri <= INIT_ONE){
++              lines[n].init_pri = INIT_ONE;
++              if(!strcmp(init, "none")) lines[n].valid = 0;
++              else {
++                      lines[n].init_str = init;
++                      lines[n].valid = 1;
++              }
++      }
++}
++
++void line_register_devfs(struct lines *set, struct line_driver *line_driver, 
++                       struct tty_driver *driver, struct line *lines,
++                       int nlines)
++{
++      int err, i, n;
++      char *from, *to;
++
++      driver->driver_name = line_driver->name;
++      driver->name = line_driver->devfs_name;
++      driver->major = line_driver->major;
++      driver->minor_start = line_driver->minor_start;
++      driver->type = line_driver->type;
++      driver->subtype = line_driver->subtype;
++      driver->magic = TTY_DRIVER_MAGIC;
++      driver->flags = TTY_DRIVER_REAL_RAW;
++
++      n = set->num;
++      driver->num = n;
++      driver->table = kmalloc(n * sizeof(driver->table[0]), GFP_KERNEL);
++      driver->termios = kmalloc(n * sizeof(driver->termios[0]), GFP_KERNEL);
++      driver->termios_locked = kmalloc(n * sizeof(driver->termios_locked[0]),
++                                       GFP_KERNEL);
++      if((driver->table == NULL) || (driver->termios == NULL) ||
++         (driver->termios_locked == NULL))
++              panic("Failed to allocate driver table");
++
++      memset(driver->table, 0, n * sizeof(driver->table[0]));
++      memset(driver->termios, 0, n * sizeof(driver->termios[0]));
++      memset(driver->termios_locked, 0, 
++             n * sizeof(driver->termios_locked[0]));
++
++      driver->write_room = line_write_room;
++      driver->init_termios = tty_std_termios;
++
++      driver->refcount = &set->refcount;
++
++      if (tty_register_driver(driver))
++              panic("line_register_devfs : Couldn't register driver\n");
++
++      from = line_driver->symlink_from;
++      to = line_driver->symlink_to;
++      err = devfs_mk_symlink(NULL, from, 0, to, NULL, NULL);
++      if(err) printk("Symlink creation from /dev/%s to /dev/%s "
++                     "returned %d\n", from, to, err);
++
++      for(i = 0; i < nlines; i++){
++              if(!lines[i].valid) 
++                      tty_unregister_devfs(driver, driver->minor_start + i);
++      }
++}
++
++void lines_init(struct line *lines, int nlines)
++{
++      int i;
++
++      for(i = 0; i < nlines; i++){
++              INIT_LIST_HEAD(&lines[i].chan_list);
++              sema_init(&lines[i].sem, 1);
++      }
++}
++
++struct winch {
++      struct list_head list;
++      int fd;
++      int tty_fd;
++      int pid;
++      struct line *line;
++};
++
++void winch_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct winch *winch = data;
++      struct tty_struct *tty;
++      int err;
++      char c;
++
++      err = generic_read(winch->fd, &c, NULL);
++      if(err < 0){
++              if(err != -EAGAIN){
++                      printk("winch_interrupt : read failed, errno = %d\n", 
++                             -err);
++                      printk("fd %d is losing SIGWINCH support\n", 
++                             winch->tty_fd);
++                      free_irq(irq, data);
++                      return;
++              }
++              goto out;
++      }
++      tty = winch->line->tty;
++      if(tty != NULL){
++              chan_window_size(&winch->line->chan_list, 
++                               &tty->winsize.ws_row, 
++                               &tty->winsize.ws_col);
++              kill_pg(tty->pgrp, SIGWINCH, 1);
++      }
++ out:
++      reactivate_fd(winch->fd, WINCH_IRQ);
++}
++
++LIST_HEAD(winch_handlers);
++
++void register_winch_irq(int fd, int tty_fd, int pid, void *line)
++{
++      struct winch *winch;
++
++      winch = kmalloc(sizeof(*winch), GFP_KERNEL);
++      if(winch == NULL){
++              printk("register_winch_irq - kmalloc failed\n");
++              return;
++      }
++      *winch = ((struct winch) { list :       LIST_HEAD_INIT(winch->list),
++                                 fd :         fd,
++                                 tty_fd :     tty_fd,
++                                 pid :        pid,
++                                 line :       line });
++      list_add(&winch->list, &winch_handlers);
++      if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
++                        "winch", winch) < 0)
++              printk("register_winch_irq - failed to register IRQ\n");
++}
++
++static void winch_cleanup(void)
++{
++      struct list_head *ele;
++      struct winch *winch;
++
++      list_for_each(ele, &winch_handlers){
++              winch = list_entry(ele, struct winch, list);
++              close(winch->fd);
++              free_irq_by_fd(winch->fd);
++              if(winch->pid != -1) os_kill_process(winch->pid);
++      }
++}
++
++__uml_exitcall(winch_cleanup);
++
++char *add_xterm_umid(char *base)
++{
++      char *umid, *title;
++      int len;
++
++      umid = get_umid(1);
++      if(umid == NULL) return(base);
++      
++      len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
++      title = kmalloc(len, GFP_KERNEL);
++      if(title == NULL){
++              printk("Failed to allocate buffer for xterm title\n");
++              return(base);
++      }
++
++      strncpy(title, base, len);
++      len -= strlen(title);
++      snprintf(&title[strlen(title)], len, " (%s)", umid);
++      return(title);
++}
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/Makefile     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,84 @@
++# 
++# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := drivers.o 
++
++CHAN_OBJS := chan_kern.o chan_user.o line.o 
++
++list-multi := slip.o daemon.o mcast.o mconsole.o net.o ubd.o hostaudio.o \
++      port.o harddog.o
++
++slip-objs := slip_kern.o slip_user.o
++daemon-objs := daemon_kern.o daemon_user.o
++mcast-objs := mcast_kern.o mcast_user.o
++net-objs := net_kern.o net_user.o
++mconsole-objs := mconsole_kern.o mconsole_user.o
++hostaudio-objs := hostaudio_kern.o hostaudio_user.o
++ubd-objs := ubd_kern.o ubd_user.o
++port-objs := port_kern.o port_user.o
++harddog-objs := harddog_kern.o harddog_user.o
++
++export-objs := mconsole_kern.o
++
++obj-y = 
++obj-$(CONFIG_SSL) += ssl.o 
++obj-$(CONFIG_UML_NET_SLIP) += slip.o
++obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
++obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
++obj-$(CONFIG_UML_NET) += net.o 
++obj-$(CONFIG_MCONSOLE) += mconsole.o
++obj-$(CONFIG_MMAPPER) += mmapper_kern.o 
++obj-$(CONFIG_BLK_DEV_UBD) += ubd.o 
++obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
++obj-$(CONFIG_FD_CHAN) += fd.o 
++obj-$(CONFIG_NULL_CHAN) += null.o 
++obj-$(CONFIG_PORT_CHAN) += port.o
++obj-$(CONFIG_PTY_CHAN) += pty.o
++obj-$(CONFIG_TTY_CHAN) += tty.o 
++obj-$(CONFIG_XTERM_CHAN) += xterm.o
++obj-$(CONFIG_UML_WATCHDOG) += harddog.o
++
++obj-y += stdio_console.o $(CHAN_OBJS)
++
++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
++
++USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) fd.o null.o pty.o \
++      tty.o xterm.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean:
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper:
++
++daemon.o : $(daemon-objs)
++
++slip.o : $(slip-objs)
++
++mcast.o : $(mcast-objs)
++
++mconsole.o : $(mconsole-objs)
++
++net.o : $(net-objs)
++
++hostaudio.o : $(hostaudio-objs)
++
++ubd.o : $(ubd-objs)
++
++port.o : $(port-objs)
++
++harddog.o : $(harddog-objs)
++
++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
++      $(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs)
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mcast.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,32 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct mcast_data {
++      char *addr;
++      unsigned short port;
++      void *mcast_addr;
++      int ttl;
++      unsigned char hwaddr[ETH_ADDR_LEN];
++      int hw_setup;
++      void *dev;
++};
++
++extern struct net_user_info mcast_user_info;
++
++extern int mcast_user_write(int fd, void *buf, int len, 
++                          struct mcast_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mcast_kern.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,159 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ */
++
++#include "linux/kernel.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/in.h"
++#include "linux/inet.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "mcast.h"
++#include "mcast_kern.h"
++
++struct mcast_data mcast_priv[MAX_UML_NETDEV] = {
++      [ 0 ... MAX_UML_NETDEV - 1 ] =
++      {
++              addr:           "239.192.168.1",
++              port:           1102,
++              ttl:            1,
++      }
++};
++
++struct net_device *mcast_init(int private_size, int index)
++{
++      struct net_device *dev;
++      struct uml_net_private *pri;
++      struct mcast_data *dpri;
++
++      dev = init_etherdev(NULL, private_size);
++      if (!dev) 
++              return NULL;
++
++      pri = dev->priv;
++      dpri = (struct mcast_data *) pri->user;
++      *dpri = mcast_priv[index];
++      printk("mcast backend ");
++      printk("multicast adddress: %s:%u, TTL:%u ",
++             dpri->addr, dpri->port, dpri->ttl);
++
++      printk("\n");
++      return(dev);
++}
++
++static unsigned short mcast_protocol(struct sk_buff *skb)
++{
++      return eth_type_trans(skb, skb->dev);
++}
++
++static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_recvfrom(fd, (*skb)->mac.raw, 
++                          (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int mcast_write(int fd, struct sk_buff **skb,
++                      struct uml_net_private *lp)
++{
++      return mcast_user_write(fd, (*skb)->data, (*skb)->len, 
++                               (struct mcast_data *) &lp->user);
++}
++
++static struct net_kern_info mcast_kern_info = {
++      init:                   mcast_init,
++      protocol:               mcast_protocol,
++      read:                   mcast_read,
++      write:                  mcast_write,
++};
++
++static int mcast_count = 0;
++
++int mcast_setup(char *str, struct uml_net *dev)
++{
++      int err, n = mcast_count;
++      int num = 0;
++      char *p1, *p2;
++
++      dev->user = &mcast_user_info;
++      dev->kern = &mcast_kern_info;
++      dev->private_size = sizeof(struct mcast_data);
++      dev->transport_index = mcast_count++;
++
++      /* somewhat more sophisticated parser, needed for in_aton */
++
++      p1 = str;
++      if (*str == ',')
++              p1++;
++      while (p1 && *p1) {
++              if ((p2 = strchr(p1, ',')))
++                      *p2++ = '\0';
++              if (strlen(p1) > 0) {
++                      switch (num) {
++                      case 0:
++                              /* First argument: Ethernet address */
++                              err = setup_etheraddr(p1, dev->mac);
++                              if (!err) 
++                                      dev->have_mac = 1;
++                              break;
++                      case 1:
++                              /* Second argument: Multicast group */
++                              mcast_priv[n].addr = p1;
++                              break;
++                      case 2:
++                              /* Third argument: Port number */
++                              mcast_priv[n].port = 
++                                      htons(simple_strtoul(p1, NULL, 10));
++                              break;
++                      case 3:
++                              /* Fourth argument: TTL */
++                              mcast_priv[n].ttl = 
++                                              simple_strtoul(p1, NULL, 10);
++                              break;
++                      }
++              }
++              p1 = p2;
++              num++;
++      }
++
++      printk(KERN_INFO "Configured mcast device: %s:%u-%u\n",
++              mcast_priv[n].addr, mcast_priv[n].port,
++              mcast_priv[n].ttl);
++
++      return(0);
++}
++
++static struct transport mcast_transport = {
++      list :  LIST_HEAD_INIT(mcast_transport.list),
++      name :  "mcast",
++      setup : mcast_setup
++};
++
++static int register_mcast(void)
++{
++      register_transport(&mcast_transport);
++      return(1);
++}
++
++__initcall(register_mcast);
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mcast_kern.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,8 @@
++#ifndef __UM_MCAST_KERN_H
++#define __UM_MCAST_KERN_H
++
++#include "net_kern.h"
++
++extern int mcast_setup(char *arg, struct uml_net *dev);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mcast_user.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,175 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ *
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <linux/inet.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include <netinet/in.h>
++#include "net_user.h"
++#include "mcast.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++static struct sockaddr_in *new_addr(char *addr, unsigned short port)
++{
++      struct sockaddr_in *sin;
++
++      sin = um_kmalloc(sizeof(struct sockaddr_in));
++      if(sin == NULL){
++              printk("new_addr: allocation of sockaddr_in failed\n");
++              return(NULL);
++      }
++      sin->sin_family = AF_INET;
++      sin->sin_addr.s_addr = in_aton(addr);
++      sin->sin_port = port;
++      return(sin);
++}
++
++static void mcast_user_init(void *data, void *dev)
++{
++      struct mcast_data *pri = data;
++
++      pri->mcast_addr = new_addr(pri->addr, pri->port);
++      pri->dev = dev;
++}
++
++static int mcast_open(void *data)
++{
++      struct mcast_data *pri = data;
++      struct sockaddr_in *sin = pri->mcast_addr;
++      struct ip_mreq mreq;
++      int fd, yes = 1;
++
++
++      if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
++              fd = -EINVAL;
++              goto out;
++      }
++
++      if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
++              printk("mcast_open : data socket failed, errno = %d\n", 
++                     errno);
++              fd = -ENOMEM;
++              goto out;
++      }
++
++      if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
++              printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
++                      errno);
++              close(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* set ttl according to config */
++      if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
++                     sizeof(pri->ttl)) < 0) {
++              printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
++                      errno);
++              close(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* set LOOP, so data does get fed back to local sockets */
++      if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
++              printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
++                      errno);
++              close(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* bind socket to mcast address */
++      if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
++              printk("mcast_open : data bind failed, errno = %d\n", errno);
++              close(fd);
++              fd = -EINVAL;
++              goto out;
++      }               
++      
++      /* subscribe to the multicast group */
++      mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
++      mreq.imr_interface.s_addr = 0;
++      if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, 
++                     &mreq, sizeof(mreq)) < 0) {
++              printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
++                      errno);
++              printk("There appears not to be a multicast-capable network "
++                     "interface on the host.\n");
++              printk("eth0 should be configured in order to use the "
++                     "multicast transport.\n");
++              close(fd);
++              fd = -EINVAL;
++      }
++
++ out:
++      return(fd);
++}
++
++static void mcast_close(int fd, void *data)
++{
++      struct ip_mreq mreq;
++      struct mcast_data *pri = data;
++      struct sockaddr_in *sin = pri->mcast_addr;
++
++      mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
++      mreq.imr_interface.s_addr = 0;
++      if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
++                     &mreq, sizeof(mreq)) < 0) {
++              printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
++                      errno);
++      }
++
++      close(fd);
++}
++
++int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
++{
++      struct sockaddr_in *data_addr = pri->mcast_addr;
++
++      return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
++}
++
++static int mcast_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info mcast_user_info = {
++      init:           mcast_user_init,
++      open:           mcast_open,
++      close:          mcast_close,
++      remove:         NULL,
++      set_mtu:        mcast_set_mtu,
++      add_address:    NULL,
++      delete_address: NULL,
++      max_packet:     MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mconsole_kern.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,373 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/slab.h"
++#include "linux/init.h"
++#include "linux/notifier.h"
++#include "linux/reboot.h"
++#include "linux/utsname.h"
++#include "linux/ctype.h"
++#include "linux/interrupt.h"
++#include "linux/sysrq.h"
++#include "linux/tqueue.h"
++#include "linux/module.h"
++#include "linux/proc_fs.h"
++#include "asm/irq.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mconsole.h"
++#include "mconsole_kern.h"
++#include "irq_user.h"
++#include "init.h"
++#include "os.h"
++#include "umid.h"
++
++static int do_unlink_socket(struct notifier_block *notifier, 
++                          unsigned long what, void *data)
++{
++      return(mconsole_unlink_socket());
++}
++
++
++static struct notifier_block reboot_notifier = {
++      notifier_call:          do_unlink_socket,
++      priority:               0,
++};
++
++LIST_HEAD(mc_requests);
++
++void mc_task_proc(void *unused)
++{
++      struct mconsole_entry *req;
++      unsigned long flags;
++      int done;
++
++      do {
++              save_flags(flags);
++              req = list_entry(mc_requests.next, struct mconsole_entry, 
++                               list);
++              list_del(&req->list);
++              done = list_empty(&mc_requests);
++              restore_flags(flags);
++              req->request.cmd->handler(&req->request);
++              kfree(req);
++      } while(!done);
++}
++
++struct tq_struct mconsole_task = {
++      routine:        mc_task_proc,
++      data:           NULL
++};
++
++void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      int fd;
++      struct mconsole_entry *new;
++      struct mc_request req;
++
++      fd = (int) dev_id;
++      while (mconsole_get_request(fd, &req)){
++              if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
++              else {
++                      new = kmalloc(sizeof(req), GFP_ATOMIC);
++                      if(new == NULL)
++                              mconsole_reply(&req, "Out of memory", 1, 0);
++                      else {
++                              new->request = req;
++                              list_add(&new->list, &mc_requests);
++                      }
++              }
++      }
++      if(!list_empty(&mc_requests)) schedule_task(&mconsole_task);
++      reactivate_fd(fd, MCONSOLE_IRQ);
++}
++
++void mconsole_version(struct mc_request *req)
++{
++      char version[256];
++
++      sprintf(version, "%s %s %s %s %s", system_utsname.sysname, 
++              system_utsname.nodename, system_utsname.release, 
++              system_utsname.version, system_utsname.machine);
++      mconsole_reply(req, version, 0, 0);
++}
++
++#define UML_MCONSOLE_HELPTEXT \
++"Commands:
++    version - Get kernel version
++    help - Print this message
++    halt - Halt UML
++    reboot - Reboot UML
++    config <dev>=<config> - Add a new device to UML; 
++      same syntax as command line
++    remove <dev> - Remove a device from UML
++    sysrq <letter> - Performs the SysRq action controlled by the letter
++    cad - invoke the Ctl-Alt-Del handler
++"
++
++void mconsole_help(struct mc_request *req)
++{
++      mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
++}
++
++void mconsole_halt(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      machine_halt();
++}
++
++void mconsole_reboot(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      machine_restart(NULL);
++}
++
++extern void ctrl_alt_del(void);
++
++void mconsole_cad(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      ctrl_alt_del();
++}
++
++void mconsole_go(struct mc_request *req)
++{
++      mconsole_reply(req, "Not stopped", 1, 0);
++}
++
++void mconsole_stop(struct mc_request *req)
++{
++      deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
++      os_set_fd_block(req->originating_fd, 1);
++      mconsole_reply(req, "", 0, 0);
++      while(mconsole_get_request(req->originating_fd, req)){
++              if(req->cmd->handler == mconsole_go) break;
++              (*req->cmd->handler)(req);
++      }
++      os_set_fd_block(req->originating_fd, 0);
++      reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
++      mconsole_reply(req, "", 0, 0);
++}
++
++LIST_HEAD(mconsole_devices);
++
++void mconsole_register_dev(struct mc_device *new)
++{
++      list_add(&new->list, &mconsole_devices);
++}
++
++static struct mc_device *mconsole_find_dev(char *name)
++{
++      struct list_head *ele;
++      struct mc_device *dev;
++
++      list_for_each(ele, &mconsole_devices){
++              dev = list_entry(ele, struct mc_device, list);
++              if(!strncmp(name, dev->name, strlen(dev->name)))
++                      return(dev);
++      }
++      return(NULL);
++}
++
++void mconsole_config(struct mc_request *req)
++{
++      struct mc_device *dev;
++      char *ptr = req->request.data;
++      int err;
++
++      ptr += strlen("config");
++      while(isspace(*ptr)) ptr++;
++      dev = mconsole_find_dev(ptr);
++      if(dev == NULL){
++              mconsole_reply(req, "Bad configuration option", 1, 0);
++              return;
++      }
++      err = (*dev->config)(&ptr[strlen(dev->name)]);
++      mconsole_reply(req, "", err, 0);
++}
++
++void mconsole_remove(struct mc_request *req)
++{
++      struct mc_device *dev;  
++      char *ptr = req->request.data;
++      int err;
++
++      ptr += strlen("remove");
++      while(isspace(*ptr)) ptr++;
++      dev = mconsole_find_dev(ptr);
++      if(dev == NULL){
++              mconsole_reply(req, "Bad remove option", 1, 0);
++              return;
++      }
++      err = (*dev->remove)(&ptr[strlen(dev->name)]);
++      mconsole_reply(req, "", err, 0);
++}
++
++#ifdef CONFIG_MAGIC_SYSRQ
++void mconsole_sysrq(struct mc_request *req)
++{
++      char *ptr = req->request.data;
++
++      ptr += strlen("sysrq");
++      while(isspace(*ptr)) ptr++;
++
++      handle_sysrq(*ptr, &current->thread.regs, NULL, NULL);
++      mconsole_reply(req, "", 0, 0);
++}
++#else
++void mconsole_sysrq(struct mc_request *req)
++{
++      mconsole_reply(req, "Sysrq not compiled in", 1, 0);
++}
++#endif
++
++static char *notify_socket = NULL;
++
++int mconsole_init(void)
++{
++      int err, sock;
++      char file[256];
++
++      if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
++      snprintf(mconsole_socket_name, sizeof(file), "%s", file);
++
++      sock = create_unix_socket(file, sizeof(file));
++      if (sock < 0){
++              printk("Failed to initialize management console\n");
++              return(1);
++      }
++
++      register_reboot_notifier(&reboot_notifier);
++
++      err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
++                           SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
++                           "mconsole", (void *)sock);
++      if (err){
++              printk("Failed to get IRQ for management console\n");
++              return(1);
++      }
++
++      if(notify_socket != NULL){
++              notify_socket = uml_strdup(notify_socket);
++              if(notify_socket != NULL)
++                      mconsole_notify(notify_socket, MCONSOLE_SOCKET,
++                                      mconsole_socket_name, 
++                                      strlen(mconsole_socket_name) + 1);
++              else printk(KERN_ERR "mconsole_setup failed to strdup "
++                          "string\n");
++      }
++
++      printk("mconsole (version %d) initialized on %s\n", 
++             MCONSOLE_VERSION, mconsole_socket_name);
++      return(0);
++}
++
++__initcall(mconsole_init);
++
++static int write_proc_mconsole(struct file *file, const char *buffer,
++                             unsigned long count, void *data)
++{
++      char *buf;
++
++      buf = kmalloc(count + 1, GFP_KERNEL);
++      if(buf == NULL) 
++              return(-ENOMEM);
++
++      if(copy_from_user(buf, buffer, count))
++              return(-EFAULT);
++      buf[count] = '\0';
++
++      mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
++      return(count);
++}
++
++static int create_proc_mconsole(void)
++{
++      struct proc_dir_entry *ent;
++
++      if(notify_socket == NULL) return(0);
++
++      ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
++      if(ent == NULL){
++              printk("create_proc_mconsole : create_proc_entry failed\n");
++              return(0);
++      }
++
++      ent->read_proc = NULL;
++      ent->write_proc = write_proc_mconsole;
++      return(0);
++}
++
++__initcall(create_proc_mconsole);
++
++#define NOTIFY "=notify:"
++
++static int mconsole_setup(char *str)
++{
++      if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
++              str += strlen(NOTIFY);
++              notify_socket = str;
++      }
++      else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
++      return(1);
++}
++
++__setup("mconsole", mconsole_setup);
++
++__uml_help(mconsole_setup,
++"mconsole=notify:<socket>\n"
++"    Requests that the mconsole driver send a message to the named Unix\n"
++"    socket containing the name of the mconsole socket.  This also serves\n"
++"    to notify outside processes when UML has booted far enough to respond\n"
++"    to mconsole requests.\n\n"
++);
++
++static int notify_panic(struct notifier_block *self, unsigned long unused1,
++                      void *ptr)
++{
++      char *message = ptr;
++
++      if(notify_socket == NULL) return(0);
++
++      mconsole_notify(notify_socket, MCONSOLE_PANIC, message, 
++                      strlen(message) + 1);
++      return(0);
++}
++
++static struct notifier_block panic_exit_notifier = {
++      notifier_call :         notify_panic,
++      next :                  NULL,
++      priority :              1
++};
++
++static int add_notifier(void)
++{
++      notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
++      return(0);
++}
++
++__initcall(add_notifier);
++
++char *mconsole_notify_socket(void)
++{
++      return(notify_socket);
++}
++
++EXPORT_SYMBOL(mconsole_notify_socket);
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mconsole_user.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,206 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <sys/un.h>
++#include <unistd.h>
++#include "user.h"
++#include "mconsole.h"
++#include "umid.h"
++
++static struct mconsole_command commands[] = {
++      { "version", mconsole_version, 1 },
++      { "halt", mconsole_halt, 0 },
++      { "reboot", mconsole_reboot, 0 },
++      { "config", mconsole_config, 0 },
++      { "remove", mconsole_remove, 0 },
++      { "sysrq", mconsole_sysrq, 1 },
++      { "help", mconsole_help, 1 },
++      { "cad", mconsole_cad, 1 },
++      { "stop", mconsole_stop, 0 },
++      { "go", mconsole_go, 1 },
++};
++
++char mconsole_socket_name[256];
++
++int mconsole_reply_v0(struct mc_request *req, char *reply)
++{
++        struct iovec iov;
++        struct msghdr msg;
++
++        iov.iov_base = reply;
++        iov.iov_len = strlen(reply);
++
++        msg.msg_name = &(req->origin);
++        msg.msg_namelen = req->originlen;
++        msg.msg_iov = &iov;
++        msg.msg_iovlen = 1;
++        msg.msg_control = NULL;
++        msg.msg_controllen = 0;
++        msg.msg_flags = 0;
++
++        return sendmsg(req->originating_fd, &msg, 0);
++}
++
++static struct mconsole_command *mconsole_parse(struct mc_request *req)
++{
++      struct mconsole_command *cmd;
++      int i;
++
++      for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
++              cmd = &commands[i];
++              if(!strncmp(req->request.data, cmd->command, 
++                          strlen(cmd->command))){
++                      return(cmd);
++              }
++      }
++      return(NULL);
++}
++
++#define MIN(a,b) ((a)<(b) ? (a):(b))
++
++#define STRINGX(x) #x
++#define STRING(x) STRINGX(x)
++
++int mconsole_get_request(int fd, struct mc_request *req)
++{
++      int len;
++
++      req->originlen = sizeof(req->origin);
++      req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
++                          (struct sockaddr *) req->origin, &req->originlen);
++      if (req->len < 0)
++              return 0;
++
++      req->originating_fd = fd;
++
++      if(req->request.magic != MCONSOLE_MAGIC){
++              /* Unversioned request */
++              len = MIN(sizeof(req->request.data) - 1, 
++                        strlen((char *) &req->request));
++              memmove(req->request.data, &req->request, len);
++              req->request.data[len] = '\0';
++
++              req->request.magic = MCONSOLE_MAGIC;
++              req->request.version = 0;
++              req->request.len = len;
++
++              mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
++                                "not supported by this driver");
++              return(0);
++      }
++
++      if(req->request.len >= MCONSOLE_MAX_DATA){
++              mconsole_reply(req, "Request too large", 1, 0);
++              return(0);
++      }
++      if(req->request.version != MCONSOLE_VERSION){
++              mconsole_reply(req, "This driver only supports version " 
++                               STRING(MCONSOLE_VERSION) " clients", 1, 0);
++      }
++      
++      req->request.data[req->request.len] = '\0';
++      req->cmd = mconsole_parse(req);
++      if(req->cmd == NULL){
++              mconsole_reply(req, "Unknown command", 1, 0);
++              return(0);
++      }
++
++      return(1);
++}
++
++int mconsole_reply(struct mc_request *req, char *str, int err, int more)
++{
++      struct mconsole_reply reply;
++      int total, len, n;
++
++      total = strlen(str);
++      do {
++              reply.err = err;
++
++              /* err can only be true on the first packet */
++              err = 0;
++
++              len = MIN(total, MCONSOLE_MAX_DATA - 1);
++
++              if(len == total) reply.more = more;
++              else reply.more = 1;
++
++              memcpy(reply.data, str, len);
++              reply.data[len] = '\0';
++              total -= len;
++              reply.len = len + 1;
++
++              len = sizeof(reply) + reply.len - sizeof(reply.data);
++
++              n = sendto(req->originating_fd, &reply, len, 0,
++                         (struct sockaddr *) req->origin, req->originlen);
++
++              if(n < 0) return(-errno);
++      } while(total > 0);
++      return(0);
++}
++
++int mconsole_unlink_socket(void)
++{
++      unlink(mconsole_socket_name);
++      return 0;
++}
++
++static int notify_sock = -1;
++
++int mconsole_notify(char *sock_name, int type, const void *data, int len)
++{
++      struct sockaddr_un target;
++      struct mconsole_notify packet;
++      int n, err;
++
++      if(notify_sock < 0){
++              notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
++              if(notify_sock < 0){
++                      printk("mconsole_notify - socket failed, errno = %d\n",
++                             errno);
++                      return(-errno);
++              }
++      }
++
++      target.sun_family = AF_UNIX;
++      strcpy(target.sun_path, sock_name);
++
++      packet.magic = MCONSOLE_MAGIC;
++      packet.version = MCONSOLE_VERSION;
++      packet.type = type;
++      len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
++      packet.len = len;
++      memcpy(packet.data, data, len);
++
++      err = 0;
++      len = sizeof(packet) + packet.len - sizeof(packet.data);
++      n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, 
++                 sizeof(target));
++      if(n < 0){
++              printk("mconsole_notify - sendto failed, errno = %d\n", errno);
++              err = -errno;
++      }
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/mmapper_kern.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,147 @@
++/*
++ * arch/um/drivers/mmapper_kern.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ *
++ * Copyright (C) 2000 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ */
++#include <linux/kdev_t.h>
++#include <linux/time.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/module.h>
++#include <linux/mm.h> 
++#include <linux/slab.h>
++#include <linux/init.h> 
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/smplock.h>
++#include <asm/pgtable.h>
++#include "mem_user.h"
++#include "user_util.h"
++ 
++static unsigned long mmapper_size;
++static unsigned long p_buf = 0;
++static char *v_buf = NULL;
++
++static ssize_t
++mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++      if(*ppos > mmapper_size)
++              return -EINVAL;
++
++      if(count + *ppos > mmapper_size)
++              count = count + *ppos - mmapper_size;
++
++      if(count < 0)
++              return -EINVAL;
++ 
++      copy_to_user(buf,&v_buf[*ppos],count);
++      
++      return count;
++}
++
++static ssize_t
++mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++      if(*ppos > mmapper_size)
++              return -EINVAL;
++
++      if(count + *ppos > mmapper_size)
++              count = count + *ppos - mmapper_size;
++
++      if(count < 0)
++              return -EINVAL;
++
++      copy_from_user(&v_buf[*ppos],buf,count);
++      
++      return count;
++}
++
++static int 
++mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++       unsigned long arg)
++{
++      return(-ENOIOCTLCMD);
++}
++
++static int 
++mmapper_mmap(struct file *file, struct vm_area_struct * vma)
++{
++      int ret = -EINVAL;
++      int size;
++
++      lock_kernel();
++      if (vma->vm_pgoff != 0)
++              goto out;
++      
++      size = vma->vm_end - vma->vm_start;
++      if(size > mmapper_size) return(-EFAULT);
++
++      /* XXX A comment above remap_page_range says it should only be
++       * called when the mm semaphore is held
++       */
++      if (remap_page_range(vma->vm_start, p_buf, size, vma->vm_page_prot))
++              goto out;
++      ret = 0;
++out:
++      unlock_kernel();
++      return ret;
++}
++
++static int
++mmapper_open(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++static int 
++mmapper_release(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++static struct file_operations mmapper_fops = {
++      owner:          THIS_MODULE,
++      read:           mmapper_read,
++      write:          mmapper_write,
++      ioctl:          mmapper_ioctl,
++      mmap:           mmapper_mmap,
++      open:           mmapper_open,
++      release:        mmapper_release,
++};
++
++static int __init mmapper_init(void)
++{
++      printk(KERN_INFO "Mapper v0.1\n");
++
++      v_buf = (char *) find_iomem("mmapper", &mmapper_size);
++      if(mmapper_size == 0) return(0);
++
++      p_buf = __pa(v_buf);
++
++      devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, 
++                      30, 0, S_IFCHR | S_IRUGO | S_IWUGO, 
++                      &mmapper_fops, NULL); 
++      devfs_mk_symlink(NULL, "mmapper0", DEVFS_FL_DEFAULT, "mmapper",
++                       NULL, NULL);
++      return(0);
++}
++
++static void mmapper_exit(void)
++{
++}
++
++module_init(mmapper_init);
++module_exit(mmapper_exit);
++
++MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
++MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/net_kern.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,729 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/netdevice.h"
++#include "linux/skbuff.h"
++#include "linux/socket.h"
++#include "linux/spinlock.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/etherdevice.h"
++#include "linux/list.h"
++#include "linux/inetdevice.h"
++#include "linux/ctype.h"
++#include "linux/bootmem.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "mconsole_kern.h"
++#include "init.h"
++#include "irq_user.h"
++
++LIST_HEAD(opened);
++
++struct uml_net devices[MAX_UML_NETDEV] = {
++      [ 0 ... MAX_UML_NETDEV - 1 ] = 
++      {
++              dev:            NULL,
++              user:           NULL,
++              kern:           NULL,
++              private_size:   0,
++      }
++};
++
++static int uml_net_rx(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      int pkt_len;
++      struct sk_buff *skb;
++
++      /* If we can't allocate memory, try again next round. */
++      if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
++              lp->stats.rx_dropped++;
++              reactivate_fd(lp->fd, UM_ETH_IRQ);
++              return 0;
++      }
++
++      skb->dev = dev;
++      skb_put(skb, dev->mtu);
++      skb->mac.raw = skb->data;
++      pkt_len = (*lp->read)(lp->fd, &skb, lp);
++
++      reactivate_fd(lp->fd, UM_ETH_IRQ);
++      if (pkt_len > 0) {
++              skb_trim(skb, pkt_len);
++              skb->protocol = (*lp->protocol)(skb);
++              netif_rx(skb);
++
++              lp->stats.rx_bytes += skb->len;
++              lp->stats.rx_packets++;
++              return pkt_len;
++      }
++
++      kfree_skb(skb);
++      return pkt_len;
++}
++
++void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct net_device *dev = dev_id;
++      struct uml_net_private *lp = dev->priv;
++      int err;
++
++      if (netif_running(dev)) {
++              spin_lock(&lp->lock);
++              while((err = uml_net_rx(dev)) > 0) ;
++              if(err < 0) {
++                      printk(KERN_ERR 
++                             "Device '%s' read returned %d, shutting it "
++                             "down\n", dev->name, err);
++                      dev->flags &= ~IFF_UP;
++                      dev_close(dev);
++              }
++              spin_unlock(&lp->lock);
++      }
++}
++
++static int uml_net_open(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      char addr[sizeof("255.255.255.255\0")];
++      int err;
++
++      spin_lock(&lp->lock);
++
++      if(lp->fd >= 0){
++              err = -ENXIO;
++              goto out;
++      }
++
++      if(!lp->have_mac){
++              dev_ip_addr(dev, addr, &lp->mac[2]);
++              set_ether_mac(dev, lp->mac);
++      }
++
++      lp->fd = (*lp->open)(&lp->user);
++      if(lp->fd < 0){
++              err = lp->fd;
++              goto out;
++      }
++
++      err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
++                           SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
++      if(err != 0){
++              printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
++              if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++              lp->fd = -1;
++              err = -ENETUNREACH;
++      }
++
++      lp->tl.data = (unsigned long) &lp->user;
++      netif_start_queue(dev);
++
++      list_add(&lp->list, &opened);
++      MOD_INC_USE_COUNT;
++ out:
++      spin_unlock(&lp->lock);
++      return(err);
++}
++
++static int uml_net_close(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      
++      netif_stop_queue(dev);
++      spin_lock(&lp->lock);
++
++      free_irq(dev->irq, dev);
++      if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++      lp->fd = -1;
++      list_del(&lp->list);
++      
++      MOD_DEC_USE_COUNT;
++      spin_unlock(&lp->lock);
++      return 0;
++}
++
++static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      unsigned long flags;
++      int len;
++
++      netif_stop_queue(dev);
++
++      spin_lock_irqsave(&lp->lock, flags);
++
++      len = (*lp->write)(lp->fd, &skb, lp);
++
++      if(len == skb->len) {
++              lp->stats.tx_packets++;
++              lp->stats.tx_bytes += skb->len;
++              dev->trans_start = jiffies;
++              netif_start_queue(dev);
++
++              /* this is normally done in the interrupt when tx finishes */
++              netif_wake_queue(dev);
++      } 
++      else if(len == 0){
++              netif_start_queue(dev);
++              lp->stats.tx_dropped++;
++      }
++      else {
++              netif_start_queue(dev);
++              printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
++      }
++
++      spin_unlock_irqrestore(&lp->lock, flags);
++
++      dev_kfree_skb(skb);
++
++      return 0;
++}
++
++static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      return &lp->stats;
++}
++
++static void uml_net_set_multicast_list(struct net_device *dev)
++{
++      if (dev->flags & IFF_PROMISC) return;
++      else if (dev->mc_count) dev->flags |= IFF_ALLMULTI;
++      else dev->flags &= ~IFF_ALLMULTI;
++}
++
++static void uml_net_tx_timeout(struct net_device *dev)
++{
++      dev->trans_start = jiffies;
++      netif_wake_queue(dev);
++}
++
++static int uml_net_set_mac(struct net_device *dev, void *addr)
++{
++      struct uml_net_private *lp = dev->priv;
++      struct sockaddr *hwaddr = addr;
++
++      spin_lock(&lp->lock);
++      memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
++      spin_unlock(&lp->lock);
++
++      return(0);
++}
++
++static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
++{
++      struct uml_net_private *lp = dev->priv;
++      int err = 0;
++
++      spin_lock(&lp->lock);
++
++      new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
++      if(new_mtu < 0){
++              err = new_mtu;
++              goto out;
++      }
++
++      dev->mtu = new_mtu;
++
++ out:
++      spin_unlock(&lp->lock);
++      return err;
++}
++
++static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      return(-EINVAL);
++}
++
++void uml_net_user_timer_expire(unsigned long _conn)
++{
++#ifdef undef
++      struct connection *conn = (struct connection *)_conn;
++
++      dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
++      do_connect(conn);
++#endif
++}
++
++static int eth_configure(struct uml_net *device, int n)
++{
++      struct net_device *dev;
++      struct uml_net_private *lp;
++      int save;
++
++      device->private_size += sizeof(struct uml_net_private) + 
++              sizeof(((struct uml_net_private *) 0)->user);
++
++      printk(KERN_INFO "Netdevice %d ", n);
++      if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
++                                  device->mac[0], device->mac[1], 
++                                  device->mac[2], device->mac[3], 
++                                  device->mac[4], device->mac[5]);
++      printk(": ");
++      dev = (*device->kern->init)(device->private_size,
++                                  device->transport_index);
++      if (dev == NULL){
++              printk(KERN_ERR "eth_configure: Out of memory on device %d\n",
++                     n);
++              return(1);
++      }
++      device->dev = dev;
++
++      dev->mtu = device->user->max_packet;
++      dev->open = uml_net_open;
++      dev->hard_start_xmit = uml_net_start_xmit;
++      dev->stop = uml_net_close;
++      dev->get_stats = uml_net_get_stats;
++      dev->set_multicast_list = uml_net_set_multicast_list;
++      dev->tx_timeout = uml_net_tx_timeout;
++      dev->set_mac_address = uml_net_set_mac;
++      dev->change_mtu = uml_net_change_mtu;
++      dev->do_ioctl = uml_net_ioctl;
++      dev->watchdog_timeo = (HZ >> 1);
++      dev->irq = UM_ETH_IRQ;
++
++      lp = dev->priv;
++
++      /* lp.user is the first four bytes of the transport data, which
++       * has already been initialized.  This structure assignment will
++       * overwrite that, so we make sure that .user gets overwritten with
++       * what it already has.
++       */
++      save = lp->user[0];
++      *lp = ((struct uml_net_private) 
++              { list :                LIST_HEAD_INIT(lp->list),
++                lock :                SPIN_LOCK_UNLOCKED,
++                dev :                 dev,
++                fd :                  -1,
++                mac :                 { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
++                have_mac :            device->have_mac,
++                protocol :            device->kern->protocol,
++                open :                device->user->open,
++                close :               device->user->close,
++                remove :              device->user->remove,
++                read :                device->kern->read,
++                write :               device->kern->write,
++                add_address :         device->user->add_address,
++                delete_address :      device->user->delete_address,
++                set_mtu :             device->user->set_mtu,
++                user :                { save } });
++      init_timer(&lp->tl);
++      lp->tl.function = uml_net_user_timer_expire;
++      memset(&lp->stats, 0, sizeof(lp->stats));
++      if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac));
++
++      if(device->user->init) 
++              (*device->user->init)(&lp->user, dev);
++      if(device->have_mac)
++              set_ether_mac(dev, device->mac);
++      return(0);
++}
++
++static int eth_parse(char *str, int *index_out, char **str_out)
++{
++      char *end;
++      int n;
++
++      n = simple_strtoul(str, &end, 0);
++      if(end == str){
++              printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
++              return(1);
++      }
++      if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){
++              printk(KERN_ERR "eth_setup: device %d out of range\n", n);
++              return(1);
++      }
++      str = end;
++      if(*str != '='){
++              printk(KERN_ERR 
++                     "eth_setup: expected '=' after device number\n");
++              return(1);
++      }
++      str++;
++      if(devices[n].dev != NULL){
++              printk(KERN_ERR "eth_setup: Device %d already configured\n",
++                     n);
++              return(1);
++      }
++      if(index_out) *index_out = n;
++      *str_out = str;
++      return(0);
++}
++
++struct eth_init {
++      struct list_head list;
++      char *init;
++      int index;
++};
++
++struct list_head transports = LIST_HEAD_INIT(transports);
++
++struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
++
++void register_transport(struct transport *new)
++{
++      struct list_head *ele, *next;
++      struct eth_init *eth;
++      char *str;
++      int err;
++
++      list_add(&new->list, &transports);
++
++      list_for_each_safe(ele, next, &eth_cmd_line){
++              eth = list_entry(ele, struct eth_init, list);
++              if(!strncmp(eth->init, new->name, strlen(new->name))){
++                      str = eth->init + strlen(new->name);
++                      err = new->setup(str, &devices[eth->index]);
++                      if(!err) eth_configure(&devices[eth->index], 
++                                             eth->index);
++                      list_del(&eth->list);
++              }
++      }
++}
++
++static int eth_setup_common(char *str, int index)
++{
++      struct list_head *ele;
++      struct transport *transport;
++
++      list_for_each(ele, &transports){
++              transport = list_entry(ele, struct transport, list);
++              if(!strncmp(str, transport->name, strlen(transport->name))){
++                      str += strlen(transport->name);
++                      return(transport->setup(str, &devices[index]));
++              }
++      }
++
++      return(-1);
++}
++
++static int eth_setup(char *str)
++{
++      struct eth_init *new;
++      int n, err;
++
++      err = eth_parse(str, &n, &str);
++      if(err) return(1);
++
++      new = alloc_bootmem(sizeof(new));
++      if(new == NULL){
++              printk("eth_init : alloc_bootmem failed\n");
++              return(1);
++      }
++      *new = ((struct eth_init) { list :      LIST_HEAD_INIT(new->list),
++                                  index :     n,
++                                  init :      str });
++      list_add_tail(&new->list, &eth_cmd_line);
++      return(1);
++}
++
++__setup("eth", eth_setup);
++__uml_help(eth_setup,
++"eth[0-9]+=<transport>,<options>\n"
++"    Configure a network device.\n\n"
++);
++
++int ndev = 0;
++
++static int eth_init(void)
++{
++      struct list_head *ele, *next;
++      struct eth_init *eth;
++      int err;
++
++      list_for_each_safe(ele, next, &eth_cmd_line){
++              eth = list_entry(ele, struct eth_init, list);
++              err = eth_setup_common(eth->init, eth->index);
++              if(!err) eth_configure(&devices[eth->index], eth->index);
++              if(err >= 0) list_del(&eth->list);
++      }
++      
++      return(1);
++}
++
++__initcall(eth_init);
++
++static int net_config(char *str)
++{
++      int err, n;
++
++      err = eth_parse(str, &n, &str);
++      if(err) return(err);
++
++      str = uml_strdup(str);
++      if(str == NULL){
++              printk(KERN_ERR "net_config failed to strdup string\n");
++              return(1);
++      }
++      err = eth_setup_common(str, n);
++      if(err){
++              kfree(str);
++              return(err);
++      }
++      err = eth_configure(&devices[n], n);
++      return(err);
++}
++
++static int net_remove(char *str)
++{
++      struct net_device *dev;
++      struct uml_net_private *lp;
++      int n;
++
++      if(!isdigit(*str)) return(-1);
++      n = *str - '0';
++      if(devices[n].dev == NULL) return(0);
++      dev = devices[n].dev;
++      lp = dev->priv;
++      if(lp->fd > 0) return(-1);
++      if(lp->remove != NULL) (*lp->remove)(&lp->user);
++      unregister_netdev(dev);
++      devices[n].dev = NULL;
++      return(0);
++}
++
++static struct mc_device net_mc = {
++      name:           "eth",
++      config:         net_config,
++      remove:         net_remove,
++};
++
++static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
++                            void *ptr)
++{
++      struct in_ifaddr *ifa = ptr;
++      u32 addr = ifa->ifa_address;
++      u32 netmask = ifa->ifa_mask;
++      struct net_device *dev = ifa->ifa_dev->dev;
++      struct uml_net_private *lp;
++      void (*proc)(unsigned char *, unsigned char *, void *);
++      unsigned char addr_buf[4], netmask_buf[4];
++
++      if(dev->open != uml_net_open) return(NOTIFY_DONE);
++
++      lp = dev->priv;
++
++      proc = NULL;
++      switch (event){
++      case NETDEV_UP:
++              proc = lp->add_address;
++              break;
++      case NETDEV_DOWN:
++              proc = lp->delete_address;
++              break;
++      }
++      if(proc != NULL){
++              addr_buf[0] = addr & 0xff;
++              addr_buf[1] = (addr >> 8) & 0xff;
++              addr_buf[2] = (addr >> 16) & 0xff;
++              addr_buf[3] = addr >> 24;
++              netmask_buf[0] = netmask & 0xff;
++              netmask_buf[1] = (netmask >> 8) & 0xff;
++              netmask_buf[2] = (netmask >> 16) & 0xff;
++              netmask_buf[3] = netmask >> 24;
++              (*proc)(addr_buf, netmask_buf, &lp->user);
++      }
++      return(NOTIFY_DONE);
++}
++
++struct notifier_block uml_inetaddr_notifier = {
++      notifier_call:          uml_inetaddr_event,
++};
++
++static int uml_net_init(void)
++{
++      struct list_head *ele;
++      struct uml_net_private *lp;     
++      struct in_device *ip;
++      struct in_ifaddr *in;
++
++      mconsole_register_dev(&net_mc);
++      register_inetaddr_notifier(&uml_inetaddr_notifier);
++
++      /* Devices may have been opened already, so the uml_inetaddr_notifier
++       * didn't get a chance to run for them.  This fakes it so that
++       * addresses which have already been set up get handled properly.
++       */
++      list_for_each(ele, &opened){
++              lp = list_entry(ele, struct uml_net_private, list);
++              ip = lp->dev->ip_ptr;
++              if(ip == NULL) continue;
++              in = ip->ifa_list;
++              while(in != NULL){
++                      uml_inetaddr_event(NULL, NETDEV_UP, in);
++                      in = in->ifa_next;
++              }
++      }       
++
++      return(0);
++}
++
++__initcall(uml_net_init);
++
++static void close_devices(void)
++{
++      struct list_head *ele;
++      struct uml_net_private *lp;     
++
++      list_for_each(ele, &opened){
++              lp = list_entry(ele, struct uml_net_private, list);
++              if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++              if(lp->remove != NULL) (*lp->remove)(&lp->user);
++      }
++}
++
++__uml_exitcall(close_devices);
++
++int setup_etheraddr(char *str, unsigned char *addr)
++{
++      char *end;
++      int i;
++
++      for(i=0;i<6;i++){
++              addr[i] = simple_strtoul(str, &end, 16);
++              if((end == str) ||
++                 ((*end != ':') && (*end != ',') && (*end != '\0'))){
++                      printk(KERN_ERR 
++                             "setup_etheraddr: failed to parse '%s' "
++                             "as an ethernet address\n", str);
++                      return(-1);
++              }
++              str = end + 1;
++      }
++      if(addr[0] & 1){
++              printk(KERN_ERR 
++                     "Attempt to assign a broadcast ethernet address to a "
++                     "device disallowed\n");
++              return(-1);
++      }
++      return(0);
++}
++
++void dev_ip_addr(void *d, char *buf, char *bin_buf)
++{
++      struct net_device *dev = d;
++      struct in_device *ip = dev->ip_ptr;
++      struct in_ifaddr *in;
++      u32 addr;
++
++      if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
++              printk(KERN_WARNING "dev_ip_addr - device not assigned an "
++                     "IP address\n");
++              return;
++      }
++      addr = in->ifa_address;
++      sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, 
++              (addr >> 16) & 0xff, addr >> 24);
++      if(bin_buf){
++              bin_buf[0] = addr & 0xff;
++              bin_buf[1] = (addr >> 8) & 0xff;
++              bin_buf[2] = (addr >> 16) & 0xff;
++              bin_buf[3] = addr >> 24;
++      }
++}
++
++void set_ether_mac(void *d, unsigned char *addr)
++{
++      struct net_device *dev = d;
++
++      memcpy(dev->dev_addr, addr, ETH_ALEN);  
++}
++
++struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
++{
++      if((skb != NULL) && (skb_tailroom(skb) < extra)){
++              struct sk_buff *skb2;
++
++              skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
++              dev_kfree_skb(skb);
++              skb = skb2;
++      }
++      if(skb != NULL) skb_put(skb, extra);
++      return(skb);
++}
++
++void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, 
++                                      void *), 
++                  void *arg)
++{
++      struct net_device *dev = d;
++      struct in_device *ip = dev->ip_ptr;
++      struct in_ifaddr *in;
++      unsigned char address[4], netmask[4];
++
++      if(ip == NULL) return;
++      in = ip->ifa_list;
++      while(in != NULL){
++              address[0] = in->ifa_address & 0xff;
++              address[1] = (in->ifa_address >> 8) & 0xff;
++              address[2] = (in->ifa_address >> 16) & 0xff;
++              address[3] = in->ifa_address >> 24;
++              netmask[0] = in->ifa_mask & 0xff;
++              netmask[1] = (in->ifa_mask >> 8) & 0xff;
++              netmask[2] = (in->ifa_mask >> 16) & 0xff;
++              netmask[3] = in->ifa_mask >> 24;
++              (*cb)(address, netmask, arg);
++              in = in->ifa_next;
++      }
++}
++
++void *get_output_buffer(int *len_out)
++{
++      void *ret;
++
++      ret = (void *) __get_free_pages(GFP_KERNEL, 0);
++      if(ret) *len_out = PAGE_SIZE;
++      else *len_out = 0;
++      return(ret);
++}
++
++void free_output_buffer(void *buffer)
++{
++      free_pages((unsigned long) buffer, 0);
++}
++
++int tap_setup_common(char *str, char *type, char **dev_name, char *mac, 
++                   int *have_mac, char **gate_addr)
++{
++      int err;
++
++      if(*str != ','){
++              printk(KERN_ERR 
++                     "ethertap_setup: expected ',' after '%s'\n", type);
++              return(1);
++      }
++      str++;
++      if(*str != ',') *dev_name = str;
++      str = strchr(str, ',');
++      if(str == NULL) return(0);
++      *str++ = '\0';
++      if(*str != ','){
++              err = setup_etheraddr(str, mac);
++              if(!err) *have_mac = 1;
++      }
++      str = strchr(str, ',');
++      if(str == NULL) return(0);
++      *str++ = '\0';
++      if(*str != '\0') *gate_addr = str;
++      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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/net_user.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,232 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "net_user.h"
++#include "helper.h"
++#include "os.h"
++
++int tap_open_common(void *dev, char *gate_addr)
++{
++      int tap_addr[4];
++
++      if(gate_addr == NULL) return(0);
++      if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
++                &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
++              printk("Invalid tap IP address - '%s'\n", 
++                     gate_addr);
++              return(-EINVAL);
++      }
++      return(0);
++}
++
++void tap_check_ips(char *gate_addr, char *eth_addr)
++{
++      int tap_addr[4];
++
++      if((gate_addr != NULL) && 
++         (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
++                 &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
++         (eth_addr[0] == tap_addr[0]) && 
++         (eth_addr[1] == tap_addr[1]) && 
++         (eth_addr[2] == tap_addr[2]) && 
++         (eth_addr[3] == tap_addr[3])){
++              printk("The tap IP address and the UML eth IP address"
++                     " must be different\n");
++      }
++}
++
++void read_output(int fd, char *output, int len)
++{
++      int remain, n, actual;
++      char c;
++
++      if(output == NULL){
++              output = &c;
++              len = sizeof(c);
++      }
++              
++      *output = '\0';
++      if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){
++              printk("read_output - read of length failed, errno = %d\n",
++                     errno);
++              return;
++      }
++
++      while(remain != 0){
++              n = (remain < len) ? remain : len;
++              actual = read(fd, output, n);
++              if(actual != n){
++                      printk("read_output - read of data failed, "
++                             "errno = %d\n", errno);
++                      return;
++              }
++              remain -= actual;
++      }
++      return;
++}
++
++int net_read(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = read(fd,  buf,  len)) < 0) && (errno == EINTR)) ;
++
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);
++}
++
++int net_recvfrom(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = recvfrom(fd,  buf,  len, 0, NULL, NULL)) < 0) && 
++            (errno == EINTR)) ;
++
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);
++}
++
++int net_write(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ;
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);      
++}
++
++int net_send(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);      
++}
++
++int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
++{
++      int n;
++
++      while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
++                         sock_len)) < 0) && (errno == EINTR)) ;
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);      
++}
++
++struct change_pre_exec_data {
++      int close_me;
++      int stdout;
++};
++
++static void change_pre_exec(void *arg)
++{
++      struct change_pre_exec_data *data = arg;
++
++      close(data->close_me);
++      dup2(data->stdout, 1);
++}
++
++static int change_tramp(char **argv, char *output, int output_len)
++{
++      int pid, fds[2], err;
++      struct change_pre_exec_data pe_data;
++
++      err = os_pipe(fds, 1, 0);
++      if(err){
++              printk("change_tramp - pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++      pe_data.close_me = fds[0];
++      pe_data.stdout = fds[1];
++      pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
++
++      close(fds[1]);
++      read_output(fds[0], output, output_len);
++      waitpid(pid, NULL, 0);  
++      return(pid);
++}
++
++static void change(char *dev, char *what, unsigned char *addr,
++                 unsigned char *netmask)
++{
++      char addr_buf[sizeof("255.255.255.255\0")];
++      char netmask_buf[sizeof("255.255.255.255\0")];
++      char version[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version, what, dev, addr_buf, 
++                       netmask_buf, NULL };
++      char *output;
++      int output_len, pid;
++
++      sprintf(version, "%d", UML_NET_VERSION);
++      sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
++      sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 
++              netmask[2], netmask[3]);
++
++      output_len = page_size();
++      output = um_kmalloc(output_len);
++      if(output == NULL)
++              printk("change : failed to allocate output buffer\n");
++
++      pid = change_tramp(argv, output, output_len);
++      if(pid < 0) return;
++
++      if(output != NULL){
++              printk("%s", output);
++              kfree(output);
++      }
++}
++
++void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
++{
++      change(arg, "add", addr, netmask);
++}
++
++void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
++{
++      change(arg, "del", addr, netmask);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/null.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,53 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <fcntl.h>
++#include "chan_user.h"
++#include "os.h"
++
++static int null_chan;
++
++void *null_init(char *str, int device, struct chan_opts *opts)
++{
++      return(&null_chan);
++}
++
++int null_open(int input, int output, int primary, void *d)
++{
++      return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
++}
++
++int null_read(int fd, char *c_out, void *unused)
++{
++      return(-ENODEV);
++}
++
++void null_free(void *data)
++{
++}
++
++struct chan_ops null_ops = {
++      init:           null_init,
++      open:           null_open,
++      close:          generic_close,
++      read:           null_read,
++      write:          generic_write,
++      console_write:  generic_console_write,
++      window_size:    generic_window_size,
++      free:           null_free,
++      winch:          0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/port.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PORT_H__
++#define __PORT_H__
++
++extern void *port_data(int port);
++extern int port_wait(void *data);
++extern void port_kern_close(void *d);
++extern int port_connection(int fd, int *socket_out, int *pid_out);
++extern int port_listen_fd(int port);
++extern void port_read(int fd, void *data);
++extern void port_kern_free(void *d);
++extern int port_rcv_fd(int fd);
++extern void port_remove_dev(void *d);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/port_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,254 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/list.h"
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/irq.h"
++#include "linux/spinlock.h"
++#include "linux/errno.h"
++#include "asm/semaphore.h"
++#include "asm/errno.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "port.h"
++#include "init.h"
++#include "os.h"
++
++struct port_list {
++      struct list_head list;
++      struct semaphore sem;
++      int port;
++      int fd;
++      spinlock_t lock;
++      struct list_head pending;
++      struct list_head connections;
++};
++
++struct port_dev {
++      struct port_list *port;
++      int fd;
++      int helper_pid;
++      int telnetd_pid;
++};
++
++struct connection {
++      struct list_head list;
++      int fd;
++      int helper_pid;
++      int socket[2];
++      int telnetd_pid;
++      struct port_list *port;
++};
++
++static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++      struct connection *conn = data;
++      int fd;
++
++      list_del(&conn->list);
++
++      fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
++      if(fd < 0){
++              printk("os_accept_connection returned %d\n", -fd);
++              os_close_file(conn->fd);
++      }
++      conn->fd = fd;
++      list_add(&conn->list, &conn->port->connections);
++
++      up(&conn->port->sem);
++}
++
++struct list_head ports = LIST_HEAD_INIT(ports);
++
++static void port_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++      struct port_list *port = data;
++      struct connection *conn;
++      int fd, socket[2], pid;
++
++      fd = port_connection(port->fd, socket, &pid);
++      if(fd < 0){
++              printk("port_connection returned %d\n", -fd);
++              goto out;
++      }
++
++      conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
++      if(conn == NULL){
++              printk("port_interrupt : failed to allocate connection\n");
++              goto out_close;
++      }
++      *conn = ((struct connection) 
++              { list :        LIST_HEAD_INIT(conn->list),
++                fd :          fd,
++                socket :      { socket[0], socket[1] },
++                telnetd_pid : pid,
++                port :        port });
++
++      if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
++                        "telnetd", conn)){
++              printk(KERN_ERR "Failed to get IRQ for telnetd\n");
++              goto out_free;
++      }
++
++      list_add(&conn->list, &port->pending);
++      goto out;
++
++ out_free:
++      kfree(conn);
++ out_close:
++      os_close_file(fd);
++      if(pid != -1) os_kill_process(pid);
++ out:
++      reactivate_fd(port->fd, ACCEPT_IRQ);
++} 
++
++void *port_data(int port_num)
++{
++      struct list_head *ele;
++      struct port_list *port;
++      struct port_dev *dev;
++      int fd;
++
++      list_for_each(ele, &ports){
++              port = list_entry(ele, struct port_list, list);
++              if(port->port == port_num) goto found;
++      }
++      port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
++      if(port == NULL){
++              printk(KERN_ERR "Allocation of port list failed\n");
++              return(NULL);
++      }
++
++      fd = port_listen_fd(port_num);
++      if(fd < 0){
++              printk(KERN_ERR "binding to port %d failed, errno = %d\n",
++                     port_num, -fd);
++              goto out_free;
++      }
++      if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
++                        port)){
++              printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
++              goto out_close;
++      }
++
++      *port = ((struct port_list) 
++              { list :        LIST_HEAD_INIT(port->list),
++                sem :         __SEMAPHORE_INITIALIZER(port->sem, 0),
++                lock :        SPIN_LOCK_UNLOCKED,
++                port :        port_num,
++                fd :          fd,
++                pending :     LIST_HEAD_INIT(port->pending),
++                connections : LIST_HEAD_INIT(port->connections) });
++      list_add(&port->list, &ports);
++
++ found:
++      dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
++      if(dev == NULL){
++              printk(KERN_ERR "Allocation of port device entry failed\n");
++              return(NULL);
++      }
++
++      *dev = ((struct port_dev) { port :              port,
++                                  fd :                -1,
++                                  helper_pid :        -1 });
++      return(dev);
++
++ out_free:
++      kfree(port);
++ out_close:
++      os_close_file(fd);
++      return(NULL);
++}
++
++void port_remove_dev(void *d)
++{
++      struct port_dev *dev = d;
++
++      if(dev->helper_pid != -1)
++              os_kill_process(dev->helper_pid);
++      if(dev->telnetd_pid != -1)
++              os_kill_process(dev->telnetd_pid);
++      dev->helper_pid = -1;
++}
++
++static void free_port(void)
++{
++      struct list_head *ele;
++      struct port_list *port;
++
++      list_for_each(ele, &ports){
++              port = list_entry(ele, struct port_list, list);
++              free_irq(ACCEPT_IRQ, port);
++              os_close_file(port->fd);
++      }
++}
++
++__uml_exitcall(free_port);
++
++int port_wait(void *data)
++{
++      struct port_dev *dev = data;
++      struct connection *conn;
++      struct port_list *port = dev->port;
++
++      while(1){
++              if(down_interruptible(&port->sem)) return(-ERESTARTSYS);
++
++              spin_lock(&port->lock);
++
++              conn = list_entry(port->connections.next, struct connection, 
++                                list);
++              list_del(&conn->list);
++              spin_unlock(&port->lock);
++
++              os_shutdown_socket(conn->socket[0], 1, 1);
++              os_close_file(conn->socket[0]);
++              os_shutdown_socket(conn->socket[1], 1, 1);
++              os_close_file(conn->socket[1]); 
++
++              /* This is done here because freeing an IRQ can't be done
++               * within the IRQ handler.  So, pipe_interrupt always ups
++               * the semaphore regardless of whether it got a successful
++               * connection.  Then we loop here throwing out failed 
++               * connections until a good one is found.
++               */
++              free_irq(TELNETD_IRQ, conn);
++
++              if(conn->fd >= 0) break;
++              os_close_file(conn->fd);
++              kfree(conn);
++      }
++
++      dev->fd = conn->fd;
++      dev->helper_pid = conn->helper_pid;
++      dev->telnetd_pid = conn->telnetd_pid;
++      kfree(conn);
++
++      return(dev->fd);
++}
++
++void port_kern_free(void *d)
++{
++      struct port_dev *dev = d;
++
++      if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid);
++      if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid);
++      kfree(dev);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/port_user.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,191 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <termios.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netinet/in.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "chan_user.h"
++#include "port.h"
++#include "helper.h"
++#include "os.h"
++
++struct port_chan {
++      int raw;
++      struct termios tt;
++      void *kernel_data;
++};
++
++void *port_init(char *str, int device, struct chan_opts *opts)
++{
++      struct port_chan *data;
++      void *kern_data;
++      char *end;
++      int port;
++
++      if(*str != ':'){
++              printk("port_init : channel type 'port' must specify a "
++                     "port number\n");
++              return(NULL);
++      }
++      str++;
++      port = strtoul(str, &end, 0);
++      if(*end != '\0'){
++              printk("port_init : couldn't parse port '%s'\n", str);
++              return(NULL);
++      }
++
++      if((kern_data = port_data(port)) == NULL) return(NULL);
++
++      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      *data = ((struct port_chan) { raw :             opts->raw,
++                                    kernel_data :     kern_data });
++      
++      return(data);
++}
++
++int port_open(int input, int output, int primary, void *d)
++{
++      struct port_chan *data = d;
++      int fd;
++
++      fd = port_wait(data->kernel_data);
++      if((fd >= 0) && data->raw){
++              tcgetattr(fd, &data->tt);
++              raw(fd, 0);
++      }
++      return(fd);
++}
++
++void port_close(int fd, void *d)
++{
++      struct port_chan *data = d;
++
++      port_remove_dev(data->kernel_data);
++      close(fd);
++}
++
++int port_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct port_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++void port_free(void *d)
++{
++      struct port_chan *data = d;
++
++      port_kern_free(data->kernel_data);
++      kfree(data);
++}
++
++struct chan_ops port_ops = {
++      init:           port_init,
++      open:           port_open,
++      close:          port_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  port_console_write,
++      window_size:    generic_window_size,
++      free:           port_free,
++      winch:          1,
++};
++
++int port_listen_fd(int port)
++{
++      struct sockaddr_in addr;
++      int fd, err;
++
++      fd = socket(PF_INET, SOCK_STREAM, 0);
++      if(fd == -1) return(-errno);
++
++      addr.sin_family = AF_INET;
++      addr.sin_port = htons(port);
++      addr.sin_addr.s_addr = htonl(INADDR_ANY);
++      if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
++              err = -errno;
++              goto out;
++      }
++  
++      if(listen(fd, 1) < 0){
++              err = -errno;
++              goto out;
++      }
++
++      return(fd);
++ out:
++      os_close_file(fd);
++      return(err);
++}
++
++struct port_pre_exec_data {
++      int sock_fd;
++      int pipe_fd;
++};
++
++void port_pre_exec(void *arg)
++{
++      struct port_pre_exec_data *data = arg;
++
++      dup2(data->sock_fd, 0);
++      dup2(data->sock_fd, 1);
++      dup2(data->sock_fd, 2);
++      close(data->sock_fd);
++      dup2(data->pipe_fd, 3);
++      os_shutdown_socket(3, 1, 0);
++      close(data->pipe_fd);
++}
++
++int port_connection(int fd, int *socket, int *pid_out)
++{
++      int new, err;
++      char *argv[] = { "/usr/sbin/in.telnetd", "-L", 
++                       "/usr/lib/uml/port-helper", NULL };
++      struct port_pre_exec_data data;
++
++      if((new = accept(fd, NULL, 0)) < 0) return(-errno);
++
++      err = os_pipe(socket, 0, 0);
++      if(err) goto out_close;
++
++      data = ((struct port_pre_exec_data)
++              { sock_fd :             new,
++                pipe_fd :             socket[1] });
++
++      err = run_helper(port_pre_exec, &data, argv, NULL);
++      if(err < 0) goto out_shutdown;
++
++      *pid_out = err;
++      return(new);
++
++ out_shutdown:
++      os_shutdown_socket(socket[0], 1, 1);
++      close(socket[0]);
++      os_shutdown_socket(socket[1], 1, 1);    
++      close(socket[1]);
++ out_close:
++      close(new);
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/pty.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,156 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <termios.h>
++#include "chan_user.h"
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++
++struct pty_chan {
++      void (*announce)(char *dev_name, int dev);
++      int dev;
++      int raw;
++      struct termios tt;
++};
++
++void *pty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++      struct pty_chan *data;
++
++      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      *data = ((struct pty_chan) { announce :         opts->announce, 
++                                   dev :              device,
++                                   raw :              opts->raw });
++      return(data);
++}
++
++int pts_open(int input, int output, int primary, void *d)
++{
++      struct pty_chan *data = d;
++      int fd;
++
++      if((fd = get_pty()) < 0){
++              printk("open_pts : Failed to open pts\n");
++              return(-errno);
++      }
++      if(data->raw){
++              tcgetattr(fd, &data->tt);
++              raw(fd, 0);
++      }
++      if(data->announce) (*data->announce)(ptsname(fd), data->dev);
++      return(fd);
++}
++
++int getmaster(char *line)
++{
++      struct stat stb;
++      char *pty, *bank, *cp;
++      int master;
++
++      pty = &line[strlen("/dev/ptyp")];
++      for (bank = "pqrs"; *bank; bank++) {
++              line[strlen("/dev/pty")] = *bank;
++              *pty = '0';
++              if (stat(line, &stb) < 0)
++                      break;
++              for (cp = "0123456789abcdef"; *cp; cp++) {
++                      *pty = *cp;
++                      master = open(line, O_RDWR);
++                      if (master >= 0) {
++                              char *tp = &line[strlen("/dev/")];
++                              int ok;
++
++                              /* verify slave side is usable */
++                              *tp = 't';
++                              ok = access(line, R_OK|W_OK) == 0;
++                              *tp = 'p';
++                              if (ok) return(master);
++                              (void) close(master);
++                      }
++              }
++      }
++      return(-1);
++}
++
++struct grantpt_info {
++      int fd;
++      int res;
++      int err;
++};
++
++static void grantpt_cb(void *arg)
++{
++      struct grantpt_info *info = arg;
++
++      info->res = grantpt(info->fd);
++      info->err = errno;
++}
++
++int pty_open(int input, int output, int primary, void *d)
++{
++      struct pty_chan *data = d;
++      int fd;
++      char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
++      struct grantpt_info info;
++
++      fd = getmaster(dev);
++      if(fd < 0) return(-errno);
++      
++      info.fd = fd;
++      tracing_cb(grantpt_cb, &info);
++      unlockpt(fd);
++
++      if(data->raw) raw(fd, 0);
++      if(data->announce) (*data->announce)(dev, data->dev);
++      return(fd);
++}
++
++int pty_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct pty_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops pty_ops = {
++      init:           pty_chan_init,
++      open:           pty_open,
++      close:          generic_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  pty_console_write,
++      window_size:    generic_window_size,
++      free:           generic_free,
++      winch:          0,
++};
++
++struct chan_ops pts_ops = {
++      init:           pty_chan_init,
++      open:           pts_open,
++      close:          generic_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  pty_console_write,
++      window_size:    generic_window_size,
++      free:           generic_free,
++      winch:          0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/slip.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++#ifndef __UM_SLIP_H
++#define __UM_SLIP_H
++
++#define BUF_SIZE 1500
++
++struct slip_data {
++      void *dev;
++      char name[sizeof("slnnnnn\0")];
++      char *addr;
++      char *gate_addr;
++      int slave;
++      char buf[2 * BUF_SIZE];
++      int pos;
++      int esc;
++};
++
++extern struct net_user_info slip_user_info;
++
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
++extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/slip_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,115 @@
++#include "linux/kernel.h"
++#include "linux/stddef.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/if_arp.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "kern.h"
++#include "slip.h"
++#include "slip_kern.h"
++
++struct slip_data slip_priv[MAX_UML_NETDEV] = {
++      [ 0 ... MAX_UML_NETDEV - 1 ] =
++      {
++              addr:           NULL,
++              gate_addr:      NULL,
++              slave:          -1,
++              buf:            { 0 },
++              pos:            0,
++              esc:            0,
++      }
++};
++
++struct net_device umn_dev;
++
++struct net_device *slip_init(int private_size, int index)
++{
++      struct uml_net_private *private;
++      struct slip_data *spri;
++
++      private = kmalloc(private_size, GFP_KERNEL);
++      if(private == NULL) return(NULL);
++      umn_dev.priv = private;
++      spri = (struct slip_data *) private->user;
++      *spri = slip_priv[index];
++      strncpy(umn_dev.name, "umn", IFNAMSIZ);
++      umn_dev.init = NULL;
++      umn_dev.hard_header_len = 0;
++      umn_dev.addr_len = 4;
++      umn_dev.type = ARPHRD_ETHER;
++      umn_dev.tx_queue_len = 256;
++      umn_dev.flags = IFF_NOARP;
++      if(register_netdev(&umn_dev))
++              printk(KERN_ERR "Couldn't initialize umn\n");
++      printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
++      
++      return(&umn_dev);
++}
++
++static unsigned short slip_protocol(struct sk_buff *skbuff)
++{
++      return(htons(ETH_P_IP));
++}
++
++static int slip_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
++                            (struct slip_data *) &lp->user));
++}
++
++static int slip_write(int fd, struct sk_buff **skb,
++                    struct uml_net_private *lp)
++{
++      return(slip_user_write(fd, (*skb)->data, (*skb)->len, 
++                             (struct slip_data *) &lp->user));
++}
++
++struct net_kern_info slip_kern_info = {
++      init:                   slip_init,
++      protocol:               slip_protocol,
++      read:                   slip_read,
++      write:                  slip_write,
++};
++
++static int slip_count = 0;
++
++int slip_setup(char *str, struct uml_net *dev)
++{
++      int n = slip_count;
++
++      dev->user = &slip_user_info;
++      dev->kern = &slip_kern_info;
++      dev->private_size = sizeof(struct slip_data);
++      dev->transport_index = slip_count++;
++      if(*str != ',') return(0);
++      str++;
++      if(str[0] != '\0') slip_priv[n].gate_addr = str;
++      return(0);
++}
++
++static struct transport slip_transport = {
++      list :  LIST_HEAD_INIT(slip_transport.list),
++      name :  "slip",
++      setup : slip_setup
++};
++
++static int register_slip(void)
++{
++      register_transport(&slip_transport);
++      return(1);
++}
++
++__initcall(register_slip);
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/slip_kern.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,8 @@
++#ifndef __UM_SLIP_KERN_H
++#define __UM_SLIP_KERN_H
++
++#include "net_kern.h"
++
++extern int slip_setup(char *arg, struct uml_net *dev);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/slip_user.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,333 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <sched.h>
++#include <string.h>
++#include <sys/fcntl.h>
++#include <sys/errno.h>
++#include <sys/termios.h>
++#include <sys/wait.h>
++#include <sys/ioctl.h>
++#include <sys/signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "net_user.h"
++#include "slip.h"
++#include "helper.h"
++#include "os.h"
++
++void slip_user_init(void *data, void *dev)
++{
++      struct slip_data *pri = data;
++
++      pri->dev = dev;
++}
++
++static int set_up_tty(int fd)
++{
++      int i;
++      struct termios tios;
++
++      if (tcgetattr(fd, &tios) < 0) {
++              printk("could not get initial terminal attributes\n");
++              return(-1);
++      }
++
++      tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
++      tios.c_iflag = IGNBRK | IGNPAR;
++      tios.c_oflag = 0;
++      tios.c_lflag = 0;
++      for (i = 0; i < NCCS; i++)
++              tios.c_cc[i] = 0;
++      tios.c_cc[VMIN] = 1;
++      tios.c_cc[VTIME] = 0;
++
++      cfsetospeed(&tios, B38400);
++      cfsetispeed(&tios, B38400);
++
++      if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
++              printk("failed to set terminal attributes\n");
++              return(-1);
++      }
++      return(0);
++}
++
++struct slip_pre_exec_data {
++      int stdin;
++      int stdout;
++      int close_me;
++};
++
++static void slip_pre_exec(void *arg)
++{
++      struct slip_pre_exec_data *data = arg;
++
++      if(data->stdin != -1) dup2(data->stdin, 0);
++      dup2(data->stdout, 1);
++      close(data->close_me);
++}
++
++static int slip_tramp(char **argv, int fd)
++{
++      struct slip_pre_exec_data pe_data;
++      char *output;
++      int status, pid, fds[2], err, output_len;
++
++      err = os_pipe(fds, 1, 0);
++      if(err){
++              printk("slip_tramp : pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++
++      err = 0;
++      pe_data.stdin = fd;
++      pe_data.stdout = fds[1];
++      pe_data.close_me = fds[0];
++      pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
++
++      if(pid < 0) err = pid;
++      else {
++              output_len = page_size();
++              output = um_kmalloc(output_len);
++              if(output == NULL)
++                      printk("slip_tramp : failed to allocate output "
++                             "buffer\n");
++
++              close(fds[1]);
++              read_output(fds[0], output, output_len);
++              if(output != NULL){
++                      printk("%s", output);
++                      kfree(output);
++              }
++              if(waitpid(pid, &status, 0) < 0) err = errno;
++              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
++                      printk("'%s' didn't exit with status 0\n", argv[0]);
++                      err = EINVAL;
++              }
++      }
++      return(err);
++}
++
++static int slip_open(void *data)
++{
++      struct slip_data *pri = data;
++      char version_buf[sizeof("nnnnn\0")];
++      char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
++      char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 
++                       NULL };
++      int sfd, mfd, disc, sencap, err;
++
++      if((mfd = get_pty()) < 0){
++              printk("umn : Failed to open pty\n");
++              return(-1);
++      }
++      if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){
++              printk("Couldn't open tty for slip line\n");
++              return(-1);
++      }
++      if(set_up_tty(sfd)) return(-1);
++      pri->slave = sfd;
++      pri->pos = 0;
++      pri->esc = 0;
++      if(pri->gate_addr != NULL){
++              sprintf(version_buf, "%d", UML_NET_VERSION);
++              strcpy(gate_buf, pri->gate_addr);
++
++              err = slip_tramp(argv, sfd);
++
++              if(err != 0){
++                      printk("slip_tramp failed - errno = %d\n", err);
++                      return(-err);
++              }
++              if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){
++                      printk("SIOCGIFNAME failed, errno = %d\n", errno);
++                      return(-errno);
++              }
++              iter_addresses(pri->dev, open_addr, pri->name);
++      }
++      else {
++              disc = N_SLIP;
++              if(ioctl(sfd, TIOCSETD, &disc) < 0){
++                      printk("Failed to set slip line discipline - "
++                             "errno = %d\n", errno);
++                      return(-errno);
++              }
++              sencap = 0;
++              if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
++                      printk("Failed to sett slip encapsulation - "
++                             "errno = %d\n", errno);
++                      return(-errno);
++              }
++      }
++      return(mfd);
++}
++
++static void slip_close(int fd, void *data)
++{
++      struct slip_data *pri = data;
++      char version_buf[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 
++                       NULL };
++      int err;
++
++      if(pri->gate_addr != NULL)
++              iter_addresses(pri->dev, close_addr, pri->name);
++
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++
++      err = slip_tramp(argv, -1);
++
++      if(err != 0)
++              printk("slip_tramp failed - errno = %d\n", err);
++      close(fd);
++      close(pri->slave);
++      pri->slave = -1;
++}
++
++/* SLIP protocol characters. */
++#define END             0300          /* indicates end of frame       */
++#define ESC             0333          /* indicates byte stuffing      */
++#define ESC_END         0334          /* ESC ESC_END means END 'data' */
++#define ESC_ESC         0335          /* ESC ESC_ESC means ESC 'data' */
++
++static int slip_unesc(struct slip_data *sl, unsigned char c)
++{
++      int ret;
++
++      switch(c){
++      case END:
++              sl->esc = 0;
++              ret = sl->pos;
++              sl->pos = 0;
++              return(ret);
++      case ESC:
++              sl->esc = 1;
++              return(0);
++      case ESC_ESC:
++              if(sl->esc){
++                      sl->esc = 0;
++                      c = ESC;
++              }
++              break;
++      case ESC_END:
++              if(sl->esc){
++                      sl->esc = 0;
++                      c = END;
++              }
++              break;
++      }
++      sl->buf[sl->pos++] = c;
++      return(0);
++}
++
++int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
++{
++      int i, n, size, start;
++
++      n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos);
++      if(n <= 0) return(n);
++
++      start = pri->pos;
++      for(i = 0; i < n; i++){
++              size = slip_unesc(pri, pri->buf[start + i]);
++              if(size){
++                      memcpy(buf, pri->buf, size);
++                      return(size);
++              }
++      }
++      return(0);
++}
++
++static int slip_esc(unsigned char *s, unsigned char *d, int len)
++{
++      unsigned char *ptr = d;
++      unsigned char c;
++
++      /*
++       * Send an initial END character to flush out any
++       * data that may have accumulated in the receiver
++       * due to line noise.
++       */
++
++      *ptr++ = END;
++
++      /*
++       * For each byte in the packet, send the appropriate
++       * character sequence, according to the SLIP protocol.
++       */
++
++      while (len-- > 0) {
++              switch(c = *s++) {
++              case END:
++                      *ptr++ = ESC;
++                      *ptr++ = ESC_END;
++                      break;
++              case ESC:
++                      *ptr++ = ESC;
++                      *ptr++ = ESC_ESC;
++                      break;
++              default:
++                      *ptr++ = c;
++                      break;
++              }
++      }
++      *ptr++ = END;
++      return (ptr - d);
++}
++
++int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
++{
++      int actual, n;
++
++      actual = slip_esc(buf, pri->buf, len);
++      n = net_write(fd, pri->buf, actual);
++      if(n < 0) return(n);
++      else return(len);
++}
++
++static int slip_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
++                        void *data)
++{
++      struct slip_data *pri = data;
++
++      if(pri->slave == -1) return;
++      open_addr(addr, netmask, pri->name);
++}
++
++static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct slip_data *pri = data;
++
++      if(pri->slave == -1) return;
++      close_addr(addr, netmask, pri->name);
++}
++
++struct net_user_info slip_user_info = {
++      init:           slip_user_init,
++      open:           slip_open,
++      close:          slip_close,
++      remove:         NULL,
++      set_mtu:        slip_set_mtu,
++      add_address:    slip_add_addr,
++      delete_address: slip_del_addr,
++      max_packet:     BUF_SIZE
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/ssl.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,226 @@
++/* 
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/fs.h"
++#include "linux/tty.h"
++#include "linux/tty_driver.h"
++#include "linux/major.h"
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "asm/termbits.h"
++#include "asm/irq.h"
++#include "line.h"
++#include "ssl.h"
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "2_5compat.h"
++
++static int ssl_version = 1;
++
++static struct tty_driver ssl_driver;
++
++static int ssl_refcount = 0;
++
++#define NR_PORTS 64
++
++void ssl_announce(char *dev_name, int dev)
++{
++      printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
++             dev_name);
++}
++
++static struct chan_opts opts = {
++      announce:       ssl_announce,
++      xterm_title:    "Serial Line #%d",
++      raw:            1,
++      tramp_stack :   0,
++};
++
++static struct line_driver driver = {
++      name :                  "UML serial line",
++      devfs_name :            "tts/%d",
++      major :                 TTYAUX_MAJOR,
++      minor_start :           64,
++      type :                  TTY_DRIVER_TYPE_SERIAL,
++      subtype :               0,
++      read_irq :              SSL_IRQ,
++      read_irq_name :         "ssl",
++      write_irq :             SSL_WRITE_IRQ,
++      write_irq_name :        "ssl-write",
++      symlink_from :          "serial",
++      symlink_to :            "tts",
++};
++
++static struct line serial_lines[NR_PORTS] = 
++      { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
++
++static struct lines lines = LINES_INIT(NR_PORTS);
++
++int ssl_open(struct tty_struct *tty, struct file *filp)
++{
++      return(line_open(serial_lines, tty, &opts));
++}
++
++static void ssl_close(struct tty_struct *tty, struct file * filp)
++{
++      line_close(serial_lines, tty);
++}
++
++static int ssl_write(struct tty_struct * tty, int from_user,
++                   const unsigned char *buf, int count)
++{
++      return(line_write(serial_lines, tty, buf, count));
++}
++
++static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
++{
++      line_write(serial_lines, tty, &ch, sizeof(ch));
++}
++
++static void ssl_flush_chars(struct tty_struct *tty)
++{
++      return;
++}
++
++static int ssl_chars_in_buffer(struct tty_struct *tty)
++{
++      return(0);
++}
++
++static void ssl_flush_buffer(struct tty_struct *tty)
++{
++      return;
++}
++
++static int ssl_ioctl(struct tty_struct *tty, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      int ret;
++
++      ret = 0;
++      switch(cmd){
++      case TCGETS:
++      case TCSETS:
++      case TCFLSH:
++      case TCSETSF:
++      case TCSETSW:
++      case TCGETA:
++      case TIOCMGET:
++              ret = -ENOIOCTLCMD;
++              break;
++      default:
++              printk(KERN_ERR 
++                     "Unimplemented ioctl in ssl_ioctl : 0x%x\n", cmd);
++              ret = -ENOIOCTLCMD;
++              break;
++      }
++      return(ret);
++}
++
++static void ssl_throttle(struct tty_struct * tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_throttle\n");
++}
++
++static void ssl_unthrottle(struct tty_struct * tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
++}
++
++static void ssl_set_termios(struct tty_struct *tty, 
++                          struct termios *old_termios)
++{
++}
++
++static void ssl_stop(struct tty_struct *tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_stop\n");
++}
++
++static void ssl_start(struct tty_struct *tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_start\n");
++}
++
++void ssl_hangup(struct tty_struct *tty)
++{
++}
++
++static int ssl_init_done = 0;
++
++int ssl_init(void)
++{
++      char *new_title;
++
++      printk(KERN_INFO "Initializing software serial port version %d\n", 
++             ssl_version);
++
++      ssl_driver = ((struct tty_driver)
++                    {
++                            refcount :        &ssl_refcount,
++                            open :            ssl_open,
++                            close :           ssl_close,
++                            write :           ssl_write,
++                            put_char :        ssl_put_char,
++                            flush_chars :     ssl_flush_chars,
++                            chars_in_buffer : ssl_chars_in_buffer,
++                            flush_buffer :    ssl_flush_buffer,
++                            ioctl :           ssl_ioctl,
++                            throttle :        ssl_throttle,
++                            unthrottle :      ssl_unthrottle,
++                            set_termios :     ssl_set_termios,
++                            stop :            ssl_stop,
++                            start :           ssl_start,
++                            hangup :          ssl_hangup
++                    });
++
++      line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, 
++                          sizeof(serial_lines)/sizeof(serial_lines[0]));
++
++      lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
++
++      new_title = add_xterm_umid(opts.xterm_title);
++      if(new_title != NULL) opts.xterm_title = new_title;
++
++      ssl_init_done = 1;
++      return(0);
++}
++
++__initcall(ssl_init);
++
++static int ssl_chan_setup(char *str)
++{
++      line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
++                 str);
++      return(1);
++}
++
++__setup("ssl", ssl_chan_setup);
++__channel_help(ssl_chan_setup, "ssl");
++
++static void ssl_exit(void)
++{
++      if(!ssl_init_done) return;
++      close_lines(serial_lines, 
++                  sizeof(serial_lines)/sizeof(serial_lines[0]));
++}
++
++__uml_exitcall(ssl_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/ssl.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SSL_H__
++#define __SSL_H__
++
++extern int ssl_read(int fd, int line);
++extern void ssl_receive_char(int line, char ch);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/stdio_console.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,211 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/posix_types.h"
++#include "linux/tty.h"
++#include "linux/tty_flip.h"
++#include "linux/types.h"
++#include "linux/major.h"
++#include "linux/kdev_t.h"
++#include "linux/console.h"
++#include "linux/string.h"
++#include "linux/sched.h"
++#include "linux/list.h"
++#include "linux/init.h"
++#include "linux/interrupt.h"
++#include "linux/slab.h"
++#include "asm/current.h"
++#include "asm/softirq.h"
++#include "asm/hardirq.h"
++#include "asm/irq.h"
++#include "stdio_console.h"
++#include "line.h"
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "init.h"
++#include "2_5compat.h"
++
++#define MAX_TTYS (8)
++
++static struct tty_driver console_driver;
++
++static struct chan_ops init_console_ops = {
++      init :          NULL,
++      open :          NULL,
++      close :         NULL,
++      read :          NULL,
++      write :         NULL,
++      console_write : generic_write,
++      window_size :   NULL,
++      free :          NULL,
++      winch:          0,
++};
++
++static struct chan init_console_chan = {
++      list :          { },
++      primary :       1,
++      input :         0,
++      output :        1,
++      opened :        1,
++      fd :            1,
++      pri :           INIT_STATIC,
++      ops :           &init_console_ops,
++      data :          NULL
++};
++
++void stdio_announce(char *dev_name, int dev)
++{
++      printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
++             dev_name);
++}
++
++static struct chan_opts opts = {
++      announce:       stdio_announce,
++      xterm_title:    "Virtual Console #%d",
++      raw:            1,
++      tramp_stack :   0,
++};
++
++static struct line_driver driver = {
++      name :                  "UML console",
++      devfs_name :            "vc/%d",
++      major :                 TTY_MAJOR,
++      minor_start :           0,
++      type :                  TTY_DRIVER_TYPE_CONSOLE,
++      subtype :               SYSTEM_TYPE_CONSOLE,
++      read_irq :              CONSOLE_IRQ,
++      read_irq_name :         "console",
++      write_irq :             CONSOLE_WRITE_IRQ,
++      write_irq_name :        "console-write",
++      symlink_from :          "ttys",
++      symlink_to :            "vc",
++};
++
++static struct lines console_lines = LINES_INIT(MAX_TTYS);
++
++struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
++                            [ 1 ... MAX_TTYS - 1 ] = 
++                            LINE_INIT(CONFIG_CON_CHAN, &driver) };
++
++static int open_console(struct tty_struct *tty)
++{
++      return(line_open(vts, tty, &opts));
++}
++
++static int con_open(struct tty_struct *tty, struct file *filp)
++{
++      return(open_console(tty));
++}
++
++static void con_close(struct tty_struct *tty, struct file *filp)
++{
++      line_close(vts, tty);
++}
++
++static int con_write(struct tty_struct *tty, int from_user, 
++                   const unsigned char *buf, int count)
++{
++      return(line_write(vts, tty, buf, count));
++}
++
++static void set_termios(struct tty_struct *tty, struct termios * old)
++{
++}
++
++static int chars_in_buffer(struct tty_struct *tty)
++{
++      return(0);
++}
++
++static int con_init_done = 0;
++
++int stdio_init(void)
++{
++      char *new_title;
++
++      printk(KERN_INFO "Initializing stdio console driver\n");
++
++      console_driver = ((struct tty_driver)
++                    {
++                            open :            con_open,
++                            close :           con_close,
++                            write :           con_write,
++                            chars_in_buffer : chars_in_buffer,
++                            set_termios :     set_termios
++                    });
++
++      line_register_devfs(&console_lines, &driver, &console_driver, vts, 
++                          sizeof(vts)/sizeof(vts[0]));
++
++      lines_init(vts, sizeof(vts)/sizeof(vts[0]));
++
++      new_title = add_xterm_umid(opts.xterm_title);
++      if(new_title != NULL) opts.xterm_title = new_title;
++
++      open_console(NULL);
++      con_init_done = 1;
++      return(0);
++}
++
++__initcall(stdio_init);
++
++static void console_write(struct console *console, const char *string, 
++                        unsigned len)
++{
++      console_write_chan(&vts[console->index].chan_list, string, len);
++}
++
++static kdev_t console_device(struct console *c)
++{
++      return mk_kdev(TTY_MAJOR, c->index);
++}
++
++static int console_setup(struct console *co, char *options)
++{
++      return(0);
++}
++
++static struct console stdiocons = INIT_CONSOLE("tty", console_write, 
++                                             console_device, console_setup,
++                                             CON_PRINTBUFFER);
++
++void stdio_console_init(void)
++{
++      INIT_LIST_HEAD(&vts[0].chan_list);
++      list_add(&init_console_chan.list, &vts[0].chan_list);
++      register_console(&stdiocons);
++}
++
++static int console_chan_setup(char *str)
++{
++      line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
++      return(1);
++}
++
++__setup("con", console_chan_setup);
++__channel_help(console_chan_setup, "con");
++
++static void console_exit(void)
++{
++      if(!con_init_done) return;
++      line_close(vts, NULL);
++      close_lines(vts, sizeof(vts)/sizeof(vts[0]));
++}
++
++__uml_exitcall(console_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/stdio_console.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,21 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __STDIO_CONSOLE_H
++#define __STDIO_CONSOLE_H
++
++extern void save_console_flags(void);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/tty.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,82 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <termios.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <unistd.h>
++#include "chan_user.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++struct tty_chan {
++      char *dev;
++      int raw;
++      struct termios tt;
++};
++
++void *tty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++      struct tty_chan *data;
++
++      if(*str != ':'){
++              printk("tty_init : channel type 'tty' must specify "
++                     "a device\n");
++              return(NULL);
++      }
++      str++;
++
++      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      *data = ((struct tty_chan) { dev :      str,
++                                   raw :      opts->raw });
++                                   
++      return(data);
++}
++
++int tty_open(int input, int output, int primary, void *d)
++{
++      struct tty_chan *data = d;
++      int fd;
++
++      fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
++      if(fd < 0) return(fd);
++      if(data->raw){
++              tcgetattr(fd, &data->tt);
++              raw(fd, 0);
++      }
++      return(fd);
++}
++
++int tty_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct tty_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops tty_ops = {
++      init:           tty_chan_init,
++      open:           tty_open,
++      close:          generic_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  tty_console_write,
++      window_size:    generic_window_size,
++      free:           generic_free,
++      winch:          0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/ubd_kern.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,941 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++/* 2001-09-28...2002-04-17
++ * Partition stuff by James_McMechan@hotmail.com
++ * old style ubd by setting UBD_SHIFT to 0
++ */
++
++#define MAJOR_NR UBD_MAJOR
++#define UBD_SHIFT 4
++
++#include "linux/config.h"
++#include "linux/blk.h"
++#include "linux/blkdev.h"
++#include "linux/hdreg.h"
++#include "linux/init.h"
++#include "linux/devfs_fs_kernel.h"
++#include "linux/cdrom.h"
++#include "linux/proc_fs.h"
++#include "linux/ctype.h"
++#include "linux/capability.h"
++#include "linux/mm.h"
++#include "linux/vmalloc.h"
++#include "linux/blkpg.h"
++#include "linux/genhd.h"
++#include "asm/segment.h"
++#include "asm/uaccess.h"
++#include "asm/irq.h"
++#include "asm/types.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mconsole_kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "ubd_user.h"
++#include "2_5compat.h"
++#include "os.h"
++
++static int ubd_open(struct inode * inode, struct file * filp);
++static int ubd_release(struct inode * inode, struct file * file);
++static int ubd_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg);
++static int ubd_revalidate(kdev_t rdev);
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << UBD_SHIFT)
++
++/* block size in bytes */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++
++/* number of bytes per sector */
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* device size in KB */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct block_device_operations ubd_blops = {
++        open:         ubd_open,
++        release:      ubd_release,
++        ioctl:                ubd_ioctl,
++        revalidate:   ubd_revalidate,
++};
++
++static struct hd_struct       ubd_part[MAX_MINOR] = 
++      { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++static request_queue_t *ubd_queue;
++
++static int fake_major = 0;
++
++#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
++{ \
++      major :         maj, \
++      major_name :    name, \
++      minor_shift :   shift, \
++      max_p :         1 << shift, \
++      part :          parts, \
++      sizes :         bsizes, \
++      nr_real :       max, \
++      real_devices :  NULL, \
++      next :          NULL, \
++      fops :          blops, \
++      de_arr :        NULL, \
++      flags :         0 \
++}
++
++static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part,
++                                               UBD_SHIFT, sizes, MAX_DEV, 
++                                               &ubd_blops);
++static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part, 
++                                                UBD_SHIFT, sizes, MAX_DEV, 
++                                                &ubd_blops);
++
++#ifdef CONFIG_BLK_DEV_UBD_SYNC
++#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 1, c : 0 })
++#else
++#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 0, c : 0 })
++#endif
++
++static struct openflags global_openflags = OPEN_FLAGS;
++
++struct cow {
++      char *file;
++      int fd;
++      unsigned long *bitmap;
++      unsigned long bitmap_len;
++      int bitmap_offset;
++        int data_offset;
++};
++
++struct ubd {
++      char *file;
++      int is_dir;
++      int count;
++      int fd;
++      __u64 size;
++      struct openflags boot_openflags;
++      struct openflags openflags;
++      devfs_handle_t real;
++      devfs_handle_t fake;
++      struct cow cow;
++};
++
++#define DEFAULT_COW { \
++      file:                   NULL, \
++        fd:                   -1, \
++        bitmap:                       NULL, \
++      bitmap_offset:          0, \
++        data_offset:          0, \
++}
++
++#define DEFAULT_UBD { \
++      file:                   NULL, \
++      is_dir:                 0, \
++      count:                  0, \
++      fd:                     -1, \
++      size:                   -1, \
++      boot_openflags:         OPEN_FLAGS, \
++      openflags:              OPEN_FLAGS, \
++      real:                   NULL, \
++      fake:                   NULL, \
++        cow:                  DEFAULT_COW, \
++}
++
++struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
++
++static int ubd0_init(void)
++{
++      if(ubd_dev[0].file == NULL)
++              ubd_dev[0].file = "root_fs";
++      return(0);
++}
++
++__initcall(ubd0_init);
++
++static struct hd_driveid ubd_id = {
++        cyls:         0,
++      heads:          128,
++      sectors:        32,
++};
++
++static int fake_ide = 0;
++static struct proc_dir_entry *proc_ide_root = NULL;
++static struct proc_dir_entry *proc_ide = NULL;
++
++static void make_proc_ide(void)
++{
++      proc_ide_root = proc_mkdir("ide", 0);
++      proc_ide = proc_mkdir("ide0", proc_ide_root);
++}
++
++static int proc_ide_read_media(char *page, char **start, off_t off, int count,
++                             int *eof, void *data)
++{
++      int len;
++
++      strcpy(page, "disk\n");
++      len = strlen("disk\n");
++      len -= off;
++      if (len < count){
++              *eof = 1;
++              if (len <= 0) return 0;
++      }
++      else len = count;
++      *start = page + off;
++      return len;
++      
++}
++
++static void make_ide_entries(char *dev_name)
++{
++      struct proc_dir_entry *dir, *ent;
++      char name[64];
++
++      if(!fake_ide) return;
++      if(proc_ide_root == NULL) make_proc_ide();
++      dir = proc_mkdir(dev_name, proc_ide);
++      ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
++      if(!ent) return;
++      ent->nlink = 1;
++      ent->data = NULL;
++      ent->read_proc = proc_ide_read_media;
++      ent->write_proc = NULL;
++      sprintf(name,"ide0/%s", dev_name);
++      proc_symlink(dev_name, proc_ide_root, name);
++}
++
++static int fake_ide_setup(char *str)
++{
++      fake_ide = 1;
++      return(1);
++}
++
++__setup("fake_ide", fake_ide_setup);
++
++__uml_help(fake_ide_setup,
++"fake_ide\n"
++"    Create ide0 entries that map onto ubd devices.\n\n"
++);
++
++static int ubd_setup_common(char *str, int *index_out)
++{
++      struct openflags flags = global_openflags;
++      char *backing_file;
++      int n;
++
++      if(index_out) *index_out = -1;
++      n = *str++;
++      if(n == '='){
++              char *end;
++              int major;
++
++              if(!strcmp(str, "sync")){
++                      global_openflags.s = 1;
++                      return(0);
++              }
++              major = simple_strtoul(str, &end, 0);
++              if(*end != '\0'){
++                      printk(KERN_ERR 
++                             "ubd_setup : didn't parse major number\n");
++                      return(1);
++              }
++              fake_gendisk.major = major;
++              fake_major = major;
++              printk(KERN_INFO "Setting extra ubd major number to %d\n",
++                     major);
++              return(0);
++      }
++
++      if(n < '0'){
++              printk(KERN_ERR "ubd_setup : index out of range\n"); }
++
++      if((n >= '0') && (n <= '9')) n -= '0';
++      else if((n >= 'a') && (n <= 'z')) n -= 'a';
++      else {
++              printk(KERN_ERR "ubd_setup : device syntax invalid\n");
++              return(1);
++      }
++      if(n >= MAX_DEV){
++              printk(KERN_ERR "ubd_setup : index out of range "
++                     "(%d devices)\n", MAX_DEV);      
++              return(1);
++      }
++
++      if(ubd_dev[n].file != NULL){
++              printk(KERN_ERR "ubd_setup : device already configured\n");
++              return(1);
++      }
++
++      if(index_out) *index_out = n;
++
++      if (*str == 'r'){
++              flags.w = 0;
++              str++;
++      }
++      if (*str == 's'){
++              flags.s = 1;
++              str++;
++      }
++      if(*str++ != '='){
++              printk(KERN_ERR "ubd_setup : Expected '='\n");
++              return(1);
++      }
++      backing_file = strchr(str, ',');
++      if(backing_file){
++              *backing_file = '\0';
++              backing_file++;
++      }
++      ubd_dev[n].file = str;
++      ubd_dev[n].cow.file = backing_file;
++      ubd_dev[n].boot_openflags = flags;
++      return(0);
++}
++
++static int ubd_setup(char *str)
++{
++      ubd_setup_common(str, NULL);
++      return(1);
++}
++
++__setup("ubd", ubd_setup);
++__uml_help(ubd_setup,
++"ubd<n>=<filename>\n"
++"    This is used to associate a device with a file in the underlying\n"
++"    filesystem. Usually, there is a filesystem in the file, but \n"
++"    that's not required. Swap devices containing swap files can be\n"
++"    specified like this. Also, a file which doesn't contain a\n"
++"    filesystem can have its contents read in the virtual \n"
++"    machine by running dd on the device. n must be in the range\n"
++"    0 to 7. Appending an 'r' to the number will cause that device\n"
++"    to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
++"    an 's' (has to be _after_ 'r', if there is one) will cause data\n"
++"    to be written to disk on the host immediately.\n\n"
++);
++
++static int fakehd(char *str)
++{
++      printk(KERN_INFO 
++             "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
++      ubd_gendisk.major_name = "hd";
++      return(1);
++}
++
++__setup("fakehd", fakehd);
++__uml_help(fakehd,
++"fakehd\n"
++"    Change the ubd device name to \"hd\".\n\n"
++);
++
++static void do_ubd_request(request_queue_t * q);
++
++int thread_fd = -1;
++
++int intr_count = 0;
++
++static void ubd_finish(int error)
++{
++      int nsect;
++
++      if(error){
++              end_request(0);
++              return;
++      }
++      nsect = CURRENT->current_nr_sectors;
++      CURRENT->sector += nsect;
++      CURRENT->buffer += nsect << 9;
++      CURRENT->errors = 0;
++      CURRENT->nr_sectors -= nsect;
++      CURRENT->current_nr_sectors = 0;
++      end_request(1);
++}
++
++static void ubd_handler(void)
++{
++      struct io_thread_req req;
++      int n;
++
++      DEVICE_INTR = NULL;
++      intr_count++;
++      n = read_ubd_fs(thread_fd, &req, sizeof(req));
++      if(n != sizeof(req)){
++              printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
++                     "errno = %d\n", os_getpid(), -n);
++              spin_lock(&REQUEST_LOCK);
++              end_request(0);
++              spin_unlock(&REQUEST_LOCK);
++              return;
++      }
++        
++        if((req.offset != ((__u64) (CURRENT->sector)) << 9) ||
++         (req.length != (CURRENT->current_nr_sectors) << 9))
++              panic("I/O op mismatch");
++      
++      spin_lock(&REQUEST_LOCK);
++      ubd_finish(req.error);
++      reactivate_fd(thread_fd, UBD_IRQ);      
++      do_ubd_request(ubd_queue);
++      spin_unlock(&REQUEST_LOCK);
++}
++
++static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
++{
++      ubd_handler();
++}
++
++static int io_pid = -1;
++
++void kill_io_thread(void)
++{
++      if(io_pid != -1) kill(io_pid, SIGKILL);
++}
++
++__uml_exitcall(kill_io_thread);
++
++int sync = 0;
++
++devfs_handle_t ubd_dir_handle;
++devfs_handle_t ubd_fake_dir_handle;
++
++static int ubd_add(int n)
++{
++      devfs_handle_t real, fake;
++      char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
++      int err;
++
++      if(ubd_dev[n].file == NULL) return(-1);
++
++      err = ubd_revalidate(MKDEV(MAJOR_NR, n << UBD_SHIFT));
++      if(err)
++              return(err);
++
++      sprintf(name, "%d", n);
++      real = devfs_register(ubd_dir_handle, name, DEVFS_FL_REMOVABLE,
++                            MAJOR_NR, n << UBD_SHIFT,
++                            S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++                            &ubd_blops, NULL);
++
++      if(fake_major != 0){
++              fake = devfs_register(ubd_fake_dir_handle, name, 
++                                    DEVFS_FL_REMOVABLE, fake_major,
++                                    n << UBD_SHIFT, 
++                                    S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | 
++                                    S_IWGRP, &ubd_blops, NULL);
++              if(fake == NULL) return(-1);
++              ubd_dev[n].fake = fake;
++      }
++
++      if(real == NULL) return(-1);
++      ubd_dev[n].real = real;
++
++      if(!strcmp(ubd_gendisk.major_name, "ubd"))
++              sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n);
++      else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
++                   n + 'a');
++
++      make_ide_entries(dev_name);
++      return(0);
++}
++
++static int ubd_config(char *str)
++{
++      int n, err;
++
++      str = uml_strdup(str);
++      if(str == NULL){
++              printk(KERN_ERR "ubd_config failed to strdup string\n");
++              return(1);
++      }
++      err = ubd_setup_common(str, &n);
++      if(err){
++              kfree(str);
++              return(-1);
++      }
++      if(n == -1) return(0);
++
++      err = ubd_add(n);
++      if(err){
++              ubd_dev[n].file = NULL;
++              return(err);
++      }
++
++      return(0);
++}
++
++static int ubd_remove(char *str)
++{
++      struct ubd *dev;
++      int n;
++
++      if(!isdigit(*str)) return(-1);
++      n = *str - '0';
++      if(n > MAX_DEV) return(-1);
++      dev = &ubd_dev[n];
++      if(dev->file == NULL) return(0);
++      if(dev->count > 0) return(-1);
++      if(dev->real != NULL) devfs_unregister(dev->real);
++      if(dev->fake != NULL) devfs_unregister(dev->fake);
++      *dev = ((struct ubd) DEFAULT_UBD);
++      return(0);
++}
++
++static struct mc_device ubd_mc = {
++      name:           "ubd",
++      config:         ubd_config,
++      remove:         ubd_remove,
++};
++
++static int ubd_mc_init(void)
++{
++      mconsole_register_dev(&ubd_mc);
++      return(0);
++}
++
++__initcall(ubd_mc_init);
++
++static request_queue_t *ubd_get_queue(kdev_t device)
++{
++      return(ubd_queue);
++}
++
++int ubd_init(void)
++{
++      unsigned long stack;
++        int i, err;
++
++      ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL);
++      if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) {
++              printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR);
++              return -1;
++      }
++      ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++      INIT_QUEUE(ubd_queue, DEVICE_REQUEST, &ubd_lock);
++      INIT_ELV(ubd_queue, &ubd_queue->elevator);
++      read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
++      blksize_size[MAJOR_NR] = blk_sizes;
++      blk_size[MAJOR_NR] = sizes;
++      INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
++        add_gendisk(&ubd_gendisk);
++      if (fake_major != 0){
++              char name[sizeof("ubd_nnn\0")];
++
++              snprintf(name, sizeof(name), "ubd_%d", fake_major);
++              ubd_fake_dir_handle = devfs_mk_dir(NULL, name, NULL);
++              if(devfs_register_blkdev(fake_major, "ubd", &ubd_blops)) {
++                      printk(KERN_ERR "ubd: unable to get major %d\n",
++                             fake_major);
++                      return -1;
++              }
++              blk_dev[fake_major].queue = ubd_get_queue;
++              read_ahead[fake_major] = 8;     /* 8 sector (4kB) read-ahead */
++              blksize_size[fake_major] = blk_sizes;
++              blk_size[fake_major] = sizes;
++              INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
++                add_gendisk(&fake_gendisk);
++      }
++      for(i=0;i<MAX_DEV;i++) ubd_add(i);
++      if(sync){
++              printk(KERN_INFO "ubd : Synchronous mode\n");
++              return(0);
++      }
++      stack = alloc_stack(0, 0);
++      io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
++                               &thread_fd);
++      if(io_pid < 0){
++              printk(KERN_ERR 
++                     "ubd : Failed to start I/O thread (errno = %d) - "
++                     "falling back to synchronous I/O\n", -io_pid);
++              return(0);
++      }
++      err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
++                           SA_INTERRUPT, "ubd", ubd_dev);
++      if(err != 0) printk(KERN_ERR 
++                          "um_request_irq failed - errno = %d\n", -err);
++      return(err);
++}
++
++__initcall(ubd_init);
++
++static void ubd_close(struct ubd *dev)
++{
++      close_fd(dev->fd);
++      if(dev->cow.file != NULL) {
++              close_fd(dev->cow.fd);
++              vfree(dev->cow.bitmap);
++              dev->cow.bitmap = NULL;
++      }
++}
++
++static int ubd_open_dev(struct ubd *dev)
++{
++      struct openflags flags;
++      int err, n, create_cow, *create_ptr;
++
++      create_cow = 0;
++      create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
++      dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
++                              &dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
++                              &dev->cow.data_offset, create_ptr);
++
++      if((dev->fd == -ENOENT) && create_cow){
++              n = dev - ubd_dev;
++              dev->fd = create_cow_file(dev->file, dev->cow.file, 
++                                        dev->openflags, 1 << 9,
++                                        &dev->cow.bitmap_offset, 
++                                        &dev->cow.bitmap_len,
++                                        &dev->cow.data_offset);
++              if(dev->fd >= 0){
++                      printk(KERN_INFO "Creating \"%s\" as COW file for "
++                             "\"%s\"\n", dev->file, dev->cow.file);
++              }
++      }
++
++      if(dev->fd < 0) return(dev->fd);
++
++      if(dev->cow.file != NULL){
++              err = -ENOMEM;
++              dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
++              if(dev->cow.bitmap == NULL) goto error;
++              flush_tlb_kernel_vm();
++
++              err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
++                                    dev->cow.bitmap_offset, 
++                                    dev->cow.bitmap_len);
++              if(err) goto error;
++
++              flags = dev->openflags;
++              flags.w = 0;
++              err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, 
++                                  NULL, NULL);
++              if(err < 0) goto error;
++              dev->cow.fd = err;
++      }
++      return(0);
++ error:
++      close_fd(dev->fd);
++      return(err);
++}
++
++static int ubd_file_size(struct ubd *dev, __u64 *size_out)
++{
++      char *file;
++
++      file = dev->cow.file ? dev->cow.file : dev->file;
++      return(os_file_size(file, size_out));
++}
++
++static int ubd_open(struct inode *inode, struct file *filp)
++{
++      struct ubd *dev;
++      int n, offset, err;
++
++      n = DEVICE_NR(inode->i_rdev);
++      dev = &ubd_dev[n];
++      if(n > MAX_DEV)
++              return -ENODEV;
++      offset = n << UBD_SHIFT;
++      if(ubd_is_dir(dev->file)){
++              dev->is_dir = 1;
++              return(0);
++      }
++      if(dev->count == 0){
++              dev->openflags = dev->boot_openflags;
++
++              err = ubd_open_dev(dev);
++              if(err){
++                      printk(KERN_ERR "ubd%d: Can't open \"%s\": "
++                             "errno = %d\n", n, dev->file, -err);
++                      return(err);
++              }
++              err = ubd_file_size(dev, &dev->size);
++              if(err) return(err);
++              sizes[offset] = dev->size / BLOCK_SIZE;
++              ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset];
++      }
++      dev->count++;
++      if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
++              if(--dev->count == 0) ubd_close(dev);
++              return -EROFS;
++      }
++      return(0);
++}
++
++static int ubd_release(struct inode * inode, struct file * file)
++{
++        int n, offset;
++
++      n =  DEVICE_NR(inode->i_rdev);
++      offset = n << UBD_SHIFT;
++      if(n > MAX_DEV)
++              return -ENODEV;
++      if(--ubd_dev[n].count == 0){
++              ubd_close(&ubd_dev[n]);
++              sizes[offset] = 0;
++              ubd_part[offset].nr_sects = 0;
++      }
++      return(0);
++}
++
++int cow_read = 0;
++int cow_write = 0;
++
++void cowify_req(struct io_thread_req *req, struct ubd *dev)
++{
++        int i, update_bitmap, sector = req->offset >> 9;
++
++      if(req->length > (sizeof(req->sector_mask) * 8) << 9)
++              panic("Operation too long");
++      if(req->op == UBD_READ) {
++              for(i = 0; i < req->length >> 9; i++){
++                      if(ubd_test_bit(sector + i, (unsigned char *) 
++                                      dev->cow.bitmap)){
++                              ubd_set_bit(i, (unsigned char *) 
++                                          &req->sector_mask);
++                              cow_read++;
++                      }
++                }
++        } 
++        else {
++              update_bitmap = 0;
++              for(i = 0; i < req->length >> 9; i++){
++                      cow_write++;
++                      ubd_set_bit(i, (unsigned char *) 
++                                  &req->sector_mask);
++                      if(!ubd_test_bit(sector + i, (unsigned char *) 
++                                       dev->cow.bitmap))
++                              update_bitmap = 1;
++                      ubd_set_bit(sector + i, (unsigned char *) 
++                                  dev->cow.bitmap);
++              }
++              if(update_bitmap){
++                      req->cow_offset = sector / (sizeof(unsigned long) * 8);
++                      req->bitmap_words[0] = 
++                              dev->cow.bitmap[req->cow_offset];
++                      req->bitmap_words[1] = 
++                              dev->cow.bitmap[req->cow_offset + 1];
++                      req->cow_offset *= sizeof(unsigned long);
++                      req->cow_offset += dev->cow.bitmap_offset;
++              }
++      }
++}
++
++static int prepare_request(struct request *req, struct io_thread_req *io_req)
++{
++      struct ubd *dev;
++      __u64 block;
++      int nsect, minor, n;
++
++      if(req->rq_status == RQ_INACTIVE) return(1);
++
++      minor = MINOR(req->rq_dev);
++      n = minor >> UBD_SHIFT;
++      dev = &ubd_dev[n];
++      if(dev->is_dir){
++              strcpy(req->buffer, "HOSTFS:");
++              strcat(req->buffer, dev->file);
++              end_request(1);
++              return(1);
++      }
++      if(IS_WRITE(req) && !dev->openflags.w){
++              printk("Write attempted on readonly ubd device %d\n", n);
++              end_request(0);
++              return(1);
++      }
++
++        req->sector += ubd_part[minor].start_sect;
++        block = req->sector;
++        nsect = req->current_nr_sectors;
++
++      io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE;
++      io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
++      io_req->fds[1] = dev->fd;
++      io_req->offsets[0] = 0;
++      io_req->offsets[1] = dev->cow.data_offset;
++      io_req->offset = ((__u64) block) << 9;
++      io_req->length = nsect << 9;
++      io_req->buffer = req->buffer;
++      io_req->sectorsize = 1 << 9;
++      io_req->sector_mask = 0;
++      io_req->cow_offset = -1;
++      io_req->error = 0;
++
++        if(dev->cow.file != NULL) cowify_req(io_req, dev);
++      return(0);
++}
++
++static void do_ubd_request(request_queue_t *q)
++{
++      struct io_thread_req io_req;
++      struct request *req;
++      int err, n;
++
++      if(thread_fd == -1){
++              while(!list_empty(&q->queue_head)){
++                      req = blkdev_entry_next_request(&q->queue_head);
++                      err = prepare_request(req, &io_req);
++                      if(!err){
++                              do_io(&io_req);
++                              ubd_finish(io_req.error);
++                      }
++              }
++      }
++      else {
++              if(DEVICE_INTR || list_empty(&q->queue_head)) return;
++              req = blkdev_entry_next_request(&q->queue_head);
++              err = prepare_request(req, &io_req);
++              if(!err){
++                      SET_INTR(ubd_handler);
++                      n = write_ubd_fs(thread_fd, (char *) &io_req, 
++                                       sizeof(io_req));
++                      if(n != sizeof(io_req))
++                              printk("write to io thread failed, "
++                                     "errno = %d\n", -n);
++              }
++      }
++}
++
++static int ubd_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      struct hd_geometry *loc = (struct hd_geometry *) arg;
++      struct ubd *dev;
++      int n, minor, err;
++
++        if(!inode) return(-EINVAL);
++      minor = MINOR(inode->i_rdev);
++      n = minor >> UBD_SHIFT;
++      if(n > MAX_DEV)
++              return(-EINVAL);
++      dev = &ubd_dev[n];
++      switch (cmd) {
++              struct hd_geometry g;
++              struct cdrom_volctrl volume;
++      case HDIO_GETGEO:
++              if(!loc) return(-EINVAL);
++              g.heads = 128;
++              g.sectors = 32;
++              g.cylinders = dev->size / (128 * 32 * hardsect_sizes[minor]);
++              g.start = 2;
++              return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
++      case BLKGETSIZE:   /* Return device size */
++              if(!arg) return(-EINVAL);
++              err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
++              if(err)
++                      return(err);
++              put_user(ubd_part[minor].nr_sects, (long *) arg);
++              return(0);
++      case BLKRRPART: /* Re-read partition tables */
++              return(ubd_revalidate(inode->i_rdev));
++
++      case HDIO_SET_UNMASKINTR:
++              if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
++              if((arg > 1) || (minor & 0x3F)) return(-EINVAL);
++              return(0);
++
++      case HDIO_GET_UNMASKINTR:
++              if(!arg)  return(-EINVAL);
++              err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
++              if(err)
++                      return(err);
++              return(0);
++
++      case HDIO_GET_MULTCOUNT:
++              if(!arg)  return(-EINVAL);
++              err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
++              if(err)
++                      return(err);
++              return(0);
++
++      case HDIO_SET_MULTCOUNT:
++              if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
++              if(MINOR(inode->i_rdev) & 0x3F) return(-EINVAL);
++              return(0);
++
++      case HDIO_GET_IDENTITY:
++              ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[minor]);
++              if(copy_to_user((char *) arg, (char *) &ubd_id, 
++                               sizeof(ubd_id)))
++                      return(-EFAULT);
++              return(0);
++              
++      case CDROMVOLREAD:
++              if(copy_from_user(&volume, (char *) arg, sizeof(volume)))
++                      return(-EFAULT);
++              volume.channel0 = 255;
++              volume.channel1 = 255;
++              volume.channel2 = 255;
++              volume.channel3 = 255;
++              if(copy_to_user((char *) arg, &volume, sizeof(volume)))
++                      return(-EFAULT);
++              return(0);
++
++      default:
++              return blk_ioctl(inode->i_rdev, cmd, arg);
++      }
++}
++
++static int ubd_revalidate(kdev_t rdev)
++{
++      int i, n, offset, err, pcount = 1 << UBD_SHIFT;
++      struct ubd *dev;
++      struct hd_struct *part;
++
++      n = DEVICE_NR(rdev);
++      offset = n << UBD_SHIFT;
++      dev = &ubd_dev[n];
++      part = &ubd_part[offset];
++
++      /* clear all old partition counts */
++      for(i = 1; i < pcount; i++) {
++              part[i].start_sect = 0;
++              part[i].nr_sects = 0;
++      }
++
++      /* If it already has been opened we can check the partitions 
++       * directly 
++       */
++      if(dev->count){
++              part->start_sect = 0;
++              register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, 
++                            &ubd_blops, part->nr_sects);
++      } 
++      else if(dev->file){
++              err = ubd_open_dev(dev);
++              if(err){
++                      printk(KERN_ERR "unable to open %s for validation\n",
++                             dev->file);
++                      return(err);
++              }
++
++              /* have to recompute sizes since we opened it */
++              err = ubd_file_size(dev, &dev->size);
++              if(err) {
++                      ubd_close(dev);
++                      return(err);
++              }
++              part->start_sect = 0;
++              part->nr_sects = dev->size / hardsect_sizes[offset];
++              register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, 
++                            &ubd_blops, part->nr_sects);
++
++              /* we are done so close it */
++              ubd_close(dev);
++      } 
++      else return(-ENODEV);
++      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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/ubd_user.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,617 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sched.h>
++#include <signal.h>
++#include <string.h>
++#include <netinet/in.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/fcntl.h>
++#include <sys/socket.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "ubd_user.h"
++#include "os.h"
++
++#include <endian.h>
++#include <byteswap.h>
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define ntohll(x) (x)
++# define htonll(x) (x)
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++# define ntohll(x)  bswap_64(x)
++# define htonll(x)  bswap_64(x)
++#else
++#error "__BYTE_ORDER not defined"
++#endif
++
++#define PATH_LEN_V1 256
++
++struct cow_header_v1 {
++      int magic;
++      int version;
++      char backing_file[PATH_LEN_V1];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++#define PATH_LEN_V2 MAXPATHLEN
++
++struct cow_header_v2 {
++      unsigned long magic;
++      unsigned long version;
++      char backing_file[PATH_LEN_V2];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++union cow_header {
++      struct cow_header_v1 v1;
++      struct cow_header_v2 v2;
++};
++
++#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
++#define COW_VERSION 2
++
++static void sizes(__u64 size, int sectorsize, int bitmap_offset, 
++                unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
++
++      *data_offset_out = bitmap_offset + *bitmap_len_out;
++      *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
++      *data_offset_out *= sectorsize;
++}
++
++static int read_cow_header(int fd, int *magic_out, char **backing_file_out, 
++                         time_t *mtime_out, __u64 *size_out, 
++                         int *sectorsize_out, int *bitmap_offset_out)
++{
++      union cow_header *header;
++      char *file;
++      int err, n;
++      unsigned long version, magic;
++
++      header = um_kmalloc(sizeof(*header));
++      if(header == NULL){
++              printk("read_cow_header - Failed to allocate header\n");
++              return(-ENOMEM);
++      }
++      err = -EINVAL;
++      n = read(fd, header, sizeof(*header));
++      if(n < offsetof(typeof(header->v1), backing_file)){
++              printk("read_cow_header - short header\n");
++              goto out;
++      }
++
++      magic = header->v1.magic;
++      if(magic == COW_MAGIC) {
++              version = header->v1.version;
++      }
++      else if(magic == ntohl(COW_MAGIC)){
++              version = ntohl(header->v1.version);
++      }
++      else goto out;
++
++      *magic_out = COW_MAGIC;
++
++      if(version == 1){
++              if(n < sizeof(header->v1)){
++                      printk("read_cow_header - failed to read V1 header\n");
++                      goto out;
++              }
++              *mtime_out = header->v1.mtime;
++              *size_out = header->v1.size;
++              *sectorsize_out = header->v1.sectorsize;
++              *bitmap_offset_out = sizeof(header->v1);
++              file = header->v1.backing_file;
++      }
++      else if(version == 2){
++              if(n < sizeof(header->v2)){
++                      printk("read_cow_header - failed to read V2 header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v2.mtime);
++              *size_out = ntohll(header->v2.size);
++              *sectorsize_out = ntohl(header->v2.sectorsize);
++              *bitmap_offset_out = sizeof(header->v2);
++              file = header->v2.backing_file;
++      }
++      else {
++              printk("read_cow_header - invalid COW version\n");
++              goto out;
++      }
++      err = -ENOMEM;
++      *backing_file_out = uml_strdup(file);
++      if(*backing_file_out == NULL){
++              printk("read_cow_header - failed to allocate backing file\n");
++              goto out;
++      }
++      err = 0;
++ out:
++      kfree(header);
++      return(err);
++}
++
++static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
++{
++      struct stat buf1, buf2;
++
++      if(from_cmdline == NULL) return(1);
++      if(!strcmp(from_cmdline, from_cow)) return(1);
++
++      if(stat(from_cmdline, &buf1) < 0){
++              printk("Couldn't stat '%s', errno = %d\n", from_cmdline, 
++                     errno);
++              return(1);
++      }
++      if(stat(from_cow, &buf2) < 0){
++              printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
++              return(1);
++      }
++      if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino))
++              return(1);
++
++      printk("Backing file mismatch - \"%s\" requested,\n"
++             "\"%s\" specified in COW header of \"%s\"\n",
++             from_cmdline, from_cow, cow);
++      return(0);
++}
++
++static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
++{
++      struct stat64 buf;
++      long long actual;
++      int err;
++
++      if(stat64(file, &buf) < 0){
++              printk("Failed to stat backing file \"%s\", errno = %d\n",
++                     file, errno);
++              return(-errno);
++      }
++
++      err = os_file_size(file, &actual);
++      if(err){
++              printk("Failed to get size of backing file \"%s\", "
++                     "errno = %d\n", file, -err);
++              return(err);
++      }
++
++      if(actual != size){
++              printk("Size mismatch (%ld vs %ld) of COW header vs backing "
++                     "file\n", size, actual);
++              return(-EINVAL);
++      }
++      if(buf.st_mtime != mtime){
++              printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
++                     "file\n", mtime, buf.st_mtime);
++              return(-EINVAL);
++      }
++      return(0);
++}
++
++int read_cow_bitmap(int fd, void *buf, int offset, int len)
++{
++      int err;
++
++      err = os_seek_file(fd, offset);
++      if(err != 0) return(-errno);
++      err = read(fd, buf, len);
++      if(err < 0) return(-errno);
++      return(0);
++}
++
++static int absolutize(char *to, int size, char *from)
++{
++      char save_cwd[256], *slash;
++      int remaining;
++
++      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
++              printk("absolutize : unable to get cwd - errno = %d\n", errno);
++              return(-1);
++      }
++      slash = strrchr(from, '/');
++      if(slash != NULL){
++              *slash = '\0';
++              if(chdir(from)){
++                      *slash = '/';
++                      printk("absolutize : Can't cd to '%s' - errno = %d\n",
++                             from, errno);
++                      return(-1);
++              }
++              *slash = '/';
++              if(getcwd(to, size) == NULL){
++                      printk("absolutize : unable to get cwd of '%s' - "
++                             "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              remaining = size - strlen(to);
++              if(strlen(slash) + 1 > remaining){
++                      printk("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcat(to, slash);
++      }
++      else {
++              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
++                      printk("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcpy(to, save_cwd);
++              strcat(to, "/");
++              strcat(to, from);
++      }
++      chdir(save_cwd);
++      return(0);
++}
++
++static int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                          int sectorsize, long long *size)
++{
++        struct cow_header_v2 *header;
++      struct stat64 buf;
++      int err;
++
++      err = os_seek_file(fd, 0);
++      if(err != 0){
++              printk("write_cow_header - lseek failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      err = -ENOMEM;
++      header = um_kmalloc(sizeof(*header));
++      if(header == NULL){
++              printk("Failed to allocate COW V2 header\n");
++              goto out;
++      }
++      header->magic = htonl(COW_MAGIC);
++      header->version = htonl(COW_VERSION);
++
++      err = -EINVAL;
++      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
++              printk("Backing file name \"%s\" is too long - names are "
++                     "limited to %d characters\n", backing_file, 
++                     sizeof(header->backing_file) - 1);
++              goto out_free;
++      }
++
++      if(absolutize(header->backing_file, sizeof(header->backing_file), 
++                    backing_file))
++              goto out_free;
++
++      err = stat64(header->backing_file, &buf);
++      if(err < 0){
++              printk("Stat of backing file '%s' failed, errno = %d\n",
++                     header->backing_file, errno);
++              err = -errno;
++              goto out_free;
++      }
++
++      err = os_file_size(header->backing_file, size);
++      if(err){
++              printk("Couldn't get size of backing file '%s', errno = %d\n",
++                     header->backing_file, -*size);
++              goto out_free;
++      }
++
++      header->mtime = htonl(buf.st_mtime);
++      header->size = htonll(*size);
++      header->sectorsize = htonl(sectorsize);
++
++      err = write(fd, header, sizeof(*header));
++      if(err != sizeof(*header)){
++              printk("Write of header to new COW file '%s' failed, "
++                     "errno = %d\n", cow_file, errno);
++              goto out_free;
++      }
++      err = 0;
++ out_free:
++      kfree(header);
++ out:
++      return(err);
++}
++
++int open_ubd_file(char *file, struct openflags *openflags, 
++                char **backing_file_out, int *bitmap_offset_out, 
++                unsigned long *bitmap_len_out, int *data_offset_out, 
++                int *create_cow_out)
++{
++      time_t mtime;
++      __u64 size;
++      char *backing_file;
++        int fd, err, sectorsize, magic, same, mode = 0644;
++
++        if((fd = os_open_file(file, *openflags, mode)) < 0){
++              if((fd == -ENOENT) && (create_cow_out != NULL))
++                      *create_cow_out = 1;
++                if(!openflags->w ||
++                   ((errno != EROFS) && (errno != EACCES))) return(-errno);
++              openflags->w = 0;
++                if((fd = os_open_file(file, *openflags, mode)) < 0) 
++                      return(fd);
++        }
++      if(backing_file_out == NULL) return(fd);
++
++      err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, 
++                            &sectorsize, bitmap_offset_out);
++      if(err && (*backing_file_out != NULL)){
++              printk("Failed to read COW header from COW file \"%s\", "
++                     "errno = %d\n", file, err);
++              goto error;
++      }
++      if(err) return(fd);
++
++      if(backing_file_out == NULL) return(fd);
++      
++      same = same_backing_files(*backing_file_out, backing_file, file);
++
++      if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
++              printk("Switching backing file to '%s'\n", *backing_file_out);
++              err = write_cow_header(file, fd, *backing_file_out, 
++                                     sectorsize, &size);
++              if(err){
++                      printk("Switch failed, errno = %d\n", err);
++                      return(err);
++              }
++      }
++      else {
++              *backing_file_out = backing_file;
++              err = backing_file_mismatch(*backing_file_out, size, mtime);
++              if(err) goto error;
++      }
++
++      sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
++            data_offset_out);
++
++        return(fd);
++ error:
++      close(fd);
++      return(err);
++}
++
++int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
++                  int sectorsize, int *bitmap_offset_out, 
++                  unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      __u64 blocks;
++      long zero;
++      int err, fd, i;
++      long long size;
++
++      flags.c = 1;
++      fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
++      if(fd < 0){
++              err = fd;
++              printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
++                     -err);
++              goto out;
++      }
++
++      err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
++      if(err) goto out_close;
++
++      blocks = (size + sectorsize - 1) / sectorsize;
++      blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
++      zero = 0;
++      for(i = 0; i < blocks; i++){
++              err = write(fd, &zero, sizeof(zero));
++              if(err != sizeof(zero)){
++                      printk("Write of bitmap to new COW file '%s' failed, "
++                             "errno = %d\n", cow_file, errno);
++                      goto out_close;
++              }
++      }
++
++      sizes(size, sectorsize, sizeof(struct cow_header_v2), 
++            bitmap_len_out, data_offset_out);
++      *bitmap_offset_out = sizeof(struct cow_header_v2);
++
++      return(fd);
++
++ out_close:
++      close(fd);
++ out:
++      return(err);
++}
++
++int read_ubd_fs(int fd, void *buffer, int len)
++{
++      int n;
++
++      n = read(fd, buffer, len);
++      if(n < 0) return(-errno);
++      else return(n);
++}
++
++int write_ubd_fs(int fd, char *buffer, int len)
++{
++      int n;
++
++      n = write(fd, buffer, len);
++      if(n < 0) return(-errno);
++      else return(n);
++}
++
++int ubd_is_dir(char *file)
++{
++      struct stat64 buf;
++
++      if(stat64(file, &buf) < 0) return(0);
++      return(S_ISDIR(buf.st_mode));
++}
++
++void do_io(struct io_thread_req *req)
++{
++      char *buf;
++      unsigned long len;
++      int n, nsectors, start, end, bit;
++      __u64 off;
++
++      nsectors = req->length / req->sectorsize;
++      start = 0;
++      do {
++              bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
++              end = start;
++              while((end < nsectors) && 
++                    (ubd_test_bit(end, (unsigned char *) 
++                                  &req->sector_mask) == bit))
++                      end++;
++
++              if(end != nsectors)
++                      printk("end != nsectors\n");
++              off = req->offset + req->offsets[bit] + 
++                      start * req->sectorsize;;
++              len = (end - start) * req->sectorsize;
++              buf = &req->buffer[start * req->sectorsize];
++
++              if(os_seek_file(req->fds[bit], off) != 0){
++                      printk("do_io - lseek failed : errno = %d\n", errno);
++                      req->error = 1;
++                      return;
++              }
++              if(req->op == UBD_READ){
++                      n = 0;
++                      do {
++                              buf = &buf[n];
++                              len -= n;
++                              n = read(req->fds[bit], buf, len);
++                              if (n < 0) {
++                                      printk("do_io - read returned %d : "
++                                             "errno = %d fd = %d\n", n,
++                                             errno, req->fds[bit]);
++                                      req->error = 1;
++                                      return;
++                              }
++                      } while((n < len) && (n != 0));
++                      if (n < len) memset(&buf[n], 0, len - n);
++              }
++              else {
++                      n = write(req->fds[bit], buf, len);
++                      if(n != len){
++                              printk("do_io - write returned %d : "
++                                     "errno = %d fd = %d\n", n, 
++                                     errno, req->fds[bit]);
++                              req->error = 1;
++                              return;
++                      }
++              }
++
++              start = end;
++      } while(start < nsectors);
++
++      if(req->cow_offset != -1){
++              if(os_seek_file(req->fds[1], req->cow_offset) != 0){
++                      printk("do_io - bitmap lseek failed : errno = %d\n",
++                             errno);
++                      req->error = 1;
++                      return;
++              }
++              n = write(req->fds[1], &req->bitmap_words, 
++                        sizeof(req->bitmap_words));
++              if(n != sizeof(req->bitmap_words)){
++                      printk("do_io - bitmap update returned %d : "
++                             "errno = %d fd = %d\n", n, errno, req->fds[1]);
++                      req->error = 1;
++                      return;
++              }
++      }
++      req->error = 0;
++      return;
++}
++
++int kernel_fd = -1;
++
++int io_count = 0;
++
++int io_thread(void *arg)
++{
++      struct io_thread_req req;
++      int n;
++
++      signal(SIGWINCH, SIG_IGN);
++      while(1){
++              n = read(kernel_fd, &req, sizeof(req));
++              if(n < 0) printk("io_thread - read returned %d, errno = %d\n",
++                               n, errno);
++              else if(n < sizeof(req)){
++                      printk("io_thread - short read : length = %d\n", n);
++                      continue;
++              }
++              io_count++;
++              do_io(&req);
++              n = write(kernel_fd, &req, sizeof(req));
++              if(n != sizeof(req))
++                      printk("io_thread - write failed, errno = %d\n",
++                             errno);
++      }
++}
++
++int start_io_thread(unsigned long sp, int *fd_out)
++{
++      int pid, fds[2], err;
++
++      err = os_pipe(fds, 1, 1);
++      if(err){
++              printk("start_io_thread - os_pipe failed, errno = %d\n", -err);
++              return(-1);
++      }
++      kernel_fd = fds[0];
++      *fd_out = fds[1];
++
++      pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
++                  NULL);
++      if(pid < 0){
++              printk("start_io_thread - clone failed : errno = %d\n", errno);
++              return(-errno);
++      }
++      return(pid);
++}
++
++#ifdef notdef
++int start_io_thread(unsigned long sp, int *fd_out)
++{
++      int pid;
++
++      if((kernel_fd = get_pty()) < 0) return(-1);
++      raw(kernel_fd, 0);
++      if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){
++              printk("Couldn't open tty for IO\n");
++              return(-1);
++      }
++
++      pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
++                  NULL);
++      if(pid < 0){
++              printk("start_io_thread - clone failed : errno = %d\n", errno);
++              return(-errno);
++      }
++      return(pid);
++}
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/drivers/xterm.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,178 @@
++/* 
++ * Copyright (C) 2001, 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 <fcntl.h>
++#include <termios.h>
++#include <signal.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "chan_user.h"
++#include "helper.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++struct xterm_chan {
++      int pid;
++      int helper_pid;
++      char *title;
++      int device;
++      int raw;
++      struct termios tt;
++      unsigned long stack;
++};
++
++void *xterm_init(char *str, int device, struct chan_opts *opts)
++{
++      struct xterm_chan *data;
++
++      if((data = malloc(sizeof(*data))) == NULL) return(NULL);
++      *data = ((struct xterm_chan) { pid :            -1, 
++                                     helper_pid :     -1,
++                                     device :         device, 
++                                     title :          opts->xterm_title,
++                                     raw :            opts->raw,
++                                     stack :          opts->tramp_stack } );
++      return(data);
++}
++
++static char *terminal_emulator = "xterm";
++static char *title_switch = "-T";
++static char *exec_switch = "-e";
++
++static int __init xterm_setup(char *line, int *add)
++{
++      *add = 0;
++      terminal_emulator = line;
++
++      line = strchr(line, ',');
++      if(line == NULL) return(0);
++      *line++ = '\0';
++      if(*line) title_switch = line;
++
++      line = strchr(line, ',');
++      if(line == NULL) return(0);
++      *line++ = '\0';
++      if(*line) exec_switch = line;
++
++      return(0);
++}
++
++__uml_setup("xterm=", xterm_setup,
++"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
++"    Specifies an alternate terminal emulator to use for the debugger,\n"
++"    consoles, and serial lines when they are attached to the xterm channel.\n"
++"    The values are the terminal emulator binary, the switch it uses to set\n"
++"    its title, and the switch it uses to execute a subprocess,\n"
++"    respectively.  The title switch must have the form '<switch> title',\n"
++"    not '<switch>=title'.  Similarly, the exec switch must have the form\n"
++"    '<switch> command arg1 arg2 ...'.\n"
++"    The default values are 'xterm=xterm,-T,-e'.  Values for gnome-terminal\n"
++"    are 'xterm=gnome-terminal,-t,-x'.\n\n"
++);
++
++int xterm_open(int input, int output, int primary, void *d)
++{
++      struct xterm_chan *data = d;
++      unsigned long stack;
++      int pid, fd, new;
++      char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
++      char *argv[] = { terminal_emulator, title_switch, title, exec_switch, 
++                       "/usr/lib/uml/port-helper", "-uml-socket",
++                       file, NULL };
++
++      fd = mkstemp(file);
++      if(fd < 0){
++              printk("xterm_open : mkstemp failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if(unlink(file)){
++              printk("xterm_open : unlink failed, errno = %d\n", errno);
++              return(-errno);
++      }
++      close(fd);
++
++      fd = create_unix_socket(file, sizeof(file));
++      if(fd < 0){
++              printk("xterm_open : create_unix_socket failed, errno = %d\n", 
++                     errno);
++              return(-errno);
++      }
++
++      sprintf(title, data->title, data->device);
++      stack = data->stack;
++      pid = run_helper(NULL, NULL, argv, &stack);
++      if(pid < 0){
++              printk("xterm_open : run_helper failed\n");
++              return(-1);
++      }
++
++      if(data->stack == 0) free_stack(stack, 0);
++
++      new = os_rcv_fd(fd, &data->helper_pid);
++      if(new < 0){
++              printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new);
++              return(new);
++      }
++
++      tcgetattr(new, &data->tt);
++      if(data->raw) raw(new, 0);
++
++      data->pid = pid;
++      return(new);
++}
++
++void xterm_close(int fd, void *d)
++{
++      struct xterm_chan *data = d;
++      
++      if(data->pid != -1) kill(data->pid, SIGKILL);
++      data->pid = -1;
++      if(data->helper_pid != -1) kill(data->helper_pid, SIGKILL);
++      data->helper_pid = -1;
++      close(fd);
++}
++
++void xterm_free(void *d)
++{
++      free(d);
++}
++
++int xterm_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct xterm_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops xterm_ops = {
++      init:           xterm_init,
++      open:           xterm_open,
++      close:          xterm_close,
++      read:           generic_read,
++      write:          generic_write,
++      console_write:  xterm_console_write,
++      window_size:    generic_window_size,
++      free:           xterm_free,
++      winch:          1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hostfs/hostfs.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,69 @@
++#ifndef __UM_FS_HOSTFS
++#define __UM_FS_HOSTFS
++
++#include "os.h"
++
++/* These are exactly the same definitions as in fs.h, but the names are 
++ * changed so that this file can be included in both kernel and user files.
++ */
++
++#define HOSTFS_ATTR_MODE      1
++#define HOSTFS_ATTR_UID       2
++#define HOSTFS_ATTR_GID       4
++#define HOSTFS_ATTR_SIZE      8
++#define HOSTFS_ATTR_ATIME     16
++#define HOSTFS_ATTR_MTIME     32
++#define HOSTFS_ATTR_CTIME     64
++#define HOSTFS_ATTR_ATIME_SET 128
++#define HOSTFS_ATTR_MTIME_SET 256
++#define HOSTFS_ATTR_FORCE     512     /* Not a change, but a change it */
++#define HOSTFS_ATTR_ATTR_FLAG 1024
++
++struct hostfs_iattr {
++      unsigned int    ia_valid;
++      mode_t          ia_mode;
++      uid_t           ia_uid;
++      gid_t           ia_gid;
++      loff_t          ia_size;
++      time_t          ia_atime;
++      time_t          ia_mtime;
++      time_t          ia_ctime;
++      unsigned int    ia_attr_flags;
++};
++
++extern int stat_file(const char *path, int *dev_out, 
++                   unsigned long long *inode_out, int *mode_out, 
++                   int *nlink_out, int *uid_out, int *gid_out, 
++                   unsigned long long *size_out, unsigned long *atime_out, 
++                   unsigned long *mtime_out, unsigned long *ctime_out, 
++                   int *blksize_out, unsigned long long *blocks_out);
++extern int access_file(char *path, int r, int w, int x);
++extern int open_file(char *path, int r, int w);
++extern int file_type(const char *path, int *rdev);
++extern void *open_dir(char *path, int *err_out);
++extern char *read_dir(void *stream, unsigned long long *pos, 
++                    unsigned long long *ino_out, int *len_out);
++extern void close_file(void *stream);
++extern void close_dir(void *stream);
++extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
++extern int write_file(int fd, unsigned long long *offset, const char *buf,
++                    int len);
++extern int lseek_file(int fd, long long offset, int whence);
++extern int file_create(char *name, int ur, int uw, int ux, int gr, 
++                     int gw, int gx, int or, int ow, int ox);
++extern int set_attr(const char *file, struct hostfs_iattr *attrs);
++extern int make_symlink(const char *from, const char *to);
++extern int unlink_file(const char *file);
++extern int do_mkdir(const char *file, int mode);
++extern int do_rmdir(const char *file);
++extern int do_mknod(const char *file, int mode, int dev);
++extern int link_file(const char *from, const char *to);
++extern int do_readlink(char *file, char *buf, int size);
++extern int rename_file(char *from, char *to);
++extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
++                   long long *bfree_out, long long *bavail_out, 
++                   long long *files_out, long long *ffree_out, 
++                   void *fsid_out, int fsid_size, long *namelen_out, 
++                   long *spare_out);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hostfs/hostfs_kern.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,807 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/stddef.h>
++#include <linux/fs.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/pagemap.h>
++#include <linux/blkdev.h>
++#include <asm/uaccess.h>
++#include "hostfs.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "user_util.h"
++#include "2_5compat.h"
++
++#define file_hostfs_i(file) (&(file)->f_dentry->d_inode->u.hostfs_i)
++
++int hostfs_d_delete(struct dentry *dentry)
++{
++      return(1);
++}
++
++struct dentry_operations hostfs_dentry_ops = {
++      d_delete:               hostfs_d_delete,
++};
++
++static char *root_ino = "/";
++
++#define HOSTFS_SUPER_MAGIC 0x00c0ffee
++
++static struct inode_operations hostfs_iops;
++static struct inode_operations hostfs_dir_iops;
++static struct address_space_operations hostfs_link_aops;
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *root, *name;
++      int len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      root = parent->d_inode->u.hostfs_i.host_filename;
++      len += strlen(root);
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len -= parent->d_name.len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], parent->d_name.name, 
++                      parent->d_name.len);
++              parent = parent->d_parent;
++      }
++      strncpy(name, root, strlen(root));
++      return(name);
++}
++
++static char *inode_name(struct inode *ino, int extra)
++{
++      struct dentry *dentry;
++
++      dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
++      return(dentry_name(dentry, extra));
++}
++
++static int read_name(struct inode *ino, char *name)
++{
++      /* The non-int inode fields are copied into ints by stat_file and
++       * then copied into the inode because passing the actual pointers
++       * in and having them treated as int * breaks on big-endian machines
++       */
++      int err;
++      int i_dev, i_mode, i_nlink, i_blksize;
++      unsigned long long i_size;
++      unsigned long long i_ino;
++      unsigned long long i_blocks;
++      err = stat_file(name, &i_dev, &i_ino, &i_mode, &i_nlink, 
++                      &ino->i_uid, &ino->i_gid, &i_size, &ino->i_atime, 
++                      &ino->i_mtime, &ino->i_ctime, &i_blksize, &i_blocks);
++      if(err) return(err);
++      ino->i_ino = i_ino;
++      ino->i_dev = i_dev;
++      ino->i_mode = i_mode;
++      ino->i_nlink = i_nlink;
++      ino->i_size = i_size;
++      ino->i_blksize = i_blksize;
++      ino->i_blocks = i_blocks;
++      if(kdev_same(ino->i_sb->s_dev, ROOT_DEV) && (ino->i_uid == getuid()))
++              ino->i_uid = 0;
++      return(0);
++}
++
++static int read_inode(struct inode *ino)
++{
++      char *name;
++      int err;
++
++      name = inode_name(ino, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = read_name(ino, name);
++      kfree(name);
++      return(err);
++}
++
++void hostfs_delete_inode(struct inode *ino)
++{
++      if(ino->u.hostfs_i.host_filename) kfree(ino->u.hostfs_i.host_filename);
++      ino->u.hostfs_i.host_filename = NULL;
++      if(ino->u.hostfs_i.fd != -1) close_file(&ino->u.hostfs_i.fd);
++      ino->u.hostfs_i.mode = 0;
++      clear_inode(ino);
++}
++
++int hostfs_statfs(struct super_block *sb, struct statfs *sf)
++{
++      /* do_statfs uses struct statfs64 internally, but the linux kernel
++       * struct statfs still has 32-bit versions for most of these fields,
++       * so we convert them here
++       */
++      int err;
++      long long f_blocks;
++      long long f_bfree;
++      long long f_bavail;
++      long long f_files;
++      long long f_ffree;
++
++      err = do_statfs(sb->s_root->d_inode->u.hostfs_i.host_filename,
++                      &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
++                      &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), 
++                      &sf->f_namelen, sf->f_spare);
++      if(err) return(err);
++      sf->f_blocks = f_blocks;
++      sf->f_bfree = f_bfree;
++      sf->f_bavail = f_bavail;
++      sf->f_files = f_files;
++      sf->f_ffree = f_ffree;
++      sf->f_type = HOSTFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct super_operations hostfs_sbops = { 
++      put_inode:      force_delete,
++      delete_inode:   hostfs_delete_inode,
++      statfs:         hostfs_statfs,
++};
++
++int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      void *dir;
++      char *name;
++      unsigned long long next, ino;
++      int error, len;
++
++      name = dentry_name(file->f_dentry, 0);
++      if(name == NULL) return(-ENOMEM);
++      dir = open_dir(name, &error);
++      kfree(name);
++      if(dir == NULL) return(-error);
++      next = file->f_pos;
++      while((name = read_dir(dir, &next, &ino, &len)) != NULL){
++              error = (*filldir)(ent, name, len, file->f_pos, 
++                                 ino, DT_UNKNOWN);
++              if(error) break;
++              file->f_pos = next;
++      }
++      close_dir(dir);
++      return(0);
++}
++
++int hostfs_file_open(struct inode *ino, struct file *file)
++{
++      char *name;
++      int mode = 0, r = 0, w = 0, fd;
++
++      mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
++      if((mode & ino->u.hostfs_i.mode) == mode) return(0);
++
++      if(ino->u.hostfs_i.fd != -1){
++              close_file(&ino->u.hostfs_i.fd);
++              ino->u.hostfs_i.fd = -1;
++      }
++      ino->u.hostfs_i.mode |= mode;
++      if(ino->u.hostfs_i.mode & FMODE_READ) r = 1;
++      if(ino->u.hostfs_i.mode & FMODE_WRITE) w = 1;
++      if(w) r = 1;
++      name = dentry_name(file->f_dentry, 0);
++      if(name == NULL) return(-ENOMEM);
++      fd = open_file(name, r, w);
++      kfree(name);
++      if(fd < 0) return(fd);
++      file_hostfs_i(file)->fd = fd;
++      return(0);
++}
++
++int hostfs_dir_open(struct inode *ino, struct file *file)
++{
++      return(0);      
++}
++
++int hostfs_dir_release(struct inode *ino, struct file *file)
++{
++      return(0);
++}
++
++int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      return(0);
++}
++
++static struct file_operations hostfs_file_fops = {
++      owner:          NULL,
++      read:           generic_file_read,
++      write:          generic_file_write,
++      mmap:           generic_file_mmap,
++      open:           hostfs_file_open,
++      release:        NULL,
++      fsync:          hostfs_fsync,
++};
++
++static struct file_operations hostfs_dir_fops = {
++      owner:          NULL,
++      readdir:        hostfs_readdir,
++      open:           hostfs_dir_open,
++      release:        hostfs_dir_release,
++      fsync:          hostfs_fsync,
++};
++
++int hostfs_writepage(struct page *page)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      char *buffer;
++      unsigned long long base;
++      int count = PAGE_CACHE_SIZE;
++      int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
++      int err;
++
++      if (page->index >= end_index)
++              count = inode->i_size & (PAGE_CACHE_SIZE-1);
++
++      buffer = kmap(page);
++      base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
++
++      err = write_file(inode->u.hostfs_i.fd, &base, buffer, count);
++      if(err != count){
++              ClearPageUptodate(page);
++              goto out;
++      }
++
++      if (base > inode->i_size)
++              inode->i_size = base;
++
++      if (PageError(page))
++              ClearPageError(page);   
++      err = 0;
++
++ out: 
++      kunmap(page);
++
++      UnlockPage(page);
++      return err; 
++}
++
++int hostfs_readpage(struct file *file, struct page *page)
++{
++      char *buffer;
++      long long start;
++      int err = 0;
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      err = read_file(file_hostfs_i(file)->fd, &start, buffer,
++                      PAGE_CACHE_SIZE);
++      if(err < 0) goto out;
++
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      if (PageError(page)) ClearPageError(page);
++      err = 0;
++ out:
++      kunmap(page);
++      UnlockPage(page);
++      return(err);
++}
++
++int hostfs_prepare_write(struct file *file, struct page *page, 
++                       unsigned int from, unsigned int to)
++{
++      char *buffer;
++      long long start, tmp;
++      int err;
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      if(from != 0){
++              tmp = start;
++              err = read_file(file_hostfs_i(file)->fd, &tmp, buffer,
++                              from);
++              if(err < 0) goto out;
++      }
++      if(to != PAGE_CACHE_SIZE){
++              start += to;
++              err = read_file(file_hostfs_i(file)->fd, &start, buffer + to,
++                              PAGE_CACHE_SIZE - to);
++              if(err < 0) goto out;           
++      }
++      err = 0;
++ out:
++      kunmap(page);
++      return(err);
++}
++
++int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
++               unsigned to)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      char *buffer;
++      long long start;
++      int err = 0;
++
++      start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
++      buffer = kmap(page);
++      err = write_file(file_hostfs_i(file)->fd, &start, buffer + from, 
++                       to - from);
++      if(err > 0) err = 0;
++      if(!err && (start > inode->i_size))
++              inode->i_size = start;
++
++      kunmap(page);
++      return(err);
++}
++
++static struct address_space_operations hostfs_aops = {
++      writepage:      hostfs_writepage,
++      readpage:       hostfs_readpage,
++      prepare_write:  hostfs_prepare_write,
++      commit_write:   hostfs_commit_write
++};
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int *error)
++{
++      struct inode *inode;
++      char *name;
++      int type, err = -ENOMEM, rdev;
++
++      inode = new_inode(sb);
++      if(inode == NULL) 
++              goto out;
++
++      inode->u.hostfs_i.host_filename = NULL;
++      inode->u.hostfs_i.fd = -1;
++      inode->u.hostfs_i.mode = 0;
++      insert_inode_hash(inode);
++      if(dentry){
++              name = dentry_name(dentry, 0);
++              if(name == NULL){
++                      err = -ENOMEM;
++                      goto out_put;
++              }
++              type = file_type(name, &rdev);
++              kfree(name);
++      }
++      else type = OS_TYPE_DIR;
++      inode->i_sb = sb;
++
++      err = 0;
++      if(type == OS_TYPE_SYMLINK)
++              inode->i_op = &page_symlink_inode_operations;
++      else if(type == OS_TYPE_DIR)
++              inode->i_op = &hostfs_dir_iops;
++      else inode->i_op = &hostfs_iops;
++
++      if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
++      else inode->i_fop = &hostfs_file_fops;
++
++      if(type == OS_TYPE_SYMLINK) inode->i_mapping->a_ops = &hostfs_link_aops;
++      else inode->i_mapping->a_ops = &hostfs_aops;
++
++      switch (type) {
++      case OS_TYPE_CHARDEV:
++              init_special_inode(inode, S_IFCHR, rdev);
++              break;
++      case OS_TYPE_BLOCKDEV:
++              init_special_inode(inode, S_IFBLK, rdev);
++              break;
++      case OS_TYPE_FIFO:
++              init_special_inode(inode, S_IFIFO, 0);
++              break;
++      case OS_TYPE_SOCK:
++              init_special_inode(inode, S_IFSOCK, 0);
++              break;
++      }
++      
++      if(error) *error = err;
++      return(inode);
++ out_put:
++      iput(inode);
++ out:
++      if(error) *error = err;
++      return(NULL);
++}
++
++int hostfs_create(struct inode *dir, struct dentry *dentry, int mode)
++{
++      struct inode *inode;
++      char *name;
++      int error;
++
++      inode = get_inode(dir->i_sb, dentry, &error);
++      if(error) return(error);
++      name = dentry_name(dentry, 0);
++      if(name == NULL){
++              iput(inode);
++              return(-ENOMEM);
++      }
++      error = file_create(name, 
++                          mode | S_IRUSR, mode | S_IWUSR, mode | S_IXUSR, 
++                          mode | S_IRGRP, mode | S_IWGRP, mode | S_IXGRP, 
++                          mode | S_IROTH, mode | S_IWOTH, mode | S_IXOTH);
++      if(!error) error = read_name(inode, name);
++      kfree(name);
++      if(error){
++              iput(inode);
++              return(error);
++      }
++      d_instantiate(dentry, inode);
++      return(0);
++}
++ 
++struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry)
++{
++      struct inode *inode;
++      char *name;
++      int error;
++
++      inode = get_inode(ino->i_sb, dentry, &error);
++      if(error != 0) return(ERR_PTR(error));
++      name = dentry_name(dentry, 0);
++      if(name == NULL) return(ERR_PTR(-ENOMEM));
++      error = read_name(inode, name);
++      kfree(name);
++      if(error){
++              iput(inode);
++              if(error == -ENOENT) inode = NULL;
++              else return(ERR_PTR(error));
++      }
++      d_add(dentry, inode);
++      dentry->d_op = &hostfs_dentry_ops;
++      return(NULL);
++}
++
++static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
++{
++        char *file;
++      int len;
++
++      file = inode_name(ino, dentry->d_name.len + 1);
++      if(file == NULL) return(NULL);
++        strcat(file, "/");
++      len = strlen(file);
++        strncat(file, dentry->d_name.name, dentry->d_name.len);
++      file[len + dentry->d_name.len] = '\0';
++        return(file);
++}
++
++int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
++{
++        char *from_name, *to_name;
++        int err;
++
++        if((from_name = inode_dentry_name(ino, from)) == NULL) 
++                return(-ENOMEM);
++        to_name = dentry_name(to, 0);
++      if(to_name == NULL){
++              kfree(from_name);
++              return(-ENOMEM);
++      }
++        err = link_file(to_name, from_name);
++        kfree(from_name);
++        kfree(to_name);
++        return(err);
++}
++
++int hostfs_unlink(struct inode *ino, struct dentry *dentry)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = unlink_file(file);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = make_symlink(file, to);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = do_mkdir(file, mode);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = do_rmdir(file);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
++{
++      struct inode *inode;
++      char *name;
++      int error;
++ 
++      inode = get_inode(dir->i_sb, dentry, &error);
++      if(error) return(error);
++      name = dentry_name(dentry, 0);
++      if(name == NULL){
++              iput(inode);
++              return(-ENOMEM);
++      }
++      init_special_inode(inode, mode, dev);
++      error = do_mknod(name, mode, dev);
++      if(!error) error = read_name(inode, name);
++      kfree(name);
++      if(error){
++              iput(inode);
++              return(error);
++      }
++      d_instantiate(dentry, inode);
++      return(0);
++}
++
++int hostfs_rename(struct inode *from_ino, struct dentry *from,
++                struct inode *to_ino, struct dentry *to)
++{
++      char *from_name, *to_name;
++      int err;
++
++      if((from_name = inode_dentry_name(from_ino, from)) == NULL)
++              return(-ENOMEM);
++      if((to_name = inode_dentry_name(to_ino, to)) == NULL){
++              kfree(from_name);
++              return(-ENOMEM);
++      }
++      err = rename_file(from_name, to_name);
++      kfree(from_name);
++      kfree(to_name);
++      return(err);
++}
++
++void hostfs_truncate(struct inode *ino)
++{
++      not_implemented();
++}
++
++int hostfs_permission(struct inode *ino, int desired)
++{
++      char *name;
++      int r = 0, w = 0, x = 0, err;
++
++      if(desired & MAY_READ) r = 1;
++      if(desired & MAY_WRITE) w = 1;
++      if(desired & MAY_EXEC) x = 1;
++      name = inode_name(ino, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = access_file(name, r, w, x);
++      kfree(name);
++      if(!err) err = vfs_permission(ino, desired);
++      return(err);
++}
++
++int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++      struct hostfs_iattr attrs;
++      char *name;
++      int err;
++
++      attrs.ia_valid = 0;
++      if(attr->ia_valid & ATTR_MODE){
++              attrs.ia_valid |= HOSTFS_ATTR_MODE;
++              attrs.ia_mode = attr->ia_mode;
++      }
++      if(attr->ia_valid & ATTR_UID){
++              if(kdev_same(dentry->d_inode->i_sb->s_dev, ROOT_DEV) && 
++                 (attr->ia_uid == 0))
++                      attr->ia_uid = getuid();
++              attrs.ia_valid |= HOSTFS_ATTR_UID;
++              attrs.ia_uid = attr->ia_uid;
++      }
++      if(attr->ia_valid & ATTR_GID){
++              if(kdev_same(dentry->d_inode->i_sb->s_dev, ROOT_DEV) && 
++                 (attr->ia_gid == 0))
++                      attr->ia_gid = getuid();
++              attrs.ia_valid |= HOSTFS_ATTR_GID;
++              attrs.ia_gid = attr->ia_gid;
++      }
++      if(attr->ia_valid & ATTR_SIZE){
++              attrs.ia_valid |= HOSTFS_ATTR_SIZE;
++              attrs.ia_size = attr->ia_size;
++      }
++      if(attr->ia_valid & ATTR_ATIME){
++              attrs.ia_valid |= HOSTFS_ATTR_ATIME;
++              attrs.ia_atime = attr->ia_atime;
++      }
++      if(attr->ia_valid & ATTR_MTIME){
++              attrs.ia_valid |= HOSTFS_ATTR_MTIME;
++              attrs.ia_mtime = attr->ia_mtime;
++      }
++      if(attr->ia_valid & ATTR_CTIME){
++              attrs.ia_valid |= HOSTFS_ATTR_CTIME;
++              attrs.ia_ctime = attr->ia_ctime;
++      }
++      if(attr->ia_valid & ATTR_ATIME_SET){
++              attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
++      }
++      if(attr->ia_valid & ATTR_MTIME_SET){
++              attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
++      }
++      name = dentry_name(dentry, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = set_attr(name, &attrs);
++      kfree(name);
++      return(err);
++}
++
++int hostfs_getattr(struct dentry *dentry, struct iattr *attr)
++{
++      not_implemented();
++      return(-EINVAL);
++}
++
++static struct inode_operations hostfs_iops = {
++      create:         hostfs_create,
++      link:           hostfs_link,
++      unlink:         hostfs_unlink,
++      symlink:        hostfs_symlink,
++      mkdir:          hostfs_mkdir,
++      rmdir:          hostfs_rmdir,
++      mknod:          hostfs_mknod,
++      rename:         hostfs_rename,
++      truncate:       hostfs_truncate,
++      permission:     hostfs_permission,
++      setattr:        hostfs_setattr,
++      getattr:        hostfs_getattr,
++};
++
++static struct inode_operations hostfs_dir_iops = {
++      create:         hostfs_create,
++      lookup:         hostfs_lookup,
++      link:           hostfs_link,
++      unlink:         hostfs_unlink,
++      symlink:        hostfs_symlink,
++      mkdir:          hostfs_mkdir,
++      rmdir:          hostfs_rmdir,
++      mknod:          hostfs_mknod,
++      rename:         hostfs_rename,
++      truncate:       hostfs_truncate,
++      permission:     hostfs_permission,
++      setattr:        hostfs_setattr,
++      getattr:        hostfs_getattr,
++};
++
++int hostfs_link_readpage(struct file *file, struct page *page)
++{
++      char *buffer, *name;
++      long long start;
++      int err;
++
++      start = page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      name = inode_name(page->mapping->host, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
++      kfree(name);
++      if(err == 0){
++              flush_dcache_page(page);
++              SetPageUptodate(page);
++              if (PageError(page)) ClearPageError(page);
++      }
++      kunmap(page);
++      UnlockPage(page);
++      return(err);
++}
++
++static struct address_space_operations hostfs_link_aops = {
++      readpage:       hostfs_link_readpage,
++};
++
++static struct super_block *hostfs_read_super_common(struct super_block *sb, 
++                                                  char *data)
++{
++      struct inode *root_inode;
++      char *name;
++
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = HOSTFS_SUPER_MAGIC;
++      sb->s_op = &hostfs_sbops;
++      if((data == NULL) || (*((char *) data) == '\0')) data = root_ino;
++      name = kmalloc(strlen(data) + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++      strcpy(name, data);
++      root_inode = get_inode(sb, NULL, NULL);
++      if(root_inode == NULL)
++              goto out_free;
++
++      root_inode->u.hostfs_i.host_filename = name;
++      sb->s_root = d_alloc_root(root_inode);
++      if(read_inode(root_inode))
++              goto out_put;
++      return(sb);
++
++ out_free:
++      kfree(name);
++ out_put:
++      iput(root_inode);
++      return(NULL);
++}
++
++struct super_block *hostfs_read_super(struct super_block *sb, void *data, 
++                                    int silent)
++{
++      return(hostfs_read_super_common(sb, data));
++}
++
++struct super_block *hostfs_root_read_super(struct super_block *sb, void *data, 
++                                         int silent)
++{
++      struct buffer_head * bh;
++      struct super_block *ret = NULL;
++      kdev_t dev = sb->s_dev;
++      int blocksize = get_hardsect_size(dev);
++
++      if(blocksize == 0) blocksize = BLOCK_SIZE;
++      set_blocksize (dev, blocksize);
++      if(!(bh = bread (dev, 0, blocksize))) return NULL;
++      if(strncmp(bh->b_data, "HOSTFS:", strlen("HOSTFS:"))) goto out;
++      ret = hostfs_read_super_common(sb, bh->b_data + strlen("HOSTFS:"));
++ out:
++      brelse (bh);
++      return(ret);
++}
++
++DECLARE_FSTYPE(hostfs_type, "hostfs", hostfs_read_super, 0);
++DECLARE_FSTYPE_DEV(hostfs_root_type, "root-hostfs", hostfs_root_read_super);
++
++static int __init init_hostfs(void)
++{
++      return(register_filesystem(&hostfs_type) ||
++             register_filesystem(&hostfs_root_type));
++}
++
++static void __exit exit_hostfs(void)
++{
++      unregister_filesystem(&hostfs_type);
++      unregister_filesystem(&hostfs_root_type);
++}
++
++module_init(init_hostfs)
++module_exit(exit_hostfs)
++MODULE_LICENSE("GPL");
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hostfs/hostfs_user.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,336 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <errno.h>
++#include <utime.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/vfs.h>
++#include "hostfs.h"
++#include "kern_util.h"
++#include "user.h"
++
++int stat_file(const char *path, int *dev_out, unsigned long long *inode_out,
++            int *mode_out, int *nlink_out, int *uid_out, int *gid_out, 
++            unsigned long long *size_out, unsigned long *atime_out,
++            unsigned long *mtime_out, unsigned long *ctime_out,
++            int *blksize_out, unsigned long long *blocks_out)
++{
++      struct stat64 buf;
++
++      if(lstat64(path, &buf) < 0) 
++              return(-errno);
++      if(dev_out != NULL) *dev_out = buf.st_dev;
++
++      /* See the Makefile for why STAT64_INO_FIELD is passed in
++       * by the build
++       */
++      if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
++      if(mode_out != NULL) *mode_out = buf.st_mode;
++      if(nlink_out != NULL) *nlink_out = buf.st_nlink;
++      if(uid_out != NULL) *uid_out = buf.st_uid;
++      if(gid_out != NULL) *gid_out = buf.st_gid;
++      if(size_out != NULL) *size_out = buf.st_size;
++      if(atime_out != NULL) *atime_out = buf.st_atime;
++      if(mtime_out != NULL) *mtime_out = buf.st_mtime;
++      if(ctime_out != NULL) *ctime_out = buf.st_ctime;
++      if(blksize_out != NULL) *blksize_out = buf.st_blksize;
++      if(blocks_out != NULL) *blocks_out = buf.st_blocks;
++      return(0);
++}
++
++int file_type(const char *path, int *rdev)
++{
++      struct stat64 buf;
++
++      if(lstat64(path, &buf) < 0) return(-errno);
++      *rdev = buf.st_rdev;
++      if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
++      else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
++      else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
++      else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
++      else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
++      else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
++      else return(OS_TYPE_FILE);
++}
++
++int access_file(char *path, int r, int w, int x)
++{
++      int mode = 0;
++
++      if(r) mode = R_OK;
++      if(w) mode |= W_OK;
++      if(x) mode |= X_OK;
++      if(access(path, mode) != 0) return(-errno);
++      else return(0);
++}
++
++int open_file(char *path, int r, int w)
++{
++      int mode = 0, fd;
++
++      if(r && !w) mode = O_RDONLY;
++      else if(!r && w) mode = O_WRONLY;
++      else if(r && w) mode = O_RDWR;
++      else panic("Impossible mode in open_file");
++      fd = open64(path, mode);
++      if(fd < 0) return(-errno);
++      else return(fd);
++}
++
++void *open_dir(char *path, int *err_out)
++{
++      DIR *dir;
++
++      dir = opendir(path);
++      *err_out = errno;
++      if(dir == NULL) return(NULL);
++      return(dir);
++}
++
++char *read_dir(void *stream, unsigned long long *pos, 
++             unsigned long long *ino_out, int *len_out)
++{
++      DIR *dir = stream;
++      struct dirent *ent;
++
++      seekdir(dir, *pos);
++      ent = readdir(dir);
++      if(ent == NULL) return(NULL);
++      *len_out = strlen(ent->d_name);
++      *ino_out = ent->d_ino;
++      *pos = telldir(dir);
++      return(ent->d_name);
++}
++
++int read_file(int fd, unsigned long long *offset, char *buf, int len)
++{
++      int n;
++
++      n = pread64(fd, buf, len, *offset);
++      if(n < 0) return(-errno);
++      *offset += n;
++      return(n);
++}
++
++int write_file(int fd, unsigned long long *offset, const char *buf, int len)
++{
++      int n;
++
++      n = pwrite64(fd, buf, len, *offset);
++      if(n < 0) return(-errno);
++      *offset += n;
++      return(n);
++}
++
++int lseek_file(int fd, long long offset, int whence)
++{
++      int ret;
++
++      ret = lseek64(fd, offset, whence);
++      if(ret < 0) return(-errno);
++      return(0);
++}
++
++void close_file(void *stream)
++{
++      close(*((int *) stream));
++}
++
++void close_dir(void *stream)
++{
++      closedir(stream);
++}
++
++int file_create(char *name, int ur, int uw, int ux, int gr, 
++              int gw, int gx, int or, int ow, int ox)
++{
++      int mode, fd;
++
++      mode = 0;
++      mode |= ur ? S_IRUSR : 0;
++      mode |= uw ? S_IWUSR : 0;
++      mode |= ux ? S_IXUSR : 0;
++      mode |= gr ? S_IRGRP : 0;
++      mode |= gw ? S_IWGRP : 0;
++      mode |= gx ? S_IXGRP : 0;
++      mode |= or ? S_IROTH : 0;
++      mode |= ow ? S_IWOTH : 0;
++      mode |= ox ? S_IXOTH : 0;
++      fd = open64(name, O_CREAT, mode);
++      if(fd < 0) return(-errno);
++      close(fd);
++      return(0);
++}
++
++int set_attr(const char *file, struct hostfs_iattr *attrs)
++{
++      struct utimbuf buf;
++      int err, ma;
++
++      if(attrs->ia_valid & HOSTFS_ATTR_MODE){
++              if(chmod(file, attrs->ia_mode) != 0) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_UID){
++              if(chown(file, attrs->ia_uid, -1)) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_GID){
++              if(chown(file, -1, attrs->ia_gid)) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
++              if(truncate(file, attrs->ia_size)) return(-errno);
++      }
++      ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
++      if((attrs->ia_valid & ma) == ma){
++              buf.actime = attrs->ia_atime;
++              buf.modtime = attrs->ia_mtime;
++              if(utime(file, &buf) != 0) return(-errno);
++      }
++      else {
++              if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
++                      err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                      NULL, NULL, NULL, &buf.modtime, NULL,
++                                      NULL, NULL);
++                      if(err != 0) return(err);
++                      buf.actime = attrs->ia_atime;
++                      if(utime(file, &buf) != 0) return(-errno);
++              }
++              if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
++                      err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                      NULL, NULL, &buf.actime, NULL, NULL, 
++                                      NULL, NULL);
++                      if(err != 0) return(err);
++                      buf.modtime = attrs->ia_mtime;
++                      if(utime(file, &buf) != 0) return(-errno);
++              }
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
++      if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
++              err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                              NULL, NULL, &attrs->ia_atime, &attrs->ia_mtime,
++                              NULL, NULL, NULL);
++              if(err != 0) return(err);
++      }
++      return(0);
++}
++
++int make_symlink(const char *from, const char *to)
++{
++      int err;
++
++      err = symlink(to, from);
++      if(err) return(-errno);
++      return(0);
++}
++
++int unlink_file(const char *file)
++{
++      int err;
++
++      err = unlink(file);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_mkdir(const char *file, int mode)
++{
++      int err;
++
++      err = mkdir(file, mode);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_rmdir(const char *file)
++{
++      int err;
++
++      err = rmdir(file);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_mknod(const char *file, int mode, int dev)
++{
++      int err;
++
++      err = mknod(file, mode, dev);
++      if(err) return(-errno);
++      return(0);
++}
++
++int link_file(const char *to, const char *from)
++{
++      int err;
++
++      err = link(to, from);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_readlink(char *file, char *buf, int size)
++{
++      int err;
++
++      err = readlink(file, buf, size);
++      if(err < 0) return(-errno);
++      if(err < size) buf[err] = '\0';
++      return(0);      
++}
++
++int rename_file(char *from, char *to)
++{
++      int err;
++
++      err = rename(from, to);
++      if(err < 0) return(-errno);
++      return(0);      
++}
++
++int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
++            long long *bfree_out, long long *bavail_out, 
++            long long *files_out, long long *ffree_out,
++            void *fsid_out, int fsid_size, long *namelen_out, 
++            long *spare_out)
++{
++      struct statfs64 buf;
++      int err;
++
++      err = statfs64(root, &buf);
++      if(err < 0) return(-errno);
++      *bsize_out = buf.f_bsize;
++      *blocks_out = buf.f_blocks;
++      *bfree_out = buf.f_bfree;
++      *bavail_out = buf.f_bavail;
++      *files_out = buf.f_files;
++      *ffree_out = buf.f_ffree;
++      memcpy(fsid_out, &buf.f_fsid, 
++             sizeof(buf.f_fsid) > fsid_size ? fsid_size : 
++             sizeof(buf.f_fsid));
++      *namelen_out = buf.f_namelen;
++      spare_out[0] = buf.f_spare[0];
++      spare_out[1] = buf.f_spare[1];
++      spare_out[2] = buf.f_spare[2];
++      spare_out[3] = buf.f_spare[3];
++      spare_out[4] = buf.f_spare[4];
++      spare_out[5] = buf.f_spare[5];
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hostfs/Makefile   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,24 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
++# to __st_ino.  It stayed in the same place, so as long as the correct name
++# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
++
++STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
++                              echo __)st_ino
++
++USER_CFLAGS := $(USER_CFLAGS) -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
++
++O_TARGET := hostfs.o
++obj-y = hostfs_kern.o hostfs_user.o
++obj-m = $(O_TARGET)
++
++CFLAGS_hostfs_kern.o := $(CFLAGS)
++CFLAGS_hostfs_user.o := $(USER_CFLAGS) -I/usr/include
++
++override CFLAGS =  
++
++include $(TOPDIR)/Rules.make
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hppfs/hppfs_kern.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,672 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/kernel.h>
++#include <asm/uaccess.h>
++#include "os.h"
++
++struct hppfs_data {
++      struct list_head list;
++      char contents[PAGE_SIZE - sizeof(struct list_head)];
++};
++
++struct hppfs_private {
++      struct file proc_file;
++      int host_fd;
++      loff_t len;
++      struct hppfs_data *contents;
++};
++
++#define HPPFS_SUPER_MAGIC 0xb00000ee
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int *error);
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *root, *name;
++      int len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      root = "proc";
++      len += strlen(root);
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len -= parent->d_name.len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], parent->d_name.name, 
++                      parent->d_name.len);
++              parent = parent->d_parent;
++      }
++      strncpy(name, root, strlen(root));
++      return(name);
++}
++
++struct dentry_operations hppfs_dentry_ops = {
++};
++
++static int file_removed(struct dentry *dentry, const char *file)
++{
++      char *host_file;
++      int extra, fd;
++
++      extra = 0;
++      if(file != NULL) extra += strlen(file) + 1;
++
++      host_file = dentry_name(dentry, extra + strlen("/remove"));
++      if(host_file == NULL){
++              printk("hppfs_lookup : allocation failed\n");
++              return(-ENOMEM);
++      }
++
++      if(file != NULL){
++              strcat(host_file, "/");
++              strcat(host_file, file);
++      }
++      strcat(host_file, "/remove");
++
++      fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++      kfree(host_file);
++      if(fd > 0){
++              os_close_file(fd);
++              return(1);
++      }
++      return(0);
++}
++
++static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry)
++{
++      struct dentry *proc_dentry;
++      struct inode *inode;
++      int err, deleted;
++
++      deleted = file_removed(dentry, NULL);
++      if(deleted < 0)
++              return(ERR_PTR(deleted));
++      else if(deleted)
++              return(ERR_PTR(-ENOENT));
++
++      proc_dentry = lookup_hash(&dentry->d_name, ino->u.hppfs_i.proc_dentry);
++      if(IS_ERR(proc_dentry))
++              return(proc_dentry);
++
++      inode = get_inode(ino->i_sb, proc_dentry, &err);
++      if(err != 0) 
++              return(ERR_PTR(err));
++
++      d_add(dentry, inode);
++      dentry->d_op = &hppfs_dentry_ops;
++      return(NULL);
++}
++
++static struct inode_operations hppfs_file_iops = {
++};
++
++static struct inode_operations hppfs_dir_iops = {
++      lookup:         hppfs_lookup,
++};
++
++static ssize_t read_proc(struct file *file, char *buf, ssize_t count, 
++                       loff_t *ppos)
++{
++      ssize_t (*read)(struct file *, char *, size_t, loff_t *);
++      ssize_t n;
++
++      read = file->f_dentry->d_inode->i_fop->read;
++              
++      /* procfs expects to be copying into userspace buffers.  So, we
++       * set KERNEL_DS in order to fake it out.
++       */
++      set_fs(KERNEL_DS);
++      n = (*read)(file, buf, count, &file->f_pos);
++      set_fs(USER_DS);
++
++      if(ppos) *ppos = file->f_pos;
++      return(n);
++}
++
++static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
++{
++      ssize_t n;
++      int cur, err;
++      char *new_buf;
++
++      n = -ENOMEM;
++      new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++      if(new_buf == NULL){
++              printk("hppfs_read_file : kmalloc failed\n");
++              goto out;
++      }
++      n = 0;
++      while(count > 0){
++              cur = min_t(ssize_t, count, PAGE_SIZE);
++              err = os_read_file(fd, new_buf, cur);
++              if(err < 0){
++                      printk("hppfs_read : read failed, errno = %d\n",
++                             count);
++                      n = err;
++                      goto out_free;
++              }
++              else if(err == 0)
++                      break;
++
++              if(copy_to_user(buf, new_buf, err)){
++                      n = -EFAULT;
++                      goto out_free;
++              }
++              n += err;
++              count -= err;
++      }
++ out_free:
++      kfree(new_buf);
++ out:
++      return(n);
++}
++
++static ssize_t hppfs_read(struct file *file, char *buf, size_t count, 
++                        loff_t *ppos)
++{
++      struct hppfs_private *hppfs = file->private_data;
++      struct hppfs_data *data;
++      loff_t off;
++      int err;
++
++      if(hppfs->contents != NULL){
++              if(*ppos >= hppfs->len) return(0);
++
++              data = hppfs->contents;
++              off = *ppos;
++              while(off >= sizeof(data->contents)){
++                      data = list_entry(&data->list.next, struct hppfs_data,
++                                        list);
++                      off -= sizeof(data->contents);
++              }
++
++              if(off + count > hppfs->len)
++                      count = hppfs->len - off;
++              memcpy(buf, &data->contents[off], count);
++              *ppos += count;
++      }
++      else if(hppfs->host_fd != -1){
++              err = os_seek_file(hppfs->host_fd, *ppos);
++              if(err){
++                      printk("hppfs_read : seek failed, errno = %d\n", err);
++                      return(err);
++              }
++              count = hppfs_read_file(hppfs->host_fd, buf, count);
++              if(count > 0)
++                      *ppos += count;
++      }
++      else count = read_proc(&hppfs->proc_file, buf, count, ppos);
++
++      return(count);
++}
++
++static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, 
++                         loff_t *ppos)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
++      int err;
++
++      write = proc_file->f_dentry->d_inode->i_fop->write;
++
++      proc_file->f_pos = file->f_pos;
++      err = (*write)(proc_file, buf, len, &proc_file->f_pos);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int open_host_sock(char *host_file, int *filter_out)
++{
++      char *end;
++      int fd;
++
++      end = &host_file[strlen(host_file)];
++      strcpy(end, "/rw");
++      *filter_out = 1;
++      fd = os_connect_socket(host_file);
++      if(fd > 0)
++              return(fd);
++
++      strcpy(end, "/r");
++      *filter_out = 0;
++      fd = os_connect_socket(host_file);
++      return(fd);
++}
++
++static void free_contents(struct hppfs_data *head)
++{
++      struct hppfs_data *data;
++      struct list_head *ele, *next;
++
++      if(head == NULL) return;
++
++      list_for_each_safe(ele, next, &head->list){
++              data = list_entry(ele, struct hppfs_data, list);
++              kfree(data);
++      }
++      kfree(head);
++}
++
++static struct hppfs_data *hppfs_get_data(int fd, int filter, 
++                                       struct file *proc_file, 
++                                       struct file *hppfs_file, 
++                                       loff_t *size_out)
++{
++      struct hppfs_data *data, *new, *head;
++      int n, err;
++
++      err = -ENOMEM;
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL){
++              printk("hppfs_get_data : head allocation failed\n");
++              goto failed;
++      }
++
++      INIT_LIST_HEAD(&data->list);
++
++      head = data;
++      *size_out = 0;
++
++      if(filter){
++              while((n = read_proc(proc_file, data->contents,
++                                   sizeof(data->contents), NULL)) > 0)
++                      os_write_file(fd, data->contents, n);
++              err = os_shutdown_socket(fd, 0, 1);
++              if(err){
++                      printk("hppfs_get_data : failed to shut down "
++                             "socket\n");
++                      goto failed_free;
++              }
++      }
++      while(1){
++              n = os_read_file(fd, data->contents, sizeof(data->contents));
++              if(n < 0){
++                      err = n;
++                      printk("hppfs_get_data : read failed, errno = %d\n",
++                             err);
++                      goto failed_free;
++              }
++              else if(n == 0)
++                      break;
++
++              *size_out += n;
++
++              if(n < sizeof(data->contents))
++                      break;
++
++              new = kmalloc(sizeof(*data), GFP_KERNEL);
++              if(new == 0){
++                      printk("hppfs_get_data : data allocation failed\n");
++                      err = -ENOMEM;
++                      goto failed_free;
++              }
++      
++              INIT_LIST_HEAD(&new->list);
++              list_add(&new->list, &data->list);
++              data = new;
++      }
++      return(head);
++
++ failed_free:
++      free_contents(head);
++ failed:              
++      return(ERR_PTR(err));
++}
++
++static struct hppfs_private *hppfs_data(void)
++{
++      struct hppfs_private *data;
++
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL)
++              return(data);
++
++      *data = ((struct hppfs_private ) { host_fd :            -1,
++                                         len :                -1,
++                                         contents :           NULL } );
++      return(data);
++}
++
++static int hppfs_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      char *host_file;
++      int err, fd, type, filter;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      host_file = dentry_name(file->f_dentry, strlen("/rw"));
++      if(host_file == NULL)
++              goto out_free2;
++
++      proc_dentry = inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&data->proc_file, proc_dentry, file->f_mode);
++      if(err)
++              goto out_free1;
++
++      type = os_file_type(host_file);
++      if(type == OS_TYPE_FILE){
++              fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++              if(fd >= 0) 
++                      data->host_fd = fd;
++              else printk("hppfs_open : failed to open '%s', errno = %d\n",
++                          host_file, -fd);
++
++              data->contents = NULL;
++      }
++      else if(type == OS_TYPE_DIR){
++              fd = open_host_sock(host_file, &filter);
++              if(fd > 0){
++                      data->contents = hppfs_get_data(fd, filter, 
++                                                      &data->proc_file, 
++                                                      file, &data->len);
++                      if(!IS_ERR(data->contents))
++                              data->host_fd = fd;
++              }
++              else printk("hppfs_open : failed to open a socket in "
++                          "'%s', errno = %d\n", host_file, -fd);
++      }
++      kfree(host_file);
++
++      file->private_data = data;
++      return(0);
++
++ out_free1:
++      kfree(host_file);
++ out_free2:
++      free_contents(data->contents);
++      kfree(data);
++ out:
++      return(err);
++}
++
++static int hppfs_dir_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      int err;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      proc_dentry = inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&data->proc_file, proc_dentry, file->f_mode);
++      if(err)
++              goto out_free;
++
++      file->private_data = data;
++      return(0);
++
++ out_free:
++      kfree(data);
++ out:
++      return(err);
++}
++
++static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      loff_t (*llseek)(struct file *, loff_t, int);
++      loff_t ret;
++
++      llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
++      if(llseek != NULL){
++              ret = (*llseek)(proc_file, off, where);
++              if(ret < 0)
++                      return(ret);
++      }
++
++      return(default_llseek(file, off, where));
++}
++
++struct hppfs_dirent {
++      void *vfs_dirent;
++      filldir_t filldir;
++      struct dentry *dentry;
++};
++
++static int hppfs_filldir(void *d, const char *name, int size, 
++                       loff_t offset, ino_t inode, unsigned int type)
++{
++      struct hppfs_dirent *dirent = d;
++
++      if(file_removed(dirent->dentry, name))
++              return(0);
++
++      return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, 
++                                inode, type));
++}
++
++static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      int (*readdir)(struct file *, void *, filldir_t);
++      struct hppfs_dirent dirent = ((struct hppfs_dirent)
++                                    { vfs_dirent :    ent,
++                                      filldir :       filldir,
++                                      dentry :        file->f_dentry } );
++      int err;
++
++      readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
++
++      proc_file->f_pos = file->f_pos;
++      err = (*readdir)(proc_file, &dirent, hppfs_filldir);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      return(0);
++}
++
++static struct file_operations hppfs_file_fops = {
++      owner:          NULL,
++      llseek:         hppfs_llseek,
++      read:           hppfs_read,
++      write:          hppfs_write,
++      open:           hppfs_open,
++};
++
++static struct file_operations hppfs_dir_fops = {
++      owner:          NULL,
++      readdir:        hppfs_readdir,
++      open:           hppfs_dir_open,
++      fsync:          hppfs_fsync,
++};
++
++static int hppfs_statfs(struct super_block *sb, struct statfs *sf)
++{
++      sf->f_blocks = 0;
++      sf->f_bfree = 0;
++      sf->f_bavail = 0;
++      sf->f_files = 0;
++      sf->f_ffree = 0;
++      sf->f_type = HPPFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct super_operations hppfs_sbops = { 
++      put_inode:      force_delete,
++      delete_inode:   NULL,
++      statfs:         hppfs_statfs,
++};
++
++static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
++{
++      struct file proc_file;
++      struct dentry *proc_dentry;
++      int (*readlink)(struct dentry *, char *, int);
++      int err, n;
++
++      proc_dentry = dentry->d_inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&proc_file, proc_dentry, FMODE_READ);
++      if(err) 
++              return(err);
++
++      readlink = proc_dentry->d_inode->i_op->readlink;
++      n = (*readlink)(proc_dentry, buffer, buflen);
++
++      if(proc_file.f_op->release)
++              (*proc_file.f_op->release)(proc_dentry->d_inode, &proc_file);
++      
++      return(n);
++}
++
++static struct inode_operations hppfs_link_iops = {
++      readlink:       hppfs_readlink,
++};
++
++static void read_inode(struct inode *ino)
++{
++      struct inode *proc_ino;
++
++      proc_ino = ino->u.hppfs_i.proc_dentry->d_inode;
++      ino->i_uid = proc_ino->i_uid;
++      ino->i_gid = proc_ino->i_gid;
++      ino->i_atime = proc_ino->i_atime;
++      ino->i_mtime = proc_ino->i_mtime;
++      ino->i_ctime = proc_ino->i_ctime;
++      ino->i_ino = proc_ino->i_ino;
++      ino->i_dev = proc_ino->i_dev;
++      ino->i_mode = proc_ino->i_mode;
++      ino->i_nlink = proc_ino->i_nlink;
++      ino->i_size = proc_ino->i_size;
++      ino->i_blksize = proc_ino->i_blksize;
++      ino->i_blocks = proc_ino->i_blocks;
++}
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int *error)
++{
++      struct inode *inode;
++      int err = -ENOMEM;
++
++      inode = get_empty_inode();
++      if(inode == NULL) 
++              goto out;
++
++      insert_inode_hash(inode);
++      if(S_ISDIR(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_dir_iops;
++              inode->i_fop = &hppfs_dir_fops;
++      }
++      else if(S_ISLNK(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_link_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++      else {
++              inode->i_op = &hppfs_file_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++
++      inode->i_sb = sb;
++      inode->u.hppfs_i.proc_dentry = dentry;
++
++      read_inode(inode);
++      err = 0;
++
++      if(error) *error = err;
++      return(inode);
++ out:
++      if(error) *error = err;
++      return(NULL);
++}
++
++static struct super_block *hppfs_read_super(struct super_block *sb, void *d, 
++                                          int silent)
++{
++      struct inode *root_inode;
++      struct file_system_type *procfs;
++      struct super_block *proc_sb;
++
++      procfs = get_fs_type("proc");
++      if(procfs == NULL) 
++              goto out;
++
++      if(list_empty(&procfs->fs_supers))
++              goto out;
++
++      proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
++                           s_instances);
++      
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = HPPFS_SUPER_MAGIC;
++      sb->s_op = &hppfs_sbops;
++
++      dget(proc_sb->s_root);
++      root_inode = get_inode(sb, proc_sb->s_root, NULL);
++      if(root_inode == NULL)
++              goto out_dput;
++
++      sb->s_root = d_alloc_root(root_inode);
++      if(sb->s_root == NULL)
++              goto out_put;
++
++      return(sb);
++
++ out_put:
++      iput(root_inode);
++ out_dput:
++      dput(proc_sb->s_root);
++ out:
++      return(NULL);
++}
++
++DECLARE_FSTYPE(hppfs_type, "hppfs", hppfs_read_super, 0);
++
++static int __init init_hppfs(void)
++{
++      return(register_filesystem(&hppfs_type));
++}
++
++static void __exit exit_hppfs(void)
++{
++      unregister_filesystem(&hppfs_type);
++}
++
++module_init(init_hppfs)
++module_exit(exit_hppfs)
++MODULE_LICENSE("GPL");
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/hppfs/Makefile    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++O_TARGET := hppfs.o
++obj-y = hppfs_kern.o #hppfs_user.o
++obj-m = $(O_TARGET)
++
++CFLAGS_hppfs_kern.o := $(CFLAGS)
++#CFLAGS_hppfs_user.o := $(USER_CFLAGS)
++
++override CFLAGS =  
++
++include $(TOPDIR)/Rules.make
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/fs/Makefile  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,23 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := fs.o
++
++subdir-y =
++subdir-m =
++
++subdir-$(CONFIG_HOSTFS) += hostfs
++subdir-$(CONFIG_HPPFS) += hppfs
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++obj-m += $(join $(subdir-m),$(subdir-m:%=/%.o))
++
++include $(TOPDIR)/Rules.make
++
++dep:
++
++clean:
++
++archmrproper:
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/2_5compat.h  2003-09-09 16:43:55.000000000 +0400
+@@ -0,0 +1,109 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __2_5_COMPAT_H__
++#define __2_5_COMPAT_H__
++
++#include "linux/version.h"
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
++
++#ifndef mk_kdev
++#define mk_kdev(maj, min) MKDEV(maj, min)
++#endif
++
++#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
++      name :          dev_name, \
++      write :         write_proc, \
++      read :          NULL, \
++      device :        device_proc, \
++      unblank :       NULL, \
++      setup :         setup_proc, \
++      flags :         f, \
++      index :         -1, \
++      cflag :         0, \
++      next :          NULL \
++}
++
++#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request)
++
++#define ELV_NOOP ELEVATOR_NOOP
++#define INIT_ELV(queue, elv) elevator_init(elv, ELV_NOOP)
++
++#define REQUEST_LOCK io_request_lock
++
++#define INIT_HARDSECT(arr, maj, sizes) arr[maj] = sizes
++
++#define IS_WRITE(req) ((req)->cmd == WRITE)
++#define IS_READ(req) ((req)->cmd == READ)
++
++#define CPU(task) ((task)->cpu)
++
++/*
++ * chaos kernel has this already -bzzz
++ *
++ * #define yield() do { current->policy |= SCHED_YIELD; schedule(); } while(0)
++ */
++
++#define SET_PRI(task) \
++      do { (task)->prio = MAX_PRIO; } while(0);
++
++#else
++
++#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
++      name :          dev_name, \
++      write :         write_proc, \
++      read :          NULL, \
++      device :        device_proc, \
++      setup :         setup_proc, \
++      flags :         f, \
++      index :         -1, \
++      cflag :         0, \
++      next :          NULL \
++}
++
++#define INIT_GENDISK(maj, name, parts, bsizes, max, blops) { \
++      major :         maj, \
++      major_name :    name, \
++      minor_shift :   0, \
++      part :          parts, \
++      sizes :         bsizes, \
++      nr_real :       max, \
++      next :          NULL, \
++      fops :          blops, \
++      de_arr :        NULL, \
++      flags :         0 \
++}
++
++#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock)
++
++#define ELV_NOOP elevator_noop
++#define INIT_ELV(queue, elv) elevator_init(queue, elv, ELV_NOOP)
++
++#define REQUEST_LOCK ubd_lock
++
++#define INIT_HARDSECT(arr, maj, sizes)
++
++#define IS_WRITE(req) (rq_data_dir(req) == WRITE)
++#define IS_READ(req) (rq_data_dir(req) == READ)
++
++#define CPU(task) ((task)->cpu)
++
++#define SET_PRI(task) do ; while(0)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/chan_kern.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,53 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHAN_KERN_H__
++#define __CHAN_KERN_H__
++
++#include "linux/tty.h"
++#include "linux/list.h"
++#include "chan_user.h"
++
++struct chan {
++      struct list_head list;
++      unsigned int primary:1;
++      unsigned int input:1;
++      unsigned int output:1;
++      unsigned int opened:1;
++      int fd;
++      enum chan_init_pri pri;
++      struct chan_ops *ops;
++      void *data;
++};
++
++extern void chan_interrupt(struct list_head *chans, struct tq_struct *task,
++                         struct tty_struct *tty, int irq, void *dev);
++extern int parse_chan_pair(char *str, struct list_head *chans, int pri, 
++                         int device, struct chan_opts *opts);
++extern int open_chan(struct list_head *chans);
++extern int write_chan(struct list_head *chans, const char *buf, int len,
++                           int write_irq);
++extern int console_write_chan(struct list_head *chans, const char *buf, 
++                            int len);
++extern void close_chan(struct list_head *chans);
++extern void chan_enable_winch(struct list_head *chans, void *line);
++extern void enable_chan(struct list_head *chans, void *data);
++extern int chan_window_size(struct list_head *chans, 
++                           unsigned short *rows_out, 
++                           unsigned short *cols_out);
++extern int chan_out_fd(struct list_head *chans);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/chan_user.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,65 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHAN_USER_H__
++#define __CHAN_USER_H__
++
++#include "init.h"
++
++struct chan_opts {
++      void (*announce)(char *dev_name, int dev);
++      char *xterm_title;
++      int raw;
++      unsigned long tramp_stack;
++};
++
++enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
++
++struct chan_ops {
++      void *(*init)(char *, int, struct chan_opts *);
++      int (*open)(int, int, int, void *);
++      void (*close)(int, void *);
++      int (*read)(int, char *, void *);
++      int (*write)(int, const char *, int, void *);
++      int (*console_write)(int, const char *, int, void *);
++      int (*window_size)(int, void *, unsigned short *, unsigned short *);
++      void (*free)(void *);
++      int winch;
++};
++
++extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
++      xterm_ops;
++
++extern void generic_close(int fd, void *unused);
++extern int generic_read(int fd, char *c_out, void *unused);
++extern int generic_write(int fd, const char *buf, int n, void *unused);
++extern int generic_console_write(int fd, const char *buf, int n, void *state);
++extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
++                             unsigned short *cols_out);
++extern void generic_free(void *data);
++
++extern void register_winch(int fd, void *device_data);
++extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
++extern void setup_tracer_winch(void);
++
++#define __channel_help(fn, prefix) \
++__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
++"    Attach a console or serial line to a host channel.  See\n" \
++"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
++"    description of this switch.\n\n" \
++);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/debug.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and
++ * Lars Brinkhoff.
++ * Licensed under the GPL
++ */
++#ifndef __DEBUG_H
++#define __DEBUG_H
++
++extern int debugger_proxy(int status, pid_t pid);
++extern void child_proxy(pid_t pid, int status);
++extern void init_proxy (pid_t pid, int waiting, int status);
++extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
++extern void fake_child_exit(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/frame.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,51 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_H_
++#define __FRAME_H_
++
++#include "sysdep/frame.h"
++
++struct sc_frame {
++      void *data;
++      int len;
++      int sig_index;
++      int sc_index;
++      int sr_index;
++      int sr_relative;
++      int sp_index;
++      struct arch_frame_data arch;
++};
++
++extern struct sc_frame signal_frame_sc;
++
++struct si_frame {
++      void *data;
++      int len;
++      int sig_index;
++      int sip_index;
++      int si_index;
++      int sr_index;
++      int sr_relative;
++      int sp_index;
++};
++
++extern struct si_frame signal_frame_si;
++
++extern void capture_signal_stack(void);
++extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/frame_kern.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_KERN_H_
++#define __FRAME_KERN_H_
++
++#include "frame.h"
++#include "sysdep/frame_kern.h"
++
++extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 
++                               unsigned long handler,
++                               void (*restorer)(void), 
++                               struct pt_regs *regs, 
++                               sigset_t *mask);
++extern int setup_signal_stack_si(unsigned long stack_top, int sig, 
++                               unsigned long handler, 
++                               void (*restorer)(void), 
++                               struct pt_regs *regs, siginfo_t *info, 
++                               sigset_t *mask);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/frame_user.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_USER_H_
++#define __FRAME_USER_H_
++
++#include "sysdep/frame_user.h"
++#include "frame.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/helper.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __HELPER_H__
++#define __HELPER_H__
++
++extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
++                    unsigned long *stack_out);
++extern int run_helper_thread(int (*proc)(void *), void *arg, 
++                           unsigned int flags, unsigned long *stack_out,
++                           int stack_order);
++extern int helper_wait(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/hostaudio.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Steve Schmidtke 
++ * Licensed under the GPL
++ */
++
++#ifndef HOSTAUDIO_H
++#define HOSTAUDIO_H
++
++#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
++#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
++
++struct hostaudio_state {
++  int fd;
++};
++
++struct hostmixer_state {
++  int fd;
++};
++
++/* UML user-side protoypes */
++extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
++                                 size_t count, loff_t *ppos);
++extern ssize_t hostaudio_write_user(struct hostaudio_state *state, 
++                                  const char *buffer, size_t count, 
++                                  loff_t *ppos);
++extern int hostaudio_ioctl_user(struct hostaudio_state *state, 
++                              unsigned int cmd, unsigned long arg);
++extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, 
++                             char *dsp);
++extern int hostaudio_release_user(struct hostaudio_state *state);
++extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
++                              unsigned int cmd, unsigned long arg);
++extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, 
++                                    int w, char *mixer);
++extern int hostmixer_release_mixdev_user(struct hostmixer_state *state);
++
++#endif /* HOSTAUDIO_H */
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/init.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,114 @@
++#ifndef _LINUX_UML_INIT_H
++#define _LINUX_UML_INIT_H
++
++/* These macros are used to mark some functions or
++ * initialized data (doesn't apply to uninitialized data)
++ * as `initialization' functions. The kernel can take this
++ * as hint that the function is used only during the initialization
++ * phase and free up used memory resources after
++ *
++ * Usage:
++ * For functions:
++ *
++ * You should add __init immediately before the function name, like:
++ *
++ * static void __init initme(int x, int y)
++ * {
++ *    extern int z; z = x * y;
++ * }
++ *
++ * If the function has a prototype somewhere, you can also add
++ * __init between closing brace of the prototype and semicolon:
++ *
++ * extern int initialize_foobar_device(int, int, int) __init;
++ *
++ * For initialized data:
++ * You should insert __initdata between the variable name and equal
++ * sign followed by value, e.g.:
++ *
++ * static int init_variable __initdata = 0;
++ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
++ *
++ * Don't forget to initialize data not at file scope, i.e. within a function,
++ * as gcc otherwise puts the data into the bss section and not into the init
++ * section.
++ *
++ * Also note, that this data cannot be "const".
++ */
++
++#ifndef _LINUX_INIT_H
++typedef int (*initcall_t)(void);
++typedef void (*exitcall_t)(void);
++
++#define __init          __attribute__ ((__section__ (".text.init")))
++#define __exit          __attribute__ ((unused, __section__(".text.exit")))
++#define __initdata      __attribute__ ((__section__ (".data.init")))
++
++#endif
++
++#ifndef MODULE
++struct uml_param {
++        const char *str;
++        int (*setup_func)(char *, int *);
++};
++
++extern initcall_t __uml_initcall_start, __uml_initcall_end;
++extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
++extern const char *__uml_help_start, *__uml_help_end;
++#endif
++
++#define __uml_initcall(fn)                                            \
++      static initcall_t __uml_initcall_##fn __uml_init_call = fn
++
++#define __uml_exitcall(fn)                                            \
++      static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
++
++extern struct uml_param __uml_setup_start, __uml_setup_end;
++
++#define __uml_postsetup(fn)                                           \
++      static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
++
++#define __non_empty_string(dummyname,string)                          \
++      struct __uml_non_empty_string_struct_##dummyname                \
++      {                                                               \
++              char _string[sizeof(string)-2];                         \
++      }
++
++#ifndef MODULE
++#define __uml_setup(str, fn, help...)                                 \
++      __non_empty_string(fn ##_setup, str);                           \
++      __uml_help(fn, help);                                           \
++      static char __uml_setup_str_##fn[] __initdata = str;            \
++      static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
++#else
++#define __uml_setup(str, fn, help...)                                 \
++
++#endif
++
++#define __uml_help(fn, help...)                                               \
++      __non_empty_string(fn ##__help, help);                          \
++      static char __uml_help_str_##fn[] __initdata = help;            \
++      static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
++
++/*
++ * Mark functions and data as being only used at initialization
++ * or exit time.
++ */
++#define __uml_init_setup      __attribute__ ((unused,__section__ (".uml.setup.init")))
++#define __uml_setup_help      __attribute__ ((unused,__section__ (".uml.help.init")))
++#define __uml_init_call               __attribute__ ((unused,__section__ (".uml.initcall.init")))
++#define __uml_postsetup_call  __attribute__ ((unused,__section__ (".uml.postsetup.init")))
++#define __uml_exit_call               __attribute__ ((unused,__section__ (".uml.exitcall.exit")))
++
++#endif /* _LINUX_UML_INIT_H */
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/initrd.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __INITRD_USER_H__
++#define __INITRD_USER_H__
++
++extern int load_initrd(char *filename, void *buf, int size);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/irq_user.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,33 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_USER_H__
++#define __IRQ_USER_H__
++
++enum { IRQ_READ, IRQ_WRITE };
++
++extern void sigio_handler(int sig, struct uml_pt_regs *regs);
++extern int activate_fd(int irq, int fd, int type, void *dev_id);
++extern void free_irq_by_irq_and_dev(int irq, void *dev_id);
++extern void free_irq_by_fd(int fd);
++extern void reactivate_fd(int fd, int irqnum);
++extern void deactivate_fd(int fd, int irqnum);
++extern void forward_interrupts(int pid);
++extern void init_irq_signals(int on_sigstack);
++extern void forward_ipi(int fd, int pid);
++extern void free_irq_later(int irq, void *dev_id);
++
++#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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/kern.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,47 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __KERN_H__
++#define __KERN_H__
++
++/* These are all user-mode things which are convenient to call directly
++ * from kernel code and for which writing a wrapper is too much of a pain.
++ * The regular include files can't be included because this file is included
++ * only into kernel code, and user-space includes conflict with kernel
++ * includes.
++ */
++
++extern int errno;
++
++extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
++extern int sleep(int);
++extern int printf(char *fmt, ...);
++extern char *strerror(int errnum);
++extern char *ptsname(int __fd);
++extern int munmap(void *, int);
++extern void *sbrk(int increment);
++extern void *malloc(int size);
++extern void perror(char *err);
++extern int kill(int pid, int sig);
++extern int getuid(void);
++extern int pause(void);
++extern int write(int, const void *, int);
++extern int exit(int);
++extern int close(int);
++extern int read(unsigned int, char *, int);
++extern int pipe(int *);
++extern int sched_yield(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/kern_util.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,136 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __KERN_UTIL_H__
++#define __KERN_UTIL_H__
++
++#include "sysdep/ptrace.h"
++
++extern int ncpus;
++extern char *linux_prog;
++extern char *gdb_init;
++extern int kmalloc_ok;
++extern int timer_irq_inited;
++extern int jail;
++
++#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
++#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
++
++extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
++extern unsigned long stack_sp(unsigned long page);
++extern int kernel_thread_proc(void *data);
++extern void syscall_segv(int sig);
++extern int current_pid(void);
++extern void set_init_pid(int pid);
++extern unsigned long alloc_stack(int order, int atomic);
++extern int do_signal(int error);
++extern int is_stack_fault(unsigned long sp);
++extern unsigned long segv(unsigned long address, unsigned long ip, 
++                        int is_write, int is_user, void *sc_ptr);
++extern int set_user_mode(void *task);
++extern void syscall_ready(void);
++extern void set_tracing(void *t, int tracing);
++extern int is_tracing(void *task);
++extern int segv_syscall(void);
++extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
++extern int page_size(void);
++extern int page_mask(void);
++extern int need_finish_fork(void);
++extern int do_proc_op(void *t, int proc_id);
++extern void free_stack(unsigned long stack, int order);
++extern void add_input_request(int op, void (*proc)(int), void *arg);
++extern int sys_execve(char *file, char **argv, char **env);
++extern char *current_cmd(void);
++extern void timer_handler(int sig, struct uml_pt_regs *regs);
++extern int set_signals(int enable);
++extern void force_sigbus(void);
++extern int pid_to_processor_id(int pid);
++extern void block_signals(void);
++extern void unblock_signals(void);
++extern void deliver_signals(void *t);
++extern void lock_syscall(void);
++extern void unlock_syscall(void);
++extern void lock_trap(void);
++extern void unlock_trap(void);
++extern void lock_pid(void);
++extern void unlock_pid(void);
++extern void cpu_idle(void);
++extern void finish_fork(void);
++extern void paging_init(void);
++extern unsigned long um_virt_to_phys(void *t, unsigned long addr);
++extern void init_flush_vm(void);
++extern void *syscall_sp(void *t);
++extern void syscall_trace(void);
++extern int hz(void);
++extern void idle_timer(void);
++extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
++extern int external_pid(void *t);
++extern int pid_to_processor_id(int pid);
++extern void boot_timer_handler(int sig);
++extern void interrupt_end(void);
++extern void tracing_reboot(void);
++extern void tracing_halt(void);
++extern void tracing_cb(void (*proc)(void *), void *arg);
++extern int debugger_signal(int status, int pid);
++extern void debugger_parent_signal(int status, int pid);
++extern void child_signal(int pid, int status);
++extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
++extern int init_parent_proxy(int pid);
++extern void check_stack_overflow(void *ptr);
++extern void relay_signal(int sig, struct uml_pt_regs *regs);
++extern int singlestepping(void *t);
++extern void clear_singlestep(void *t);
++extern void not_implemented(void);
++extern int user_context(unsigned long sp);
++extern void timer_irq(struct uml_pt_regs *regs);
++extern void unprotect_stack(unsigned long stack);
++extern void do_uml_exitcalls(void);
++extern int attach_debugger(int idle_pid, int pid, int stop);
++extern void *round_up(unsigned long addr);
++extern void *round_down(unsigned long addr);
++extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
++extern int config_gdb(char *str);
++extern int remove_gdb(void);
++extern char *uml_strdup(char *string);
++extern void unprotect_kernel_mem(void);
++extern void protect_kernel_mem(void);
++extern unsigned long get_kmem_end(void);
++extern void set_kmem_end(unsigned long);
++extern void set_task_sizes(int arg);
++extern void uml_cleanup(void);
++extern int pid_to_processor_id(int pid);
++extern void set_current(void *t);
++extern void lock_signalled_task(void *t);
++extern void IPI_handler(int cpu);
++extern int jail_setup(char *line, int *add);
++extern void *get_init_task(void);
++extern int clear_user_proc(void *buf, int size);
++extern int copy_to_user_proc(void *to, void *from, int size);
++extern int copy_from_user_proc(void *to, void *from, int size);
++extern void set_thread_sc(void *sc);
++extern void bus_handler(int sig, struct uml_pt_regs *regs);
++extern long execute_syscall(void *r);
++extern int smp_sigio_handler(void);
++extern void *get_current(void);
++extern struct task_struct *get_task(int pid, int require);
++extern void machine_halt(void);
++extern int is_syscall(unsigned long addr);
++extern void arch_switch(void);
++extern int is_valid_pid(int pid);
++extern void free_irq(unsigned int, void *);
++extern int um_in_interrupt(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/line.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,102 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __LINE_H__
++#define __LINE_H__
++
++#include "linux/list.h"
++#include "linux/tqueue.h"
++#include "linux/tty.h"
++#include "asm/semaphore.h"
++#include "chan_user.h"
++
++struct line_driver {
++      char *name;
++      char *devfs_name;
++      short major;
++      short minor_start;
++      short type;
++      short subtype;
++      int read_irq;
++      char *read_irq_name;
++      int write_irq;
++      char *write_irq_name;
++      char *symlink_from;
++      char *symlink_to;
++};
++
++struct line {
++      char *init_str;
++      int init_pri;
++      struct list_head chan_list;
++      int valid;
++      int count;
++      struct tty_struct *tty;
++      struct semaphore sem;
++      char *buffer;
++      char *head;
++      char *tail;
++      int sigio;
++      struct tq_struct task;
++      struct line_driver *driver;
++      int have_irq;
++};
++
++#define LINE_INIT(str, d) \
++      { init_str :    str, \
++        init_pri :    INIT_STATIC, \
++        chan_list :   { }, \
++        valid :       1, \
++        count :       0, \
++        tty :         NULL, \
++        sem :         { }, \
++        buffer :      NULL, \
++        head :        NULL, \
++        tail :        NULL, \
++        sigio :       0, \
++        driver :      d, \
++          have_irq :  0 }
++
++struct lines {
++      int num;
++      int refcount;
++};
++
++#define LINES_INIT(n) \
++      {  num :                n, \
++         refcount :           0 }
++
++extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
++extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
++extern void line_close(struct line *lines, struct tty_struct *tty);
++extern int line_open(struct line *lines, struct tty_struct *tty, 
++                   struct chan_opts *opts);
++extern void line_setup(struct line *lines, int num, char *init);
++extern int line_write(struct line *line, struct tty_struct *tty, 
++                    const char *buf, int len);
++extern int line_write_room(struct tty_struct *tty);
++extern char *add_xterm_umid(char *base);
++extern int line_setup_irq(int fd, int input, int output, void *data);
++extern void line_close_chan(struct line *line);
++extern void line_disable(struct line *line, int current_irq);
++extern void line_register_devfs(struct lines *set, 
++                              struct line_driver *line_driver, 
++                              struct tty_driver *driver, struct line *lines,
++                              int nlines);
++extern void lines_init(struct line *lines, int nlines);
++extern void close_lines(struct line *lines, int nlines);
++
++#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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/Makefile     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,7 @@
++all : sc.h
++
++sc.h : ../util/mk_sc
++      ../util/mk_sc > $@
++
++../util/mk_sc :
++      $(MAKE) -C ../util mk_sc
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/mconsole.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MCONSOLE_H__
++#define __MCONSOLE_H__
++
++#define MCONSOLE_MAGIC (0xcafebabe)
++#define MCONSOLE_MAX_DATA (512)
++#define MCONSOLE_VERSION 2
++
++struct mconsole_request {
++      unsigned long magic;
++      int version;
++      int len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_reply {
++      int err;
++      int more;
++      int len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_notify {
++      unsigned long magic;
++      int version;    
++      enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
++             MCONSOLE_USER_NOTIFY } type;
++      int len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mc_request;
++
++struct mconsole_command
++{
++      char *command;
++      void (*handler)(struct mc_request *req);
++      int as_interrupt;
++};
++
++struct mc_request
++{
++      int len;
++      int as_interrupt;
++
++      int originating_fd;
++      int originlen;
++      unsigned char origin[128];                      /* sockaddr_un */
++
++      struct mconsole_request request;
++      struct mconsole_command *cmd;
++};
++
++extern char mconsole_socket_name[];
++
++extern int mconsole_unlink_socket(void);
++extern int mconsole_reply(struct mc_request *req, char *reply, int err,
++                        int more);
++
++extern void mconsole_version(struct mc_request *req);
++extern void mconsole_help(struct mc_request *req);
++extern void mconsole_halt(struct mc_request *req);
++extern void mconsole_reboot(struct mc_request *req);
++extern void mconsole_config(struct mc_request *req);
++extern void mconsole_remove(struct mc_request *req);
++extern void mconsole_sysrq(struct mc_request *req);
++extern void mconsole_cad(struct mc_request *req);
++extern void mconsole_stop(struct mc_request *req);
++extern void mconsole_go(struct mc_request *req);
++
++extern int mconsole_get_request(int fd, struct mc_request *req);
++extern int mconsole_notify(char *sock_name, int type, const void *data, 
++                         int len);
++extern char *mconsole_notify_socket(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/mconsole_kern.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MCONSOLE_KERN_H__
++#define __MCONSOLE_KERN_H__
++
++#include "linux/config.h"
++#include "linux/list.h"
++#include "mconsole.h"
++
++struct mconsole_entry {
++      struct list_head list;
++      struct mc_request request;
++};
++
++struct mc_device {
++      struct list_head list;
++      char *name;
++      int (*config)(char *);
++      int (*remove)(char *);
++};
++
++#ifdef CONFIG_MCONSOLE
++
++extern void mconsole_register_dev(struct mc_device *new);
++
++#else
++
++static inline void mconsole_register_dev(struct mc_device *new)
++{
++}
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/mem.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_H__
++#define __MEM_H__
++
++struct vm_reserved {
++      struct list_head list;
++      unsigned long start;
++      unsigned long end;
++};
++
++extern void set_usable_vm(unsigned long start, unsigned long end);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/mem_user.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,88 @@
++/*
++ * arch/um/include/mem_user.h
++ *
++ * BRIEF MODULE DESCRIPTION
++ * user side memory interface for support IO memory inside user mode linux
++ *
++ * Copyright (C) 2001 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _MEM_USER_H
++#define _MEM_USER_H
++
++struct mem_region {
++      char *driver;
++      unsigned long start;
++      unsigned long len;
++      void *mem_map;
++      int fd;
++};
++
++extern struct mem_region *regions[];
++extern struct mem_region physmem_region;
++
++#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
++
++extern unsigned long host_task_size;
++extern unsigned long task_size;
++
++extern int init_mem_user(void);
++extern int create_mem_file(unsigned long len);
++extern void setup_range(int fd, char *driver, unsigned long start,
++                      unsigned long total, struct mem_region *region,
++                      void *reserved);
++extern void map(unsigned long virt, unsigned long p, unsigned long len, 
++              int r, int w, int x);
++extern int unmap(void *addr, int len);
++extern int protect(unsigned long addr, unsigned long len, int r, int w, 
++                 int x, int must_succeed);
++extern void setup_memory(void *entry);
++extern unsigned long find_iomem(char *driver, unsigned long *len_out);
++extern int init_maps(struct mem_region *region);
++extern int nregions(void);
++extern void setup_one_range(int n, int fd, char *driver, unsigned long start, 
++                          unsigned long len, struct mem_region *region);
++extern int reserve_vm(unsigned long start, unsigned long end, void *e);
++extern unsigned long get_vm(unsigned long len);
++extern void setup_physmem(unsigned long start, unsigned long usable,
++                        unsigned long len);
++extern int setup_region(struct mem_region *region, void *entry);
++extern void add_iomem(char *name, int fd, int size);
++extern struct mem_region *phys_region(unsigned long phys);
++extern unsigned long phys_offset(unsigned long phys);
++extern void unmap_physmem(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/net_kern.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,75 @@
++#ifndef __UM_NET_KERN_H
++#define __UM_NET_KERN_H
++
++#include "linux/netdevice.h"
++#include "linux/skbuff.h"
++#include "linux/socket.h"
++#include "linux/list.h"
++
++#define MAX_UML_NETDEV (16)
++
++struct uml_net {
++      struct net_device *dev;
++      struct net_user_info *user;
++      struct net_kern_info *kern;
++      int private_size;
++      int transport_index;
++      unsigned char mac[ETH_ALEN];
++      int have_mac;
++};
++
++struct uml_net_private {
++      struct list_head list;
++      spinlock_t lock;
++      struct net_device *dev;
++      struct timer_list tl;
++      struct net_device_stats stats;
++      int fd;
++      unsigned char mac[ETH_ALEN];
++      int have_mac;
++      unsigned short (*protocol)(struct sk_buff *);
++      int (*open)(void *);
++      void (*close)(int, void *);
++      void (*remove)(void *);
++      int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
++      int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
++      
++      void (*add_address)(unsigned char *, unsigned char *, void *);
++      void (*delete_address)(unsigned char *, unsigned char *, void *);
++      int (*set_mtu)(int mtu, void *);
++      int user[1];
++};
++
++struct net_kern_info {
++      struct net_device *(*init)(int, int);
++      unsigned short (*protocol)(struct sk_buff *);
++      int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
++      int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
++};
++
++struct transport {
++      struct list_head list;
++      char *name;
++      int (*setup)(char *, struct uml_net *);
++};
++
++extern struct net_device *ether_init(int);
++extern unsigned short ether_protocol(struct sk_buff *);
++extern int setup_etheraddr(char *str, unsigned char *addr);
++extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
++extern int tap_setup_common(char *str, char *type, char **dev_name, 
++                          char *hw_addr, int *hw_setup, char **gate_addr);
++extern void register_transport(struct transport *new);
++
++#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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/net_user.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,57 @@
++#ifndef __UM_NET_USER_H__
++#define __UM_NET_USER_H__
++
++#define ETH_ADDR_LEN (6)
++#define ETH_HEADER_ETHERTAP (16)
++#define ETH_HEADER_OTHER (14)
++#define ETH_MAX_PACKET (1500)
++
++#define UML_NET_VERSION (4)
++
++struct net_user_info {
++      void (*init)(void *, void *);
++      int (*open)(void *);
++      void (*close)(int, void *);
++      void (*remove)(void *);
++      int (*set_mtu)(int mtu, void *);
++      void (*add_address)(unsigned char *, unsigned char *, void *);
++      void (*delete_address)(unsigned char *, unsigned char *, void *);
++      int max_packet;
++};
++
++extern void ether_user_init(void *data, void *dev);
++extern void dev_ip_addr(void *d, char *buf, char *bin_buf);
++extern void set_ether_mac(void *d, unsigned char *addr);
++extern void iter_addresses(void *d, void (*cb)(unsigned char *, 
++                                             unsigned char *, void *), 
++                         void *arg);
++
++extern void *get_output_buffer(int *len_out);
++extern void free_output_buffer(void *buffer);
++
++extern int tap_open_common(void *dev, char *gate_addr);
++extern void tap_check_ips(char *gate_addr, char *eth_addr);
++
++extern void read_output(int fd, char *output_out, int len);
++
++extern int net_read(int fd, void *buf, int len);
++extern int net_recvfrom(int fd, void *buf, int len);
++extern int net_write(int fd, void *buf, int len);
++extern int net_send(int fd, void *buf, int len);
++extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
++
++extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
++extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/os.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,121 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __OS_H__
++#define __OS_H__
++
++#include "asm/types.h"
++#include "../os/include/file.h"
++
++#define OS_TYPE_FILE 1 
++#define OS_TYPE_DIR 2 
++#define OS_TYPE_SYMLINK 3 
++#define OS_TYPE_CHARDEV 4
++#define OS_TYPE_BLOCKDEV 5
++#define OS_TYPE_FIFO 6
++#define OS_TYPE_SOCK 7
++
++struct openflags {
++      unsigned int r : 1;
++      unsigned int w : 1;
++      unsigned int s : 1;     /* O_SYNC */
++      unsigned int c : 1;     /* O_CREAT */
++      unsigned int t : 1;     /* O_TRUNC */
++      unsigned int a : 1;     /* O_APPEND */
++      unsigned int e : 1;     /* O_EXCL */
++};
++
++#define OPENFLAGS() ((struct openflags) { r : 0, w : 0, c : 0, s : 0 })
++
++static inline struct openflags of_read(struct openflags flags)
++{
++      flags.r = 1; 
++      return(flags);
++}
++
++static inline struct openflags of_write(struct openflags flags)
++{
++      flags.w = 1; 
++      return(flags); 
++}
++
++static inline struct openflags of_rdwr(struct openflags flags)
++{
++      return(of_read(of_write(flags)));
++}
++
++static inline struct openflags of_set_rw(struct openflags flags, int r, int w)
++{
++      flags.r = r;
++      flags.w = w;
++      return(flags);
++}
++
++static inline struct openflags of_sync(struct openflags flags)
++{ 
++      flags.s = 1; 
++      return(flags); 
++}
++
++static inline struct openflags of_create(struct openflags flags)
++{ 
++      flags.c = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_trunc(struct openflags flags)
++{ 
++      flags.t = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_append(struct openflags flags)
++{ 
++      flags.a = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_excl(struct openflags flags)
++{ 
++      flags.e = 1; 
++      return(flags); 
++}
++ 
++extern int os_seek_file(int fd, __u64 offset);
++extern int os_open_file(char *file, struct openflags flags, int mode);
++extern int os_read_file(int fd, char *buf, int len);
++extern int os_file_size(char *file, long long *size_out);
++extern int os_pipe(int *fd, int stream, int close_on_exec);
++extern int os_set_fd_async(int fd, int owner);
++extern int os_set_fd_block(int fd, int blocking);
++extern int os_accept_connection(int fd);
++extern int os_shutdown_socket(int fd, int r, int w);
++extern void os_close_file(int fd);
++extern int os_rcv_fd(int fd, int *helper_pid_out);
++extern int create_unix_socket(char *file, int len);
++extern int os_connect_socket(char *name);
++extern int os_file_type(char *file);
++extern int os_file_mode(char *file, struct openflags *mode_out);
++extern int os_write_file(int fd, char *buf, int count);
++
++extern unsigned long os_process_pc(int pid);
++extern int os_process_parent(int pid);
++extern void os_stop_process(int pid);
++extern void os_kill_process(int pid);
++extern void os_usr1_process(int pid);
++extern int os_getpid(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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/process.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,25 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROCESS_H__
++#define __PROCESS_H__
++
++#include <asm/sigcontext.h>
++
++extern void sig_handler(int sig, struct sigcontext sc);
++extern void alarm_handler(int sig, struct sigcontext sc);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/ptrace_user.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,18 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_USER_H__
++#define __PTRACE_USER_H__
++
++#include "sysdep/ptrace_user.h"
++
++extern int ptrace_getregs(long pid, unsigned long *regs_out);
++extern int ptrace_setregs(long pid, unsigned long *regs_in);
++extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
++extern void arch_enter_kernel(void *task, int pid);
++extern void arch_leave_kernel(void *task, int pid);
++extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sigcontext.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UML_SIGCONTEXT_H__
++#define __UML_SIGCONTEXT_H__
++
++#include "sysdep/sigcontext.h"
++
++extern int sc_size(void *data);
++extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data);
++extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data);
++extern void sc_to_sc(void *to_ptr, void *from_ptr);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sigio.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGIO_H__
++#define __SIGIO_H__
++
++extern int write_sigio_irq(int fd);
++extern int register_sigio_fd(int fd);
++extern int read_sigio_fd(int fd);
++extern int add_sigio_fd(int fd, int read);
++extern int ignore_sigio_fd(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/signal_kern.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGNAL_KERN_H__
++#define __SIGNAL_KERN_H__
++
++#include "sysdep/ptrace.h"
++
++extern void signal_deliverer(int sig);
++extern int probe_stack(unsigned long sp, int delta);
++extern int have_signals(void *t);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/signal_user.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGNAL_USER_H__
++#define __SIGNAL_USER_H__
++
++extern int signal_stack_size;
++
++extern int change_sig(int signal, int on);
++extern void set_sigstack(void *stack, int size);
++extern void set_handler(int sig, void (*handler)(int), int flags, ...);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/syscall_user.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSCALL_USER_H__
++#define __SYSCALL_USER_H__
++
++#include <asm/sigcontext.h>
++
++extern void syscall_handler(int sig, struct uml_pt_regs *regs);
++extern void exit_kernel(int pid, void *task);
++extern int do_syscall(void *task, int pid);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/frame.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_I386_H
++#define __FRAME_I386_H
++
++struct arch_frame_data_raw {
++      unsigned long sc_end;
++};
++
++struct arch_frame_data {
++      int fpstate_size;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/frame_kern.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,57 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_KERN_I386_H
++#define __FRAME_KERN_I386_H
++
++/* This is called from sys_sigreturn.  It takes the sp at the point of the
++ * sigreturn system call and returns the address of the sigcontext struct
++ * on the stack.
++ */
++
++static inline void *sp_to_sc(unsigned long sp)
++{
++      return((void *) sp);
++}
++
++static inline void *sp_to_rt_sc(unsigned long sp)
++{
++      unsigned long sc;
++
++      sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4;
++      return((void *) sc);
++}
++
++static inline void *sp_to_mask(unsigned long sp)
++{
++      unsigned long mask;
++
++      mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8;
++      return((void *) mask);
++}
++
++extern int sc_size(void *data);
++
++static inline void *sp_to_rt_mask(unsigned long sp)
++{
++      unsigned long mask;
++
++      mask = sp - signal_frame_si.sp_index + signal_frame_si.len + 
++              sc_size(&signal_frame_sc.arch) - 4;
++      return((void *) mask);
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/frame_user.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,82 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_USER_I386_H
++#define __FRAME_USER_I386_H
++
++#include <asm/page.h>
++#include "sysdep/frame.h"
++
++/* This stuff is to calculate the size of the fp state struct at runtime
++ * because it has changed between 2.2 and 2.4 and it would be good for a
++ * UML compiled on one to work on the other.
++ * So, setup_arch_frame_raw fills in the arch struct with the raw data, which
++ * just contains the address of the end of the sigcontext.  This is invoked
++ * from the signal handler.
++ * setup_arch_frame uses that data to figure out what 
++ * arch_frame_data.fpstate_size should be.  It really has no idea, since it's
++ * not allowed to do sizeof(struct fpstate) but it's safe to consider that it's
++ * everything from the end of the sgcontext up to the top of the stack.  So,
++ * it masks off the page number to get the offset within the page and subtracts
++ * that from the page size, and that's how big the fpstate struct will be
++ * considered to be.
++ */
++
++static inline void setup_arch_frame_raw(struct arch_frame_data_raw *data,
++                                      struct sigcontext *sc)
++{
++      data->sc_end = (unsigned long) sc;
++      data->sc_end += sizeof(*sc);
++}
++
++static inline void setup_arch_frame(struct arch_frame_data_raw *in, 
++                                  struct arch_frame_data *out)
++{
++      unsigned long fpstate_start = in->sc_end;
++
++      fpstate_start &= ~PAGE_MASK;
++      out->fpstate_size = PAGE_SIZE - fpstate_start;
++}
++
++/* This figures out where on the stack the SA_RESTORER function address
++ * is stored.  For i386, it's the signal handler return address, so it's
++ * located next to the frame pointer.
++ * This is inlined, so __builtin_frame_address(0) is correct.  Otherwise,
++ * it would have to be __builtin_frame_address(1).
++ */
++
++static inline unsigned long frame_restorer(void)
++{
++      unsigned long *fp;
++
++      fp = __builtin_frame_address(0);
++      return((unsigned long) (fp + 1));
++}
++
++/* Similarly, this returns the value of sp when the handler was first
++ * entered.  This is used to calculate the proper sp when delivering
++ * signals.
++ */
++
++static inline unsigned long frame_sp(void)
++{
++      unsigned long *fp;
++
++      fp = __builtin_frame_address(0);
++      return((unsigned long) (fp + 1));
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/ptrace.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,115 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_I386_PTRACE_H
++#define __SYSDEP_I386_PTRACE_H
++
++#include "sysdep/sc.h"
++
++struct uml_pt_regs {
++      unsigned long args[6];
++      long syscall;
++      int is_user;
++      void *sc;
++};
++
++#define EMPTY_UML_PT_REGS { \
++      syscall :       -1, \
++      args :          { [0 ... 5] = 0 }, \
++      is_user :       0, \
++      sc :            NULL }
++
++#define UPT_IP(regs) SC_IP((regs)->sc)
++#define UPT_SP(regs) SC_SP((regs)->sc)
++#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc)
++#define UPT_EAX(regs) SC_EAX((regs)->sc)
++#define UPT_EBX(regs) SC_EBX((regs)->sc)
++#define UPT_ECX(regs) SC_ECX((regs)->sc)
++#define UPT_EDX(regs) SC_EDX((regs)->sc)
++#define UPT_ESI(regs) SC_ESI((regs)->sc)
++#define UPT_EDI(regs) SC_EDI((regs)->sc)
++#define UPT_EBP(regs) SC_EBP((regs)->sc)
++#define UPT_ORIG_EAX(regs) ((regs)->syscall)
++#define UPT_CS(regs) SC_CS((regs)->sc)
++#define UPT_SS(regs) SC_SS((regs)->sc)
++#define UPT_DS(regs) SC_DS((regs)->sc)
++#define UPT_ES(regs) SC_ES((regs)->sc)
++#define UPT_FS(regs) SC_FS((regs)->sc)
++#define UPT_GS(regs) SC_GS((regs)->sc)
++#define UPT_SC(regs) ((regs)->sc)
++
++#define UPT_REG(regs, reg) \
++      ({      unsigned long val; \
++              switch(reg){ \
++              case EIP: val = UPT_IP(regs); break; \
++              case UESP: val = UPT_SP(regs); break; \
++              case EAX: val = UPT_EAX(regs); break; \
++              case EBX: val = UPT_EBX(regs); break; \
++              case ECX: val = UPT_ECX(regs); break; \
++              case EDX: val = UPT_EDX(regs); break; \
++              case ESI: val = UPT_ESI(regs); break; \
++              case EDI: val = UPT_EDI(regs); break; \
++              case EBP: val = UPT_EBP(regs); break; \
++              case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \
++              case CS: val = UPT_CS(regs); break; \
++              case SS: val = UPT_SS(regs); break; \
++              case DS: val = UPT_DS(regs); break; \
++              case ES: val = UPT_ES(regs); break; \
++              case FS: val = UPT_FS(regs); break; \
++              case GS: val = UPT_GS(regs); break; \
++              case EFL: val = UPT_EFLAGS(regs); break; \
++              default :  \
++                      panic("Bad register in UPT_REG : %d\n", reg);  \
++                      val = -1; \
++              } \
++              val; \
++      })
++      
++
++#define UPT_SET(regs, reg, val) \
++      do { \
++              switch(reg){ \
++              case EIP: UPT_IP(regs) = val; break; \
++              case UESP: UPT_SP(regs) = val; break; \
++              case EAX: UPT_EAX(regs) = val; break; \
++              case EBX: UPT_EBX(regs) = val; break; \
++              case ECX: UPT_ECX(regs) = val; break; \
++              case EDX: UPT_EDX(regs) = val; break; \
++              case ESI: UPT_ESI(regs) = val; break; \
++              case EDI: UPT_EDI(regs) = val; break; \
++              case EBP: UPT_EBP(regs) = val; break; \
++              case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \
++              case CS: UPT_CS(regs) = val; break; \
++              case SS: UPT_SS(regs) = val; break; \
++              case DS: UPT_DS(regs) = val; break; \
++              case ES: UPT_ES(regs) = val; break; \
++              case FS: UPT_FS(regs) = val; break; \
++              case GS: UPT_GS(regs) = val; break; \
++              case EFL: UPT_EFLAGS(regs) = val; break; \
++              default :  \
++                      panic("Bad register in UPT_SET : %d\n", reg);  \
++                      break; \
++              } \
++      } while (0)
++
++#define UPT_SET_SYSCALL_RETURN(regs, res) \
++      SC_SET_SYSCALL_RETURN((regs)->sc, (res))
++#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc)
++#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs)
++#define UPT_SYSCALL_NR(regs) ((regs)->syscall)
++#define UPT_SYSCALL_RET(regs) UPT_EAX(regs)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/ptrace_user.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,62 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_I386_PTRACE_USER_H__
++#define __SYSDEP_I386_PTRACE_USER_H__
++
++#include <asm/ptrace.h>
++
++#define PT_OFFSET(r) ((r) * sizeof(long))
++
++#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX])
++#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX)
++
++#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX)
++#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX)
++#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
++#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
++#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
++
++#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
++
++#define PT_IP_OFFSET PT_OFFSET(EIP)
++#define PT_IP(regs) ((regs)[EIP])
++#define PT_SP(regs) ((regs)[UESP])
++
++#ifndef FRAME_SIZE
++#define FRAME_SIZE (17)
++#endif
++#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
++
++#define FP_FRAME_SIZE (27)
++#define FPX_FRAME_SIZE (128)
++
++#ifdef PTRACE_GETREGS
++#define UM_HAVE_GETREGS
++#endif
++
++#ifdef PTRACE_SETREGS
++#define UM_HAVE_SETREGS
++#endif
++
++#ifdef PTRACE_GETFPREGS
++#define UM_HAVE_GETFPREGS
++#endif
++
++#ifdef PTRACE_SETFPREGS
++#define UM_HAVE_SETFPREGS
++#endif
++
++#ifdef PTRACE_GETFPXREGS
++#define UM_HAVE_GETFPXREGS
++#endif
++
++#ifdef PTRACE_SETFPXREGS
++#define UM_HAVE_SETFPXREGS
++#endif
++
++extern void update_debugregs(int seq);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/sigcontext.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,52 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_SIGCONTEXT_I386_H
++#define __SYS_SIGCONTEXT_I386_H
++
++#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
++
++#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
++#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0)
++
++#define SC_FAULT_ADDR(sc) SC_CR2(sc)
++#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2)
++
++/* ptrace expects that, at the start of a system call, %eax contains
++ * -ENOSYS, so this makes it so.
++ */
++#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
++
++/* These are General Protection and Page Fault */
++#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14))
++
++/* XXX struct sigcontext needs declaring by now */
++
++static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
++                            unsigned long syscall)
++{
++      regs->syscall = syscall;
++      regs->args[0] = SC_EBX(sc);
++      regs->args[1] = SC_ECX(sc);
++      regs->args[2] = SC_EDX(sc);
++      regs->args[3] = SC_ESI(sc);
++      regs->args[4] = SC_EDI(sc);
++      regs->args[5] = SC_EBP(sc);
++}
++
++extern unsigned long *sc_sigmask(void *sc_ptr);
++extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-i386/syscalls.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,59 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/unistd.h"
++
++typedef long syscall_handler_t(struct pt_regs);
++
++#define EXECUTE_SYSCALL(syscall, regs) (*sys_call_table[syscall])(*regs);
++
++extern syscall_handler_t sys_modify_ldt;
++extern syscall_handler_t old_mmap_i386;
++extern syscall_handler_t old_select;
++extern syscall_handler_t sys_ni_syscall;
++
++#define ARCH_SYSCALLS \
++      [ __NR_mmap ] = old_mmap_i386, \
++      [ __NR_select ] = old_select, \
++      [ __NR_vm86old ] = sys_ni_syscall, \
++        [ __NR_modify_ldt ] = sys_modify_ldt, \
++      [ __NR_lchown32 ] = sys_lchown, \
++      [ __NR_getuid32 ] = sys_getuid, \
++      [ __NR_getgid32 ] = sys_getgid, \
++      [ __NR_geteuid32 ] = sys_geteuid, \
++      [ __NR_getegid32 ] = sys_getegid, \
++      [ __NR_setreuid32 ] = sys_setreuid, \
++      [ __NR_setregid32 ] = sys_setregid, \
++      [ __NR_getgroups32 ] = sys_getgroups, \
++      [ __NR_setgroups32 ] = sys_setgroups, \
++      [ __NR_fchown32 ] = sys_fchown, \
++      [ __NR_setresuid32 ] = sys_setresuid, \
++      [ __NR_getresuid32 ] = sys_getresuid, \
++      [ __NR_setresgid32 ] = sys_setresgid, \
++      [ __NR_getresgid32 ] = sys_getresgid, \
++      [ __NR_chown32 ] = sys_chown, \
++      [ __NR_setuid32 ] = sys_setuid, \
++      [ __NR_setgid32 ] = sys_setgid, \
++      [ __NR_setfsuid32 ] = sys_setfsuid, \
++      [ __NR_setfsgid32 ] = sys_setfsgid, \
++      [ __NR_pivot_root ] = sys_pivot_root, \
++      [ __NR_mincore ] = sys_mincore, \
++      [ __NR_madvise ] = sys_madvise, \
++        [ 222 ] = sys_ni_syscall, 
++        
++/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
++
++#define LAST_ARCH_SYSCALL 222
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ia64/ptrace.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_PTRACE_H
++#define __SYSDEP_IA64_PTRACE_H
++
++struct sys_pt_regs {
++  int foo;
++};
++
++#define EMPTY_REGS { 0 }
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ia64/sigcontext.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_SIGCONTEXT_H
++#define __SYSDEP_IA64_SIGCONTEXT_H
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ia64/syscalls.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_SYSCALLS_H
++#define __SYSDEP_IA64_SYSCALLS_H
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ppc/ptrace.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,104 @@
++/* 
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_PTRACE_PPC_H
++#define __SYS_PTRACE_PPC_H
++
++#include "linux/config.h"
++#include "linux/types.h"
++
++/* the following taken from <asm-ppc/ptrace.h> */
++
++#ifdef CONFIG_PPC64
++#define PPC_REG unsigned long /*long*/
++#else
++#define PPC_REG unsigned long
++#endif
++struct sys_pt_regs_s {
++      PPC_REG gpr[32];
++      PPC_REG nip;
++      PPC_REG msr;
++      PPC_REG orig_gpr3;      /* Used for restarting system calls */
++      PPC_REG ctr;
++      PPC_REG link;
++      PPC_REG xer;
++      PPC_REG ccr;
++      PPC_REG mq;             /* 601 only (not used at present) */
++                              /* Used on APUS to hold IPL value. */
++      PPC_REG trap;           /* Reason for being here */
++      PPC_REG dar;            /* Fault registers */
++      PPC_REG dsisr;
++      PPC_REG result;         /* Result of a system call */
++};
++
++#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG))
++
++struct sys_pt_regs {
++    PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)];
++};
++
++#define UM_MAX_REG (PT_FPR0)
++#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG))
++
++#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } }
++
++#define UM_REG(r, n) ((r)->regs[n])
++
++#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3)
++#define UM_SP(r) UM_REG(r, PT_R1)
++#define UM_IP(r) UM_REG(r, PT_NIP)
++#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR)
++#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0)
++#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3)
++#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4)
++#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5)
++#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6)
++#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7)
++#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8)
++
++#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG))
++#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG))
++#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG))
++#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG))
++#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG))
++
++#define UM_SET_SYSCALL_RETURN(_regs, result)          \
++do {                                                    \
++        if (result < 0) {                             \
++              (_regs)->regs[PT_CCR] |= 0x10000000;    \
++              UM_SYSCALL_RET((_regs)) = -result;      \
++        } else {                                      \
++              UM_SYSCALL_RET((_regs)) = result;       \
++        }                                               \
++} while(0)
++
++extern void shove_aux_table(unsigned long sp);
++#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp);
++
++/* These aren't actually defined.  The undefs are just to make sure
++ * everyone's clear on the concept.
++ */
++#undef UML_HAVE_GETREGS
++#undef UML_HAVE_GETFPREGS
++#undef UML_HAVE_SETREGS
++#undef UML_HAVE_SETFPREGS
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ppc/sigcontext.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,62 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_SIGCONTEXT_PPC_H
++#define __SYS_SIGCONTEXT_PPC_H
++
++#define DSISR_WRITE 0x02000000
++
++#define SC_FAULT_ADDR(sc) ({ \
++              struct sigcontext_struct *_sc = (sc); \
++              long retval = -1; \
++              switch (_sc->regs->trap) { \
++              case 0x300: \
++                      /* data exception */ \
++                      retval = _sc->regs->dar; \
++                      break; \
++              case 0x400: \
++                      /* instruction exception */ \
++                      retval = _sc->regs->nip; \
++                      break; \
++              default: \
++                      panic("SC_FAULT_ADDR: unhandled trap type\n"); \
++              } \
++              retval; \
++      })
++
++#define SC_FAULT_WRITE(sc) ({ \
++              struct sigcontext_struct *_sc = (sc); \
++              long retval = -1; \
++              switch (_sc->regs->trap) { \
++              case 0x300: \
++                      /* data exception */ \
++                      retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
++                      break; \
++              case 0x400: \
++                      /* instruction exception: not a write */ \
++                      retval = 0; \
++                      break; \
++              default: \
++                      panic("SC_FAULT_ADDR: unhandled trap type\n"); \
++              } \
++              retval; \
++      })
++
++#define SC_IP(sc) ((sc)->regs->nip)
++#define SC_SP(sc) ((sc)->regs->gpr[1])
++#define SEGV_IS_FIXABLE(sc) (1)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysdep-ppc/syscalls.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,50 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2,
++                             unsigned long arg3, unsigned long arg4,
++                             unsigned long arg5, unsigned long arg6);
++
++#define EXECUTE_SYSCALL(syscall, regs) \
++        (*sys_call_table[syscall])(UM_SYSCALL_ARG1(&regs), \
++                                 UM_SYSCALL_ARG2(&regs), \
++                                 UM_SYSCALL_ARG3(&regs), \
++                                 UM_SYSCALL_ARG4(&regs), \
++                                 UM_SYSCALL_ARG5(&regs), \
++                                 UM_SYSCALL_ARG6(&regs))
++
++extern syscall_handler_t sys_mincore;
++extern syscall_handler_t sys_madvise;
++
++/* old_mmap needs the correct prototype since syscall_kern.c includes
++ * this file.
++ */
++int old_mmap(unsigned long addr, unsigned long len,
++           unsigned long prot, unsigned long flags,
++           unsigned long fd, unsigned long offset);
++
++#define ARCH_SYSCALLS \
++      [ __NR_modify_ldt ] = sys_ni_syscall, \
++      [ __NR_pciconfig_read ] = sys_ni_syscall, \
++      [ __NR_pciconfig_write ] = sys_ni_syscall, \
++      [ __NR_pciconfig_iobase ] = sys_ni_syscall, \
++      [ __NR_pivot_root ] = sys_ni_syscall, \
++      [ __NR_multiplexer ] = sys_ni_syscall, \
++      [ __NR_mmap ] = old_mmap, \
++      [ __NR_madvise ] = sys_madvise, \
++      [ __NR_mincore ] = sys_mincore, 
++
++#define LAST_ARCH_SYSCALL __NR_mincore
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/sysrq.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SYSRQ_H
++#define __UM_SYSRQ_H
++
++extern void show_trace(unsigned long *stack);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/tlb.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TLB_H__
++#define __TLB_H__
++
++extern void mprotect_kernel_vm(int w);
++extern void force_flush_all(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/ubd_user.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,78 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_UBD_USER_H
++#define __UM_UBD_USER_H
++
++#include "os.h"
++
++enum ubd_req { UBD_READ, UBD_WRITE };
++
++struct io_thread_req {
++      enum ubd_req op;
++      int fds[2];
++      unsigned long offsets[2];
++      unsigned long long offset;
++      unsigned long length;
++      char *buffer;
++      int sectorsize;
++      unsigned long sector_mask;
++      unsigned long cow_offset;
++      unsigned long bitmap_words[2];
++      int error;
++};
++
++extern int open_ubd_file(char *file, struct openflags *openflags, 
++                       char **backing_file_out, int *bitmap_offset_out, 
++                       unsigned long *bitmap_len_out, int *data_offset_out,
++                       int *create_cow_out);
++extern int create_cow_file(char *cow_file, char *backing_file, 
++                         struct openflags flags, int sectorsize, 
++                         int *bitmap_offset_out, 
++                         unsigned long *bitmap_len_out,
++                         int *data_offset_out);
++extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
++extern int read_ubd_fs(int fd, void *buffer, int len);
++extern int write_ubd_fs(int fd, char *buffer, int len);
++extern int start_io_thread(unsigned long sp, int *fds_out);
++extern void do_io(struct io_thread_req *req);
++extern int ubd_is_dir(char *file);
++
++static inline int ubd_test_bit(__u64 bit, unsigned char *data)
++{
++      __u64 n;
++      int bits, off;
++
++      bits = sizeof(data[0]) * 8;
++      n = bit / bits;
++      off = bit % bits;
++      return((data[n] & (1 << off)) != 0);
++}
++
++static inline void ubd_set_bit(__u64 bit, unsigned char *data)
++{
++      __u64 n;
++      int bits, off;
++
++      bits = sizeof(data[0]) * 8;
++      n = bit / bits;
++      off = bit % bits;
++      data[n] |= (1 << off);
++}
++
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/umid.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++extern int umid_file_name(char *name, char *buf, int len);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/umn.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UMN_H
++#define __UMN_H
++
++extern int open_umn_tty(int *slave_out, int *slipno_out);
++extern void close_umn_tty(int master, int slave);
++extern int umn_send_packet(int fd, void *data, int len);
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern void slip_unesc(unsigned char s);
++extern void umn_read(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/user.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,29 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __USER_H__
++#define __USER_H__
++
++extern void panic(const char *fmt, ...);
++extern int printk(const char *fmt, ...);
++extern void schedule(void);
++extern void *um_kmalloc(int size);
++extern void *um_kmalloc_atomic(int size);
++extern void kfree(void *ptr);
++extern int in_aton(char *str);
++extern int open_gdb_chan(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/include/user_util.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,126 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __USER_UTIL_H__
++#define __USER_UTIL_H__
++
++#include "sysdep/ptrace.h"
++
++extern int grantpt(int __fd);
++extern int unlockpt(int __fd);
++extern char *ptsname(int __fd);
++
++enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
++
++struct cpu_task {
++      int pid;
++      void *task;
++};
++
++extern struct cpu_task cpu_tasks[];
++
++extern unsigned long low_physmem;
++extern unsigned long high_physmem;
++extern unsigned long uml_physmem;
++extern unsigned long uml_reserved;
++extern unsigned long end_vm;
++extern unsigned long start_vm;
++
++extern int tracing_pid;
++extern int honeypot;
++
++extern char host_info[];
++
++extern char saved_command_line[];
++extern char command_line[];
++
++extern int gdb_pid;
++
++extern char *tempdir;
++
++extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
++extern unsigned long _unprotected_end;
++extern unsigned long brk_start;
++
++extern int pty_output_sigio;
++extern int pty_close_sigio;
++
++extern void *open_maps(void);
++extern void close_maps(void *fd);
++extern unsigned long get_brk(void);
++extern void stop(void);
++extern int proc_start_thread(unsigned long ip, unsigned long sp);
++extern void stack_protections(unsigned long address);
++extern void task_protections(unsigned long address);
++extern void abandon_proc_space(int (*proc)(void *), unsigned long sp);
++extern int signals(int (*init_proc)(void *), void *sp);
++extern int __personality(int);
++extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
++extern void *add_signal_handler(int sig, void (*handler)(int));
++extern void signal_init(void);
++extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
++                          int clone_flags, int (*tramp)(void *));
++extern void trace_myself(void);
++extern void timer(void);
++extern void get_profile_timer(void);
++extern void disable_profile_timer(void);
++extern void set_timers(int set_signal);
++extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
++extern int input_loop(void);
++extern void continue_execing_proc(int pid);
++extern int linux_main(int argc, char **argv);
++extern void remap_data(void *segment_start, void *segment_end, int w);
++extern void set_cmdline(char *cmd);
++extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
++extern void setup_input(void);
++extern int get_pty(void);
++extern void save_signal_state(int *sig_ptr);
++extern void *um_kmalloc(int size);
++extern int raw(int fd, int complain);
++extern int switcheroo(int fd, int prot, void *from, void *to, int size);
++extern void idle_sleep(int secs);
++extern void setup_machinename(char *machine_out);
++extern void setup_hostinfo(void);
++extern void add_arg(char *cmd_line, char *arg);
++extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
++extern void attach_process(int pid);
++extern void calc_sigframe_size(void);
++extern int fork_tramp(void *sig_stack);
++extern void do_exec(int old_pid, int new_pid);
++extern void tracer_panic(char *msg, ...);
++extern void close_fd(int);
++extern int make_tempfile(const char *template, char **tempname, int do_unlink);
++extern char *get_umid(int only_if_set);
++extern void do_longjmp(void *p);
++extern void term_handler(int sig);
++extern void suspend_new_thread(int fd);
++extern int detach(int pid, int sig);
++extern int attach(int pid);
++extern void kill_child_dead(int pid);
++extern int cont(int pid);
++extern void check_ptrace(void);
++extern void check_sigio(void);
++extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
++extern int user_read(int fd, char *buf, int len);
++extern int user_write(int fd, char *buf, int len);
++extern void write_sigio_workaround(void);
++extern void arch_check_bugs(void);
++extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
++extern void user_time_init(void);
++extern unsigned long pid_pc(int pid);
++extern int arch_fixup(unsigned long address, void *sc_ptr);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/config.c.in   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++/* 
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/exec_kern.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,124 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/slab.h"
++#include "linux/smp_lock.h"
++#include "asm/ptrace.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "tlb.h"
++#include "2_5compat.h"
++#include "os.h"
++
++/* See comment above fork_tramp for why sigstop is defined and used like
++ * this
++ */
++
++static int sigstop = SIGSTOP;
++
++static int exec_tramp(void *sig_stack)
++{
++      int sig = sigstop;
++
++      block_signals();
++      init_new_thread(sig_stack, NULL);
++      kill(os_getpid(), sig);
++      return(0);
++}
++
++void flush_thread(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((void *) current->thread.kernel_stack,
++                                 stack, 0, exec_tramp);
++      if(new_pid < 0){
++              printk(KERN_ERR 
++                     "flush_thread : new thread failed, errno = %d\n",
++                     -new_pid);
++              do_exit(SIGKILL);
++      }
++
++      if(current->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);
++      os_usr1_process(os_getpid());
++
++      free_page(stack);
++      protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
++      task_protections((unsigned long) current);
++      force_flush_all();
++      unblock_signals();
++}
++
++void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
++{
++      set_fs(USER_DS);
++      flush_tlb_mm(current->mm);
++      PT_REGS_IP(regs) = eip;
++      PT_REGS_SP(regs) = esp;
++      PT_FIX_EXEC_STACK(esp);
++}
++
++static int execve1(char *file, char **argv, char **env)
++{
++        int error;
++
++        error = do_execve(file, argv, env, &current->thread.regs);
++        if (error == 0){
++                current->ptrace &= ~PT_DTRACE;
++                set_cmdline(current_cmd());
++        }
++        return(error);
++}
++
++int um_execve(char *file, char **argv, char **env)
++{
++      if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp);
++      return(-1);
++}
++
++int sys_execve(char *file, char **argv, char **env)
++{
++      int error;
++      char *filename;
++
++      lock_kernel();
++      filename = getname((char *) file);
++      error = PTR_ERR(filename);
++      if (IS_ERR(filename)) goto out;
++      error = execve1(filename, argv, env);
++      putname(filename);
++ out:
++      unlock_kernel();
++      return(error);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/exec_user.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,49 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <sched.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include <signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "ptrace_user.h"
++
++void do_exec(int old_pid, int new_pid)
++{
++      unsigned long regs[FRAME_SIZE];
++
++      if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
++         (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) ||
++         (waitpid(new_pid, 0, WUNTRACED) < 0))
++              tracer_panic("do_exec failed to attach proc - errno = %d",
++                           errno);
++
++      if(ptrace_getregs(old_pid, regs) < 0)
++              tracer_panic("do_exec failed to get registers - errno = %d",
++                           errno);
++
++      kill(old_pid, SIGKILL);
++
++      if(ptrace_setregs(new_pid, regs) < 0)
++              tracer_panic("do_exec failed to start new proc - errno = %d",
++                           errno);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/exitcode.c    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,70 @@
++/* 
++ * 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"
++
++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 *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);
++}
++
++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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/frame.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,293 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <signal.h>
++#include <wait.h>
++#include <sched.h>
++#include <errno.h>
++#include <sys/ptrace.h>
++#include <sys/mman.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++#include "frame_user.h"
++#include "kern_util.h"
++#include "ptrace_user.h"
++#include "os.h"
++
++static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
++                       unsigned long top, void **data_out)
++{
++      unsigned long regs[FRAME_SIZE];
++      int pid, status, n, len;
++
++      /* Start the child as a thread */
++      pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);
++      if(pid < 0){
++              printf("capture_stack : clone failed - errno = %d\n", errno);
++              exit(1);
++      }
++
++      /* Wait for it to stop itself and continue it with a SIGUSR1 to force 
++       * it into the signal handler.
++       */
++      n = waitpid(pid, &status, WUNTRACED);
++      if(n < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++              fprintf(stderr, "capture_stack : Expected SIGSTOP, "
++                      "got status = 0x%x\n", status);
++              exit(1);
++      }
++      if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){
++              printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      /* Wait for it to stop itself again and grab its registers again.  
++       * At this point, the handler has stuffed the addresses of
++       * sig, sc, and SA_RESTORER in raw.
++       */
++      n = waitpid(pid, &status, WUNTRACED);
++      if(n < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++              fprintf(stderr, "capture_stack : Expected SIGSTOP, "
++                      "got status = 0x%x\n", status);
++              exit(1);
++      }
++      if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){
++              printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      /* It has outlived its usefulness, so continue it so it can exit */
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){
++              printf("capture_stack : mmap failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(waitpid(pid, &status, 0) < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
++              printf("capture_stack : Expected exit status 0, "
++                     "got status = 0x%x\n", status);
++              exit(1);
++      }
++
++      /* The frame that we want is the top of the signal stack */
++
++      len = top - PT_SP(regs);
++      *data_out = malloc(len);
++      if(*data_out == NULL){
++              printf("capture_stack : malloc failed - errno = %d\n", errno);
++              exit(1);
++      }
++      memcpy(*data_out, (void *) PT_SP(regs), len);
++
++      return(len);
++}
++
++static void child_common(void *sp, int size, sighandler_t handler, int flags)
++{
++      stack_t ss;
++      struct sigaction sa;
++
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++              printf("PTRACE_TRACEME failed, errno = %d\n", errno);
++      }
++      ss.ss_sp = sp;
++      ss.ss_flags = 0;
++      ss.ss_size = size;
++      if(sigaltstack(&ss, NULL) < 0){
++              printf("sigaltstack failed - errno = %d\n", errno);
++              _exit(1);
++      }
++
++      sa.sa_handler = handler;
++      sigemptyset(&sa.sa_mask);
++      sa.sa_flags = SA_ONSTACK | flags;
++      if(sigaction(SIGUSR1, &sa, NULL) < 0){
++              printf("sigaction failed - errno = %d\n", errno);
++              _exit(1);
++      }
++
++      os_stop_process(os_getpid());
++}
++
++struct sc_frame signal_frame_sc;
++
++struct sc_frame_raw {
++      void *stack;
++      int size;
++      unsigned long sig;
++      unsigned long sc;
++      unsigned long sr;
++      unsigned long sp;
++      struct arch_frame_data_raw arch;
++};
++
++static struct sc_frame_raw *raw_sc = NULL;
++
++static void sc_handler(int sig, struct sigcontext sc)
++{
++      raw_sc->sig = (unsigned long) &sig;
++      raw_sc->sc = (unsigned long) &sc;
++      raw_sc->sr = frame_restorer();
++      raw_sc->sp = frame_sp();
++      setup_arch_frame_raw(&raw_sc->arch, &sc);
++      os_stop_process(os_getpid());
++      _exit(0);
++}
++
++static int sc_child(void *arg)
++{
++      raw_sc = arg;
++      child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, 
++                   0);
++      return(-1);
++}
++
++struct si_frame signal_frame_si;
++
++struct si_frame_raw {
++      void *stack;
++      int size;
++      unsigned long sig;
++      unsigned long sip;
++      unsigned long si;
++      unsigned long sr;
++      unsigned long sp;
++};
++
++static struct si_frame_raw *raw_si = NULL;
++
++static void si_handler(int sig, siginfo_t *si)
++{
++      raw_si->sig = (unsigned long) &sig;
++      raw_si->sip = (unsigned long) &si;
++      raw_si->si = (unsigned long) si;
++      raw_si->sr = frame_restorer();
++      raw_si->sp = frame_sp();
++      os_stop_process(os_getpid());
++      _exit(0);
++}
++
++static int si_child(void *arg)
++{
++      raw_si = arg;
++      child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler,
++                   SA_SIGINFO);
++      return(-1);
++}
++
++void capture_signal_stack(void)
++{
++      struct sc_frame_raw raw_sc;
++      struct si_frame_raw raw_si;
++      void *stack, *sigstack;
++      unsigned long top, sig_top, base;
++
++      stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){
++              printf("capture_signal_stack : mmap failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++      sig_top = (unsigned long) sigstack + PAGE_SIZE;
++
++      raw_sc.stack = sigstack;
++      raw_sc.size = PAGE_SIZE;
++      signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
++                                          sig_top, &signal_frame_sc.data);
++
++      /* These are the offsets within signal_frame_sc.data (counting from
++       * the bottom) of sig, sc, SA_RESTORER, and the initial sp.
++       */
++
++      base = sig_top - signal_frame_sc.len;
++      signal_frame_sc.sig_index = raw_sc.sig - base;
++      signal_frame_sc.sc_index = raw_sc.sc - base;
++      signal_frame_sc.sr_index = raw_sc.sr - base;
++      if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) == 
++         (unsigned long) sigstack){
++              unsigned long *sr = (unsigned long *) raw_sc.sr;
++              unsigned long frame = (unsigned long) signal_frame_sc.data;
++
++              signal_frame_sc.sr_relative = 1;
++              *sr -= raw_sc.sr;
++              *((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
++      }
++      else signal_frame_sc.sr_relative = 0;
++      signal_frame_sc.sp_index = raw_sc.sp - base;
++      setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
++
++      /* Repeat for the siginfo variant */
++
++      raw_si.stack = sigstack;
++      raw_si.size = PAGE_SIZE;
++      signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
++                                          sig_top, &signal_frame_si.data);
++      base = sig_top - signal_frame_si.len;
++      signal_frame_si.sig_index = raw_si.sig - base;
++      signal_frame_si.sip_index = raw_si.sip - base;
++      signal_frame_si.si_index = raw_si.si - base;
++      signal_frame_si.sr_index = raw_si.sr - base;
++      if((*((unsigned long *) raw_si.sr) & PAGE_MASK) == 
++         (unsigned long) sigstack){
++              unsigned long *sr = (unsigned long *) raw_si.sr;
++              unsigned long frame = (unsigned long) signal_frame_si.data;
++
++              signal_frame_sc.sr_relative = 1;
++              *sr -= raw_si.sr;
++              *((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
++      }
++      else signal_frame_si.sr_relative = 0;
++      signal_frame_si.sp_index = raw_si.sp - base;
++
++      if((munmap(stack, PAGE_SIZE) < 0) || 
++         (munmap(sigstack, PAGE_SIZE) < 0)){
++              printf("capture_signal_stack : munmap failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++}
++
++void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
++{
++      struct sigcontext *sc = sc_ptr;
++
++      SC_IP(sc) = ip;
++      SC_SP(sc) = sp;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/frame_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,131 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/signal.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "sysdep/ptrace.h"
++
++int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
++{
++      if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
++              return -EFAULT;
++      if (from->si_code < 0)
++              return __copy_to_user(to, from, sizeof(siginfo_t));
++      else {
++              int err;
++
++              /* If you change siginfo_t structure, please be sure
++                 this code is fixed accordingly.
++                 It should never copy any pad contained in the structure
++                 to avoid security leaks, but must copy the generic
++                 3 ints plus the relevant union member.  */
++              err = __put_user(from->si_signo, &to->si_signo);
++              err |= __put_user(from->si_errno, &to->si_errno);
++              err |= __put_user((short)from->si_code, &to->si_code);
++              /* First 32bits of unions are always present.  */
++              err |= __put_user(from->si_pid, &to->si_pid);
++              switch (from->si_code >> 16) {
++              case __SI_FAULT >> 16:
++                      break;
++              case __SI_CHLD >> 16:
++                      err |= __put_user(from->si_utime, &to->si_utime);
++                      err |= __put_user(from->si_stime, &to->si_stime);
++                      err |= __put_user(from->si_status, &to->si_status);
++              default:
++                      err |= __put_user(from->si_uid, &to->si_uid);
++                      break;
++              }
++              return err;
++      }
++}
++
++static int copy_restorer(void (*restorer)(void), unsigned long start, 
++                       unsigned long sr_index, int sr_relative)
++{
++      if(restorer != 0){
++              if(copy_to_user((void *) (start + sr_index), &restorer, 
++                              sizeof(restorer)))
++                      return(1);
++      }
++      else if(sr_relative){
++              unsigned long *sr = (unsigned long *) (start + sr_index);
++              *sr += (unsigned long) sr;
++      }
++      return(0);
++}
++
++int setup_signal_stack_si(unsigned long stack_top, int sig, 
++                        unsigned long handler, void (*restorer)(void), 
++                        struct pt_regs *regs, siginfo_t *info, 
++                        sigset_t *mask)
++{
++      unsigned long start, sc, sigs;
++      void *sip;
++      int sig_size = _NSIG_WORDS * sizeof(unsigned long);
++
++      start = stack_top - signal_frame_si.len - 
++              sc_size(&signal_frame_sc.arch) - sig_size;
++      sip = (void *) (start + signal_frame_si.si_index);
++      sc = start + signal_frame_si.len;
++      sigs = sc + sc_size(&signal_frame_sc.arch);
++      if(copy_sc_to_user((void *) sc, regs->regs.sc, 
++                         &signal_frame_sc.arch) ||
++         copy_to_user((void *) start, signal_frame_si.data,
++                      signal_frame_si.len) ||
++         copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, 
++                      sizeof(sig)) ||
++         copy_siginfo_to_user(sip, info) ||
++         copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
++                      sizeof(sip)) ||
++         copy_to_user((void *) sigs, mask, sig_size) ||
++         copy_restorer(restorer, start, signal_frame_si.sr_index,
++                       signal_frame_si.sr_relative))
++              return(1);
++      
++      PT_REGS_IP(regs) = handler;
++      PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
++      return(0);
++}
++
++int setup_signal_stack_sc(unsigned long stack_top, int sig, 
++                        unsigned long handler, void (*restorer)(void), 
++                        struct pt_regs *regs, sigset_t *mask)
++{
++      int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
++      unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size;
++      void *user_sc = (void *) (start + signal_frame_sc.sc_index);
++
++      sigs = start + signal_frame_sc.len;
++      if(copy_to_user((void *) start, signal_frame_sc.data, 
++                      signal_frame_sc.len) ||
++         copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
++                      sizeof(sig)) ||
++         copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) ||
++         copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
++         copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
++         copy_restorer(restorer, start, signal_frame_sc.sr_index,
++                       signal_frame_sc.sr_relative))
++              return(1);
++
++      PT_REGS_IP(regs) = handler;
++      PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
++
++      set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/gmon_syms.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/module.h"
++
++extern void __bb_init_func(void *);
++EXPORT_SYMBOL(__bb_init_func);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/gprof_syms.c  2003-09-09 16:15:18.000000000 +0400
+@@ -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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/helper.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,146 @@
++/* 
++ * 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 <fcntl.h>
++#include <sched.h>
++#include <sys/signal.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "kern_util.h"
++#include "os.h"
++
++struct helper_data {
++      void (*pre_exec)(void*);
++      void *pre_data;
++      char **argv;
++      int fd;
++};
++
++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;
++
++      if(helper_pause){
++              signal(SIGHUP, helper_hup);
++              pause();
++      }
++      if(data->pre_exec != NULL)
++              (*data->pre_exec)(data->pre_data);
++      execvp(argv[0], argv);
++      printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
++      write(data->fd, &errno, sizeof(errno));
++      _exit(1);
++}
++
++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], err, n;
++
++      if((stack_out != NULL) && (*stack_out != 0))
++              stack = *stack_out;
++      else stack = alloc_stack(0, um_in_interrupt());
++      if(stack == 0) return(-ENOMEM);
++
++      err = os_pipe(fds, 1, 0);
++      if(err){
++              printk("run_helper : pipe failed, errno = %d\n", -err);
++              return(err);
++      }
++      if(fcntl(fds[1], F_SETFD, 1) != 0){
++              printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n",
++                     errno);
++              return(-errno);
++      }
++
++      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);
++              return(-errno);
++      }
++      close(fds[1]);
++      n = read(fds[0], &err, sizeof(err));
++      if(n < 0){
++              printk("run_helper : read on pipe failed, errno = %d\n", 
++                     errno);
++              return(-errno);
++      }
++      else if(n != 0) pid = -err;
++
++      if(stack_out == NULL) free_stack(stack, 0);
++        else *stack_out = stack;
++      return(pid);
++}
++
++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){
++              pid = waitpid(pid, &status, 0);
++              if(pid < 0)
++                      printk("run_helper_thread - wait failed, errno = %d\n",
++                             pid);
++              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;
++
++      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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/initrd_kern.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/blk.h"
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "initrd.h"
++#include "init.h"
++#include "os.h"
++
++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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/initrd_user.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "initrd.h"
++#include "os.h"
++
++int load_initrd(char *filename, void *buf, int size)
++{
++      int fd, n;
++
++      if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){
++              printk("Opening '%s' failed - errno = %d\n", filename, errno);
++              return(-1);
++      }
++      if((n = read(fd, buf, size)) != size){
++              printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
++                     size, filename, n, errno);
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/init_task.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/sched.h"
++#include "linux/version.h"
++#include "asm/uaccess.h"
++#include "asm/pgtable.h"
++#include "user_util.h"
++#include "mem_user.h"
++
++static struct fs_struct init_fs = INIT_FS;
++static struct files_struct init_files = INIT_FILES;
++static struct signal_struct init_signals = INIT_SIGNALS;
++struct mm_struct init_mm = INIT_MM(init_mm);
++
++/*
++ * Initial task structure.
++ *
++ * We need to make sure that this is 16384-byte aligned due to the
++ * way process stacks are handled. This is done by having a special
++ * "init_task" linker map entry..
++ */
++
++union task_union init_task_union 
++__attribute__((__section__(".data.init_task"))) = 
++{ INIT_TASK(init_task_union.task) };
++
++struct task_struct *alloc_task_struct(void){
++      struct task_struct *task;
++
++      task = (struct task_struct *) __get_free_pages(GFP_KERNEL, 2);
++      if(task == NULL) return(NULL);
++      return(task);
++}
++
++void unprotect_stack(unsigned long stack)
++{
++      protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
++}
++
++void free_task_struct(struct task_struct *task)
++{
++      /* free_pages decrements the page counter and only actually frees
++       * the pages if they are now not accessed by anything.
++       */
++      free_pages((unsigned long) task, 2);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/irq.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,813 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
++ *    Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "linux/irq.h"
++#include "linux/kernel_stat.h"
++#include "linux/interrupt.h"
++#include "linux/random.h"
++#include "linux/slab.h"
++#include "linux/file.h"
++#include "linux/proc_fs.h"
++#include "linux/init.h"
++#include "linux/seq_file.h"
++#include "asm/irq.h"
++#include "asm/hw_irq.h"
++#include "asm/hardirq.h"
++#include "asm/atomic.h"
++#include "asm/signal.h"
++#include "asm/system.h"
++#include "asm/errno.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++
++static void register_irq_proc (unsigned int irq);
++
++irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
++        { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
++
++/*
++ * Generic no controller code
++ */
++
++static void enable_none(unsigned int irq) { }
++static unsigned int startup_none(unsigned int irq) { return 0; }
++static void disable_none(unsigned int irq) { }
++static void ack_none(unsigned int irq)
++{
++/*
++ * 'what should we do if we get a hw irq event on an illegal vector'.
++ * each architecture has to answer this themselves, it doesnt deserve
++ * a generic callback i think.
++ */
++#if CONFIG_X86
++      printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
++#ifdef CONFIG_X86_LOCAL_APIC
++      /*
++       * Currently unexpected vectors happen only on SMP and APIC.
++       * We _must_ ack these because every local APIC has only N
++       * irq slots per priority level, and a 'hanging, unacked' IRQ
++       * holds up an irq slot - in excessive cases (when multiple
++       * unexpected vectors occur) that might lock up the APIC
++       * completely.
++       */
++      ack_APIC_irq();
++#endif
++#endif
++}
++
++/* startup is the same as "enable", shutdown is same as "disable" */
++#define shutdown_none disable_none
++#define end_none      enable_none
++
++struct hw_interrupt_type no_irq_type = {
++      "none",
++      startup_none,
++      shutdown_none,
++      enable_none,
++      disable_none,
++      ack_none,
++      end_none
++};
++
++volatile unsigned long irq_err_count;
++
++/*
++ * Generic, controller-independent functions:
++ */
++
++int get_irq_list(char *buf)
++{
++      int i, j;
++      struct irqaction * action;
++      char *p = buf;
++
++      p += sprintf(p, "           ");
++      for (j=0; j<smp_num_cpus; j++)
++              p += sprintf(p, "CPU%d       ",j);
++      *p++ = '\n';
++
++      for (i = 0 ; i < NR_IRQS ; i++) {
++              action = irq_desc[i].action;
++              if (!action) 
++                      continue;
++              p += sprintf(p, "%3d: ",i);
++#ifndef CONFIG_SMP
++              p += sprintf(p, "%10u ", kstat_irqs(i));
++#else
++              for (j = 0; j < smp_num_cpus; j++)
++                      p += sprintf(p, "%10u ",
++                              kstat.irqs[cpu_logical_map(j)][i]);
++#endif
++              p += sprintf(p, " %14s", irq_desc[i].handler->typename);
++              p += sprintf(p, "  %s", action->name);
++
++              for (action=action->next; action; action = action->next)
++                      p += sprintf(p, ", %s", action->name);
++              *p++ = '\n';
++      }
++      p += sprintf(p, "\n");
++#ifdef notdef
++#if CONFIG_SMP
++      p += sprintf(p, "LOC: ");
++      for (j = 0; j < smp_num_cpus; j++)
++              p += sprintf(p, "%10u ",
++                      apic_timer_irqs[cpu_logical_map(j)]);
++      p += sprintf(p, "\n");
++#endif
++#endif
++      p += sprintf(p, "ERR: %10lu\n", irq_err_count);
++      return p - buf;
++}
++
++
++/*
++ * This should really return information about whether
++ * we should do bottom half handling etc. Right now we
++ * end up _always_ checking the bottom half, which is a
++ * waste of time and is not what some drivers would
++ * prefer.
++ */
++int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, 
++                   struct irqaction * action)
++{
++      int status;
++      int cpu = smp_processor_id();
++
++      irq_enter(cpu, irq);
++
++      status = 1;     /* Force the "do bottom halves" bit */
++
++      if (!(action->flags & SA_INTERRUPT))
++              __sti();
++
++      do {
++              status |= action->flags;
++              action->handler(irq, action->dev_id, regs);
++              action = action->next;
++      } while (action);
++      if (status & SA_SAMPLE_RANDOM)
++              add_interrupt_randomness(irq);
++      __cli();
++
++      irq_exit(cpu, irq);
++
++      return status;
++}
++
++/*
++ * Generic enable/disable code: this just calls
++ * down into the PIC-specific version for the actual
++ * hardware disable after having gotten the irq
++ * controller lock. 
++ */
++ 
++/**
++ *    disable_irq_nosync - disable an irq without waiting
++ *    @irq: Interrupt to disable
++ *
++ *    Disable the selected interrupt line. Disables of an interrupt
++ *    stack. Unlike disable_irq(), this function does not ensure existing
++ *    instances of the IRQ handler have completed before returning.
++ *
++ *    This function may be called from IRQ context.
++ */
++ 
++void inline disable_irq_nosync(unsigned int irq)
++{
++      irq_desc_t *desc = irq_desc + irq;
++      unsigned long flags;
++
++      spin_lock_irqsave(&desc->lock, flags);
++      if (!desc->depth++) {
++              desc->status |= IRQ_DISABLED;
++              desc->handler->disable(irq);
++      }
++      spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++/**
++ *    disable_irq - disable an irq and wait for completion
++ *    @irq: Interrupt to disable
++ *
++ *    Disable the selected interrupt line. Disables of an interrupt
++ *    stack. That is for two disables you need two enables. This
++ *    function waits for any pending IRQ handlers for this interrupt
++ *    to complete before returning. If you use this function while
++ *    holding a resource the IRQ handler may need you will deadlock.
++ *
++ *    This function may be called - with care - from IRQ context.
++ */
++ 
++void disable_irq(unsigned int irq)
++{
++      disable_irq_nosync(irq);
++
++      if (!local_irq_count(smp_processor_id())) {
++              do {
++                      barrier();
++              } while (irq_desc[irq].status & IRQ_INPROGRESS);
++      }
++}
++
++/**
++ *    enable_irq - enable interrupt handling on an irq
++ *    @irq: Interrupt to enable
++ *
++ *    Re-enables the processing of interrupts on this IRQ line
++ *    providing no disable_irq calls are now in effect.
++ *
++ *    This function may be called from IRQ context.
++ */
++ 
++void enable_irq(unsigned int irq)
++{
++      irq_desc_t *desc = irq_desc + irq;
++      unsigned long flags;
++
++      spin_lock_irqsave(&desc->lock, flags);
++      switch (desc->depth) {
++      case 1: {
++              unsigned int status = desc->status & ~IRQ_DISABLED;
++              desc->status = status;
++              if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
++                      desc->status = status | IRQ_REPLAY;
++                      hw_resend_irq(desc->handler,irq);
++              }
++              desc->handler->enable(irq);
++              /* fall-through */
++      }
++      default:
++              desc->depth--;
++              break;
++      case 0:
++              printk(KERN_ERR "enable_irq() unbalanced from %p\n",
++                     __builtin_return_address(0));
++      }
++      spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++/*
++ * do_IRQ handles all normal device IRQ's (the special
++ * SMP cross-CPU interrupts have their own specific
++ * handlers).
++ */
++unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
++{     
++      /* 
++       * 0 return value means that this irq is already being
++       * handled by some other CPU. (or is disabled)
++       */
++      int cpu = smp_processor_id();
++      irq_desc_t *desc = irq_desc + irq;
++      struct irqaction * action;
++      unsigned int status;
++
++      kstat.irqs[cpu][irq]++;
++      spin_lock(&desc->lock);
++      desc->handler->ack(irq);
++      /*
++         REPLAY is when Linux resends an IRQ that was dropped earlier
++         WAITING is used by probe to mark irqs that are being tested
++         */
++      status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
++      status |= IRQ_PENDING; /* we _want_ to handle it */
++
++      /*
++       * If the IRQ is disabled for whatever reason, we cannot
++       * use the action we have.
++       */
++      action = NULL;
++      if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
++              action = desc->action;
++              status &= ~IRQ_PENDING; /* we commit to handling */
++              status |= IRQ_INPROGRESS; /* we are handling it */
++      }
++      desc->status = status;
++
++      /*
++       * If there is no IRQ handler or it was disabled, exit early.
++         Since we set PENDING, if another processor is handling
++         a different instance of this same irq, the other processor
++         will take care of it.
++       */
++      if (!action)
++              goto out;
++
++      /*
++       * Edge triggered interrupts need to remember
++       * pending events.
++       * This applies to any hw interrupts that allow a second
++       * instance of the same irq to arrive while we are in do_IRQ
++       * or in the handler. But the code here only handles the _second_
++       * instance of the irq, not the third or fourth. So it is mostly
++       * useful for irq hardware that does not mask cleanly in an
++       * SMP environment.
++       */
++      for (;;) {
++              spin_unlock(&desc->lock);
++              handle_IRQ_event(irq, (struct pt_regs *) regs, action);
++              spin_lock(&desc->lock);
++              
++              if (!(desc->status & IRQ_PENDING))
++                      break;
++              desc->status &= ~IRQ_PENDING;
++      }
++      desc->status &= ~IRQ_INPROGRESS;
++out:
++      /*
++       * The ->end() handler has to deal with interrupts which got
++       * disabled while the handler was running.
++       */
++      desc->handler->end(irq);
++      spin_unlock(&desc->lock);
++
++      if (softirq_pending(cpu))
++              do_softirq();
++      return 1;
++}
++
++/**
++ *    request_irq - allocate an interrupt line
++ *    @irq: Interrupt line to allocate
++ *    @handler: Function to be called when the IRQ occurs
++ *    @irqflags: Interrupt type flags
++ *    @devname: An ascii name for the claiming device
++ *    @dev_id: A cookie passed back to the handler function
++ *
++ *    This call allocates interrupt resources and enables the
++ *    interrupt line and IRQ handling. From the point this
++ *    call is made your handler function may be invoked. Since
++ *    your handler function must clear any interrupt the board 
++ *    raises, you must take care both to initialise your hardware
++ *    and to set up the interrupt handler in the right order.
++ *
++ *    Dev_id must be globally unique. Normally the address of the
++ *    device data structure is used as the cookie. Since the handler
++ *    receives this value it makes sense to use it.
++ *
++ *    If your interrupt is shared you must pass a non NULL dev_id
++ *    as this is required when freeing the interrupt.
++ *
++ *    Flags:
++ *
++ *    SA_SHIRQ                Interrupt is shared
++ *
++ *    SA_INTERRUPT            Disable local interrupts while processing
++ *
++ *    SA_SAMPLE_RANDOM        The interrupt can be used for entropy
++ *
++ */
++ 
++int request_irq(unsigned int irq,
++              void (*handler)(int, void *, struct pt_regs *),
++              unsigned long irqflags, 
++              const char * devname,
++              void *dev_id)
++{
++      int retval;
++      struct irqaction * action;
++
++#if 1
++      /*
++       * Sanity-check: shared interrupts should REALLY pass in
++       * a real dev-ID, otherwise we'll have trouble later trying
++       * to figure out which interrupt is which (messes up the
++       * interrupt freeing logic etc).
++       */
++      if (irqflags & SA_SHIRQ) {
++              if (!dev_id)
++                      printk(KERN_ERR "Bad boy: %s (at 0x%x) called us "
++                             "without a dev_id!\n", devname, (&irq)[-1]);
++      }
++#endif
++
++      if (irq >= NR_IRQS)
++              return -EINVAL;
++      if (!handler)
++              return -EINVAL;
++
++      action = (struct irqaction *)
++                      kmalloc(sizeof(struct irqaction), GFP_KERNEL);
++      if (!action)
++              return -ENOMEM;
++
++      action->handler = handler;
++      action->flags = irqflags;
++      action->mask = 0;
++      action->name = devname;
++      action->next = NULL;
++      action->dev_id = dev_id;
++
++      retval = setup_irq(irq, action);
++      if (retval)
++              kfree(action);
++      return retval;
++}
++
++int um_request_irq(unsigned int irq, int fd, int type,
++                 void (*handler)(int, void *, struct pt_regs *),
++                 unsigned long irqflags, const char * devname,
++                 void *dev_id)
++{
++      int retval;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if(retval) return(retval);
++      return(activate_fd(irq, fd, type, dev_id));
++}
++
++/* this was setup_x86_irq but it seems pretty generic */
++int setup_irq(unsigned int irq, struct irqaction * new)
++{
++      int shared = 0;
++      unsigned long flags;
++      struct irqaction *old, **p;
++      irq_desc_t *desc = irq_desc + irq;
++
++      /*
++       * Some drivers like serial.c use request_irq() heavily,
++       * so we have to be careful not to interfere with a
++       * running system.
++       */
++      if (new->flags & SA_SAMPLE_RANDOM) {
++              /*
++               * This function might sleep, we want to call it first,
++               * outside of the atomic block.
++               * Yes, this might clear the entropy pool if the wrong
++               * driver is attempted to be loaded, without actually
++               * installing a new handler, but is this really a problem,
++               * only the sysadmin is able to do this.
++               */
++              rand_initialize_irq(irq);
++      }
++
++      /*
++       * The following block of code has to be executed atomically
++       */
++      spin_lock_irqsave(&desc->lock,flags);
++      p = &desc->action;
++      if ((old = *p) != NULL) {
++              /* Can't share interrupts unless both agree to */
++              if (!(old->flags & new->flags & SA_SHIRQ)) {
++                      spin_unlock_irqrestore(&desc->lock,flags);
++                      return -EBUSY;
++              }
++
++              /* add new interrupt at end of irq queue */
++              do {
++                      p = &old->next;
++                      old = *p;
++              } while (old);
++              shared = 1;
++      }
++
++      *p = new;
++
++      if (!shared) {
++              desc->depth = 0;
++              desc->status &= ~IRQ_DISABLED;
++              desc->handler->startup(irq);
++      }
++      spin_unlock_irqrestore(&desc->lock,flags);
++
++      register_irq_proc(irq);
++      return 0;
++}
++
++/**
++ *    free_irq - free an interrupt
++ *    @irq: Interrupt line to free
++ *    @dev_id: Device identity to free
++ *
++ *    Remove an interrupt handler. The handler is removed and if the
++ *    interrupt line is no longer in use by any driver it is disabled.
++ *    On a shared IRQ the caller must ensure the interrupt is disabled
++ *    on the card it drives before calling this function. The function
++ *    does not return until any executing interrupts for this IRQ
++ *    have completed.
++ *
++ *    This function may be called from interrupt context. 
++ *
++ *    Bugs: Attempting to free an irq in a handler for the same irq hangs
++ *          the machine.
++ */
++ 
++void free_irq(unsigned int irq, void *dev_id)
++{
++      irq_desc_t *desc;
++      struct irqaction **p;
++      unsigned long flags;
++
++      if (irq >= NR_IRQS)
++              return;
++
++      desc = irq_desc + irq;
++      spin_lock_irqsave(&desc->lock,flags);
++      p = &desc->action;
++      for (;;) {
++              struct irqaction * action = *p;
++              if (action) {
++                      struct irqaction **pp = p;
++                      p = &action->next;
++                      if (action->dev_id != dev_id)
++                              continue;
++
++                      /* Found it - now remove it from the list of entries */
++                      *pp = action->next;
++                      if (!desc->action) {
++                              desc->status |= IRQ_DISABLED;
++                              desc->handler->shutdown(irq);
++                      }
++                      free_irq_by_irq_and_dev(irq, dev_id);
++                      spin_unlock_irqrestore(&desc->lock,flags);
++
++#ifdef CONFIG_SMP
++                      /* Wait to make sure it's not being used on another CPU */
++                      while (desc->status & IRQ_INPROGRESS)
++                              barrier();
++#endif
++                      kfree(action);
++                      return;
++              }
++              printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
++              spin_unlock_irqrestore(&desc->lock,flags);
++              return;
++      }
++}
++
++static struct proc_dir_entry * root_irq_dir;
++static struct proc_dir_entry * irq_dir [NR_IRQS];
++static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
++
++static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
++
++#define HEX_DIGITS 8
++
++static int irq_affinity_read_proc (char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++      if (count < HEX_DIGITS+1)
++              return -EINVAL;
++      return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
++}
++
++static unsigned int parse_hex_value (const char *buffer,
++              unsigned long count, unsigned long *ret)
++{
++      unsigned char hexnum [HEX_DIGITS];
++      unsigned long value;
++      int i;
++
++      if (!count)
++              return -EINVAL;
++      if (count > HEX_DIGITS)
++              count = HEX_DIGITS;
++      if (copy_from_user(hexnum, buffer, count))
++              return -EFAULT;
++
++      /*
++       * Parse the first 8 characters as a hex string, any non-hex char
++       * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
++       */
++      value = 0;
++
++      for (i = 0; i < count; i++) {
++              unsigned int c = hexnum[i];
++
++              switch (c) {
++                      case '0' ... '9': c -= '0'; break;
++                      case 'a' ... 'f': c -= 'a'-10; break;
++                      case 'A' ... 'F': c -= 'A'-10; break;
++              default:
++                      goto out;
++              }
++              value = (value << 4) | c;
++      }
++out:
++      *ret = value;
++      return 0;
++}
++
++static int irq_affinity_write_proc (struct file *file, const char *buffer,
++                                      unsigned long count, void *data)
++{
++      int irq = (long) data, full_count = count, err;
++      unsigned long new_value;
++
++      if (!irq_desc[irq].handler->set_affinity)
++              return -EIO;
++
++      err = parse_hex_value(buffer, count, &new_value);
++
++#if CONFIG_SMP
++      /*
++       * Do not allow disabling IRQs completely - it's a too easy
++       * way to make the system unusable accidentally :-) At least
++       * one online CPU still has to be targeted.
++       */
++      if (!(new_value & cpu_online_map))
++              return -EINVAL;
++#endif
++
++      irq_affinity[irq] = new_value;
++      irq_desc[irq].handler->set_affinity(irq, new_value);
++
++      return full_count;
++}
++
++static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++      unsigned long *mask = (unsigned long *) data;
++      if (count < HEX_DIGITS+1)
++              return -EINVAL;
++      return sprintf (page, "%08lx\n", *mask);
++}
++
++static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
++                                      unsigned long count, void *data)
++{
++      unsigned long *mask = (unsigned long *) data, full_count = count, err;
++      unsigned long new_value;
++
++      err = parse_hex_value(buffer, count, &new_value);
++      if (err)
++              return err;
++
++      *mask = new_value;
++      return full_count;
++}
++
++#define MAX_NAMELEN 10
++
++static void register_irq_proc (unsigned int irq)
++{
++      struct proc_dir_entry *entry;
++      char name [MAX_NAMELEN];
++
++      if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
++          irq_dir[irq])
++              return;
++
++      memset(name, 0, MAX_NAMELEN);
++      sprintf(name, "%d", irq);
++
++      /* create /proc/irq/1234 */
++      irq_dir[irq] = proc_mkdir(name, root_irq_dir);
++
++      /* create /proc/irq/1234/smp_affinity */
++      entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
++
++      entry->nlink = 1;
++      entry->data = (void *)(long)irq;
++      entry->read_proc = irq_affinity_read_proc;
++      entry->write_proc = irq_affinity_write_proc;
++
++      smp_affinity_entry[irq] = entry;
++}
++
++unsigned long prof_cpu_mask = -1;
++
++void __init init_irq_proc (void)
++{
++      struct proc_dir_entry *entry;
++      int i;
++
++      /* create /proc/irq */
++      root_irq_dir = proc_mkdir("irq", 0);
++
++      /* create /proc/irq/prof_cpu_mask */
++      entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
++
++      entry->nlink = 1;
++      entry->data = (void *)&prof_cpu_mask;
++      entry->read_proc = prof_cpu_mask_read_proc;
++      entry->write_proc = prof_cpu_mask_write_proc;
++
++      /*
++       * Create entries for all existing IRQs.
++       */
++      for (i = 0; i < NR_IRQS; i++)
++              register_irq_proc(i);
++}
++
++unsigned long probe_irq_on(void)
++{
++      return(0);
++}
++
++int probe_irq_off(unsigned long val)
++{
++      return(0);
++}
++
++static unsigned int startup_SIGIO_irq(unsigned int irq)
++{
++      return(0);
++}
++
++static void shutdown_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGIO(unsigned int irq)
++{
++}
++
++static void end_SIGIO_irq(unsigned int irq)
++{
++}
++
++static unsigned int startup_SIGVTALRM_irq(unsigned int irq)
++{
++      return(0);
++}
++
++static void shutdown_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGVTALRM(unsigned int irq)
++{
++}
++
++static void end_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static struct hw_interrupt_type SIGIO_irq_type = {
++      "SIGIO",
++      startup_SIGIO_irq,
++      shutdown_SIGIO_irq,
++      enable_SIGIO_irq,
++      disable_SIGIO_irq,
++      mask_and_ack_SIGIO,
++      end_SIGIO_irq,
++      NULL
++};
++
++static struct hw_interrupt_type SIGVTALRM_irq_type = {
++      "SIGVTALRM",
++      startup_SIGVTALRM_irq,
++      shutdown_SIGVTALRM_irq,
++      enable_SIGVTALRM_irq,
++      disable_SIGVTALRM_irq,
++      mask_and_ack_SIGVTALRM,
++      end_SIGVTALRM_irq,
++      NULL
++};
++
++void __init init_IRQ(void)
++{
++      int i;
++
++      irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
++      irq_desc[TIMER_IRQ].action = 0;
++      irq_desc[TIMER_IRQ].depth = 1;
++      irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
++      enable_irq(TIMER_IRQ);
++      for(i=1;i<NR_IRQS;i++){
++              irq_desc[i].status = IRQ_DISABLED;
++              irq_desc[i].action = 0;
++              irq_desc[i].depth = 1;
++              irq_desc[i].handler = &SIGIO_irq_type;
++              enable_irq(i);
++      }
++      init_irq_signals(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/irq_user.c    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,357 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <string.h>
++#include <sys/poll.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++#include "sigio.h"
++#include "irq_user.h"
++#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, struct uml_pt_regs *regs)
++{
++      struct irq_fd *irq_fd, *next;
++      int i, n;
++
++      if(smp_sigio_handler()) return;
++      while(1){
++              if((n = poll(pollfds, pollfds_num, 0)) < 0){
++                      if(errno == EINTR) continue;
++                      printk("sigio_handler : poll returned %d, "
++                             "errno = %d\n", n, errno);
++                      break;
++              }
++              if(n == 0) break;
++
++              irq_fd = active_fds;
++              for(i = 0; i < pollfds_num; i++){
++                      if(pollfds[i].revents != 0){
++                              irq_fd->current_events = pollfds[i].revents;
++                              pollfds[i].events = 0;
++                      }
++                      irq_fd = irq_fd->next;
++              }
++
++              for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
++                      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);
++                      }
++              }
++      }
++}
++
++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 irq_fd *new_fd;
++      int pid, retval, events, err;
++
++      for(new_fd = active_fds;new_fd;new_fd = new_fd->next){
++              if((new_fd->fd == fd) && (new_fd->type == type)){
++                      printk("Registering fd %d twice\n", fd);
++                      printk("Irqs : %d, %d\n", new_fd->irq, irq);
++                      printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id);
++                      return(-EIO);
++              }
++      }
++      pid = cpu_tasks[0].pid;
++      if((retval = os_set_fd_async(fd, pid)) != 0)
++              return(retval);
++      new_fd = um_kmalloc(sizeof(*new_fd));
++      err = -ENOMEM;
++      if(new_fd == NULL) return(err);
++      pollfds_num++;
++      if(pollfds_num > pollfds_size){
++              struct pollfd *tmp_pfd;
++
++              tmp_pfd = um_kmalloc(pollfds_num * sizeof(pollfds[0]));
++              if(tmp_pfd == NULL){
++                      pollfds_num--;
++                      goto out_irq;
++              }
++              if(pollfds != NULL){
++                      memcpy(tmp_pfd, pollfds,
++                             sizeof(pollfds[0]) * pollfds_size);
++                      kfree(pollfds);
++              }
++              pollfds = tmp_pfd;
++              pollfds_size = pollfds_num;
++      }
++
++      if(type == IRQ_READ) events = POLLIN | POLLPRI;
++      else events = POLLOUT;
++      *new_fd = ((struct irq_fd) { next :             NULL,
++                                   id :               dev_id,
++                                   fd :               fd,
++                                   type :             type,
++                                   irq :              irq,
++                                   pid :              pid,
++                                   events :           events,
++                                   current_events:    0,
++                                   freed :            0  } );
++
++      *last_irq_ptr = new_fd;
++      last_irq_ptr = &new_fd->next;
++
++      if(type == IRQ_WRITE) events = 0;
++
++      pollfds[pollfds_num - 1] = ((struct pollfd) { fd :      fd,
++                                                    events :  events,
++                                                    revents : 0 });
++
++      maybe_sigio_broken(fd, type);
++
++      return(0);
++
++ out_irq:
++      kfree(new_fd);
++      return(err);
++}
++
++static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
++{
++      struct irq_fd **prev;
++      int i = 0;
++
++      prev = &active_fds;
++      while(*prev != NULL){
++              if((*test)(*prev, arg)){
++                      struct irq_fd *old_fd = *prev;
++                      if(pollfds[i].fd != (*prev)->fd){
++                              printk("free_irq_by_cb - mismatch between "
++                                     "active_fds and pollfds, fd %d vs %d\n",
++                                     (*prev)->fd, pollfds[i].fd);
++                              return;
++                      }
++                      memcpy(&pollfds[i], &pollfds[i + 1],
++                             (pollfds_num - i - 1) * sizeof(pollfds[0]));
++                      pollfds_num--;
++                      if(last_irq_ptr == &old_fd->next) 
++                              last_irq_ptr = prev;
++                      *prev = (*prev)->next;
++                      if(old_fd->type == IRQ_WRITE) 
++                              ignore_sigio_fd(old_fd->fd);
++                      kfree(old_fd);
++                      continue;
++              }
++              prev = &(*prev)->next;
++              i++;
++      }
++}
++
++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(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);
++              return(NULL);
++      }
++      if(pollfds[i].fd != fd){
++              printk("find_irq_by_fd - mismatch between active_fds and "
++                     "pollfds, fd %d vs %d, need %d\n", irq->fd, 
++                     pollfds[i].fd, fd);
++              return(NULL);
++      }
++      *index_out = i;
++      return(irq);
++}
++
++void free_irq_later(int irq, void *dev_id)
++{
++      struct irq_fd *irq_fd;
++
++      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);
++              return;
++      }
++      irq_fd->freed = 1;
++}
++
++void reactivate_fd(int fd, int irqnum)
++{
++      struct irq_fd *irq;
++      int i;
++
++      irq = find_irq_by_fd(fd, irqnum, &i);
++      if(irq == NULL) return;
++      pollfds[i].events = irq->events;
++      maybe_sigio_broken(fd, irq->type);
++}
++
++void deactivate_fd(int fd, int irqnum)
++{
++      struct irq_fd *irq;
++      int i;
++
++      irq = find_irq_by_fd(fd, irqnum, &i);
++      if(irq == NULL) return;
++      pollfds[i].events = 0;
++}
++
++void forward_ipi(int fd, int pid)
++{
++      if(fcntl(fd, F_SETOWN, pid) < 0){
++              int save_errno = errno;
++              if(fcntl(fd, F_GETOWN, 0) != pid){
++                      printk("forward_ipi: F_SETOWN failed, fd = %d, "
++                             "me = %d, target = %d, errno = %d\n", fd, 
++                             os_getpid(), pid, save_errno);
++              }
++      }
++}
++
++void forward_interrupts(int pid)
++{
++      struct irq_fd *irq;
++
++      for(irq=active_fds;irq != NULL;irq = irq->next){
++              if(fcntl(irq->fd, F_SETOWN, pid) < 0){
++                      int save_errno = errno;
++                      if(fcntl(irq->fd, F_GETOWN, 0) != pid){
++                              /* XXX Just remove the irq rather than
++                               * print out an infinite stream of these
++                               */
++                              printk("Failed to forward %d to pid %d, "
++                                     "errno = %d\n", irq->fd, pid, 
++                                     save_errno);
++                      }
++              }
++              irq->pid = pid;
++      }
++}
++
++void init_irq_signals(int on_sigstack)
++{
++      __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_NODEFER | SA_RESTART, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      signal(SIGWINCH, SIG_IGN);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/ksyms.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,51 @@
++#include "linux/module.h"
++#include "linux/string.h"
++#include "asm/current.h"
++#include "asm/delay.h"
++#include "asm/processor.h"
++#include "asm/unistd.h"
++#include "asm/pgalloc.h"
++#include "asm/page.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "helper.h"
++
++EXPORT_SYMBOL(stop);
++EXPORT_SYMBOL(strtok);
++EXPORT_SYMBOL(uml_physmem);
++EXPORT_SYMBOL(set_signals);
++EXPORT_SYMBOL(__const_udelay);
++EXPORT_SYMBOL(task_size);
++EXPORT_SYMBOL(__do_copy_from_user);
++EXPORT_SYMBOL(__do_strncpy_from_user);
++EXPORT_SYMBOL(__do_strnlen_user); 
++EXPORT_SYMBOL(flush_tlb_range);
++EXPORT_SYMBOL(__do_clear_user);
++EXPORT_SYMBOL(honeypot);
++EXPORT_SYMBOL(host_task_size);
++EXPORT_SYMBOL(arch_validate);
++
++EXPORT_SYMBOL(region_va);
++EXPORT_SYMBOL(region_pa);
++EXPORT_SYMBOL(phys_mem_map);
++EXPORT_SYMBOL(page_mem_map);
++
++EXPORT_SYMBOL(os_open_file);
++EXPORT_SYMBOL(os_read_file);
++EXPORT_SYMBOL(os_write_file);
++EXPORT_SYMBOL(os_seek_file);
++EXPORT_SYMBOL(os_pipe);
++EXPORT_SYMBOL(helper_wait);
++EXPORT_SYMBOL(os_shutdown_socket);
++EXPORT_SYMBOL(os_connect_socket);
++EXPORT_SYMBOL(run_helper);
++EXPORT_SYMBOL(tracing_pid);
++EXPORT_SYMBOL(kernel_thread);
++EXPORT_SYMBOL(start_thread);
++EXPORT_SYMBOL(dump_thread);
++
++/* This is here because UML expands open to sys_open, not to a system
++ * call instruction.
++ */
++
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/Makefile      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,84 @@
++O_TARGET = um.o
++
++obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \
++      helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
++      process.o process_kern.o ptrace.o reboot.o resource.o setup.o \
++      sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
++      syscall_kern.o syscall_user.o sysrq.o sys_call_table.o time.o \
++      time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
++      umid.o user_syms.o user_util.o
++
++ifeq ($(CONFIG_BLK_DEV_INITRD), y)
++  obj-y += initrd_kern.o initrd_user.o
++endif
++
++# user_syms.o not included here because Rules.make has its own ideas about
++# building anything in export-objs
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) config.o process.o time.o umid.o \
++      user_util.o helper.o
++
++export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o
++
++UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
++UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
++
++ifeq ($(CONFIG_MODULES), y)
++  DMODULES = -D__CONFIG_MODULES__
++endif
++
++ifeq ($(CONFIG_MODVERSIONS), y)
++  DMODVERSIONS = -D__CONFIG_MODVERSIONS__
++endif
++
++ifeq ($(CONFIG_GPROF), y)
++    obj-y += gprof_syms.o
++    export-objs += gprof_syms.o
++endif
++
++ifeq ($(CONFIG_GCOV), y)
++    obj-y += gmon_syms.o
++    export-objs += gmon_syms.o
++endif
++
++ifeq ($(CONFIG_TTY_LOG), y)
++    obj-y += tty_log.o
++    USER_OBJS += tty_log.o
++endif
++
++CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS)  \
++      -I../include -I/usr/include
++
++CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
++
++include $(TOPDIR)/Rules.make
++
++$(O_TARGET) : unmap_fin.o
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++unmap.o: unmap.c
++      $(CC) $(UNMAP_CFLAGS) -c -o $@ $<
++
++frame.o: frame.c
++      $(CC) $(CFLAGS_$@) -c -o $@ $<
++
++unmap_fin.o : unmap.o
++      ld -r -o $@ $< -lc -L/usr/lib
++
++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
++
++config.c : config.c.in $(TOPDIR)/.config
++      $(PERL) -e $(QUOTE) < config.c.in > $@
++
++clean:
++      $(RM) config.c
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper: clean
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/mem.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,605 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/types.h"
++#include "linux/mm.h"
++#include "linux/fs.h"
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/swap.h"
++#include "linux/slab.h"
++#include "linux/vmalloc.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/bitops.h"
++#include "asm/uaccess.h"
++#include "asm/tlb.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "mem.h"
++#include "kern.h"
++#include "init.h"
++
++unsigned long high_physmem;
++
++unsigned long low_physmem;
++
++unsigned long vm_start;
++
++unsigned long vm_end;
++
++pgd_t swapper_pg_dir[1024];
++
++unsigned long *empty_zero_page = NULL;
++
++unsigned long *empty_bad_page = NULL;
++
++const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
++
++static unsigned long totalram_pages = 0;
++
++extern char __init_begin, __init_end;
++extern long physmem_size;
++
++#ifdef CONFIG_SMP
++mmu_gather_t mmu_gathers[NR_CPUS];
++#endif
++
++int kmalloc_ok = 0;
++
++#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0))
++struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
++#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
++
++static unsigned long brk_end;
++
++static void map_cb(void *unused)
++{
++      map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
++}
++
++void unmap_physmem(void)
++{
++      unmap((void *) brk_end, uml_reserved - brk_end);
++}
++
++extern char __binary_start;
++
++void mem_init(void)
++{
++      unsigned long start;
++
++      max_mapnr = num_physpages = max_low_pfn;
++
++        /* 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) ROUND_UP(sbrk(0));
++      map_cb(NULL);
++      tracing_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;
++      if(uml_physmem != start){
++              map(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();
++      printk(KERN_INFO "Memory: %luk available\n", 
++             (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
++      kmalloc_ok = 1;
++}
++
++void paging_init(void)
++{
++      struct mem_region *region;
++      unsigned long zones_size[MAX_NR_ZONES], start, end;
++      int i, index;
++
++      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] = (high_physmem >> PAGE_SHIFT) - 
++              (uml_physmem >> PAGE_SHIFT);
++      free_area_init(zones_size);
++      start = phys_region_index(__pa(uml_physmem));
++      end = phys_region_index(__pa(high_physmem - 1));
++      for(i = start; i <= end; i++){
++              region = regions[i];
++              index = (region->start - uml_physmem) / PAGE_SIZE;
++              region->mem_map = &mem_map[index];
++              if(i > start) free_bootmem(__pa(region->start), region->len);
++      }
++}
++
++static int meminfo_22 = 0;
++
++static int meminfo_compat(char *str)
++{
++      meminfo_22 = 1;
++      return(1);
++}
++
++__setup("22_meminfo", meminfo_compat);
++
++void si_meminfo(struct sysinfo *val)
++{
++      val->totalram = totalram_pages;
++      val->sharedram = 0;
++      val->freeram = nr_free_pages();
++      val->bufferram = atomic_read(&buffermem_pages);
++      val->totalhigh = 0;
++      val->freehigh = 0;
++      val->mem_unit = PAGE_SIZE;
++      if(meminfo_22){
++              val->freeram <<= PAGE_SHIFT;
++              val->bufferram <<= PAGE_SHIFT;
++              val->totalram <<= PAGE_SHIFT;
++              val->sharedram <<= PAGE_SHIFT;
++      }
++}
++
++pte_t __bad_page(void)
++{
++      clear_page(empty_bad_page);
++        return pte_mkdirty(mk_pte((struct page *) empty_bad_page, 
++                                PAGE_SHARED));
++}
++
++/* This can't do anything because nothing in the kernel image can be freed
++ * since it's not in kernel physical memory.
++ */
++
++void free_initmem(void)
++{
++}
++
++#ifdef CONFIG_BLK_DEV_INITRD
++
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++      if (start < end)
++              printk ("Freeing initrd memory: %ldk freed\n", 
++                      (end - start) >> 10);
++      for (; start < end; start += PAGE_SIZE) {
++              ClearPageReserved(virt_to_page(start));
++              set_page_count(virt_to_page(start), 1);
++              free_page(start);
++              totalram_pages++;
++      }
++}
++      
++#endif
++
++int do_check_pgt_cache(int low, int high)
++{
++        int freed = 0;
++        if(pgtable_cache_size > high) {
++                do {
++                        if (pgd_quicklist) {
++                                free_pgd_slow(get_pgd_fast());
++                                freed++;
++                        }
++                        if (pmd_quicklist) {
++                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
++                                freed++;
++                        }
++                        if (pte_quicklist) {
++                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
++                                freed++;
++                        }
++                } while(pgtable_cache_size > low);
++        }
++        return freed;
++}
++
++void show_mem(void)
++{
++        int i, total = 0, reserved = 0;
++        int shared = 0, cached = 0;
++        int highmem = 0;
++
++        printk("Mem-info:\n");
++        show_free_areas();
++        printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++        i = max_mapnr;
++        while(i-- > 0) {
++                total++;
++                if(PageHighMem(mem_map + i))
++                        highmem++;
++                if(PageReserved(mem_map + i))
++                        reserved++;
++                else if(PageSwapCache(mem_map + i))
++                        cached++;
++                else if(page_count(mem_map + i))
++                        shared += page_count(mem_map + i) - 1;
++        }
++        printk("%d pages of RAM\n", total);
++        printk("%d pages of HIGHMEM\n", highmem);
++        printk("%d reserved pages\n", reserved);
++        printk("%d pages shared\n", shared);
++        printk("%d pages swap cached\n", cached);
++        printk("%ld pages in page table cache\n", pgtable_cache_size);
++        show_buffers();
++}
++
++unsigned long kmem_top = 0;
++
++unsigned long get_kmem_end(void)
++{
++      if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM;
++      return(kmem_top);
++}
++
++void set_kmem_end(unsigned long new)
++{
++      kmem_top = new;
++}
++
++static int __init uml_mem_setup(char *line, int *add)
++{
++      char *retptr;
++      physmem_size = memparse(line,&retptr);
++      return 0;
++}
++__uml_setup("mem=", uml_mem_setup,
++"mem=<Amount of desired ram>\n"
++"    This controls how much \"physical\" memory the kernel allocates\n"
++"    for the system. The size is specified as a number followed by\n"
++"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
++"    This is not related to the amount of memory in the physical\n"
++"    machine. It can be more, and the excess, if it's ever used, will\n"
++"    just be swapped out.\n        Example: mem=64M\n\n"
++);
++
++struct page *arch_validate(struct page *page, int mask, int order)
++{
++      unsigned long addr, zero = 0;
++      int i;
++
++ again:
++      if(page == NULL) return(page);
++      addr = (unsigned long) page_address(page);
++      for(i = 0; i < (1 << order); i++){
++              current->thread.fault_addr = (void *) addr;
++              if(__do_copy_to_user((void *) addr, &zero, 
++                                   sizeof(zero),
++                                   &current->thread.fault_addr,
++                                   &current->thread.fault_catcher)){
++                      if(!(mask & __GFP_WAIT)) return(NULL);
++                      else break;
++              }
++              addr += PAGE_SIZE;
++      }
++      if(i == (1 << order)) return(page);
++      page = _alloc_pages(mask, order);
++      goto again;
++}
++
++static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);
++
++static struct vm_reserved head = {
++      list :          LIST_HEAD_INIT(head.list),
++      start :         0,
++      end :           0xffffffff
++};
++
++static struct vm_reserved tail = {
++      list :          LIST_HEAD_INIT(tail.list),
++      start :         0,
++      end :           0xffffffff
++};
++
++void set_usable_vm(unsigned long start, unsigned long end)
++{
++      list_add(&head.list, &vm_reserved);
++      list_add(&tail.list, &head.list);
++      head.end = start;
++      tail.start = end;
++}
++
++int reserve_vm(unsigned long start, unsigned long end, void *e)
++             
++{
++      struct vm_reserved *entry = e, *reserved, *prev;
++      struct list_head *ele;
++
++      list_for_each(ele, &vm_reserved){
++              reserved = list_entry(ele, struct vm_reserved, list);
++              if(reserved->start >= end) goto found;
++      }
++      panic("Reserved vm out of range");
++ found:
++      prev = list_entry(ele->prev, struct vm_reserved, list);
++      if(prev->end > start)
++              panic("Can't reserve vm");
++      if(entry == NULL)
++              entry = kmalloc(sizeof(*entry), GFP_KERNEL);
++      if(entry == NULL){
++              printk("reserve_vm : Failed to allocate entry\n");
++              return(-ENOMEM);
++      }
++      *entry = ((struct vm_reserved) 
++              { list :        LIST_HEAD_INIT(entry->list),
++                start :       start,
++                end :         end });
++      list_add(&entry->list, &prev->list);
++      return(0);
++}
++
++unsigned long get_vm(unsigned long len)
++{
++      struct vm_reserved *this, *next;
++      struct list_head *ele;
++      unsigned long start;
++      int err;
++      
++      list_for_each(ele, &vm_reserved){
++              this = list_entry(ele, struct vm_reserved, list);
++              next = list_entry(ele->next, struct vm_reserved, list);
++              if((this->start < next->start) && 
++                 (this->end + len + PAGE_SIZE <= next->start))
++                      goto found;
++      }
++      return(0);
++ found:
++      start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE;
++      err = reserve_vm(start, start + len, NULL);
++      if(err) return(0);
++      return(start);
++}
++
++int nregions(void)
++{
++      return(NREGIONS);
++}
++
++int init_maps(struct mem_region *region)
++{
++      struct page *p, *map;
++      int i, n;
++
++      if(region == &physmem_region){
++              region->mem_map = mem_map;
++              return(0);
++      }
++      else if(region->mem_map != NULL) return(0);
++
++      n = region->len >> PAGE_SHIFT;
++      map = kmalloc(n * sizeof(struct page), GFP_KERNEL);
++      if(map == NULL) map = vmalloc(n * sizeof(struct page));
++      if(map == NULL)
++              return(-ENOMEM);
++      for(i = 0; i < n; i++){
++              p = &map[i];
++              set_page_count(p, 0);
++              SetPageReserved(p);
++              INIT_LIST_HEAD(&p->list);
++      }
++      region->mem_map = map;
++      return(0);
++}
++
++void setup_range(int fd, char *driver, unsigned long start, 
++               unsigned long len, struct mem_region *region, void *reserved)
++{
++      int i, incr;
++
++      i = 0;
++      do {
++              for(; i < NREGIONS; i++){
++                      if(regions[i] == NULL) break;           
++              }
++              if(i == NREGIONS){
++                      printk("setup_range : no free regions\n");
++                      return;
++              }
++              setup_one_range(i, fd, driver, start, len, region);
++              region = regions[i];
++              if(setup_region(region, reserved)){
++                      kfree(region);
++                      regions[i] = NULL;
++                      return;
++              }
++              incr = min(len, (unsigned long) REGION_SIZE);
++              start += incr;
++              len -= incr;
++      } while(len > 0);
++}
++
++struct iomem {
++      char *name;
++      int fd;
++      unsigned long size;
++};
++
++struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = 
++                                       { name :       NULL,
++                                         fd :         -1,
++                                         size :       0 } };
++
++int num_iomem_regions = 0;
++
++void add_iomem(char *name, int fd, int size)
++{
++      if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
++              return;
++      size = (size + PAGE_SIZE - 1) & PAGE_MASK;
++      iomem_regions[num_iomem_regions++] = 
++              ((struct iomem) { name :        name,
++                                fd :          fd,
++                                size :        size } );
++}
++
++int setup_iomem(void)
++{
++      struct iomem *iomem;
++      int i;
++
++      for(i = 0; i < num_iomem_regions; i++){
++              iomem = &iomem_regions[i];
++              setup_range(iomem->fd, iomem->name, -1, iomem->size, NULL, 
++                          NULL);
++      }
++      return(0);
++}
++
++__initcall(setup_iomem);
++
++#define PFN_UP(x)     (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
++#define PFN_DOWN(x)   ((x) >> PAGE_SHIFT)
++
++static struct mem_region physmem_region;
++static struct vm_reserved physmem_reserved;
++
++void setup_physmem(unsigned long start, unsigned long reserve_end,
++                 unsigned long len)
++{
++      struct mem_region *region = &physmem_region;
++      struct vm_reserved *reserved = &physmem_reserved;
++      unsigned long cur;
++      int do_free = 1, bootmap_size;
++
++      do {
++              cur = min(len, (unsigned long) REGION_SIZE);
++              if(region == NULL) 
++                      region = alloc_bootmem_low_pages(sizeof(*region));
++              if(reserved == NULL) 
++                      reserved = alloc_bootmem_low_pages(sizeof(*reserved));
++              if((region == NULL) || (reserved == NULL))
++                      panic("Couldn't allocate physmem region or vm "
++                            "reservation\n");
++              setup_range(-1, NULL, start, cur, region, reserved);
++
++              if(do_free){
++                      unsigned long reserve = reserve_end - start;
++                      int pfn = PFN_UP(__pa(reserve_end));
++                      int delta = (len - reserve) >> PAGE_SHIFT;
++
++                      bootmap_size = init_bootmem(pfn, pfn + delta);
++                      free_bootmem(__pa(reserve_end) + bootmap_size,
++                                   cur - bootmap_size - reserve);
++                      do_free = 0;
++              }
++              start += cur;
++              len -= cur;
++              region = NULL;
++              reserved = NULL;
++      } while(len > 0);
++}
++
++struct mem_region *phys_region(unsigned long phys)
++{
++      unsigned int n = phys_region_index(phys);
++
++      if(regions[n] == NULL) 
++              panic("Physical address in uninitialized region");
++      return(regions[n]);
++}
++
++unsigned long phys_offset(unsigned long phys)
++{
++      return(phys_addr(phys));
++}
++
++struct page *phys_mem_map(unsigned long phys)
++{
++      return((struct page *) phys_region(phys)->mem_map);
++}
++
++struct page *pte_mem_map(pte_t pte)
++{
++      return(phys_mem_map(pte_val(pte)));
++}
++
++struct mem_region *page_region(struct page *page, int *index_out)
++{
++      int i;
++      struct mem_region *region;
++      struct page *map;
++
++      for(i = 0; i < NREGIONS; i++){
++              region = regions[i];
++              if(region == NULL) continue;
++              map = region->mem_map;
++              if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){
++                      if(index_out != NULL) *index_out = i;
++                      return(region);
++              }
++      }
++      panic("No region found for page");
++      return(NULL);
++}
++
++struct page *page_mem_map(struct page *page)
++{
++      return((struct page *) page_region(page, NULL)->mem_map);
++}
++
++extern unsigned long region_pa(void *virt)
++{
++      struct mem_region *region;
++      unsigned long addr = (unsigned long) virt;
++      int i;
++
++      for(i = 0; i < NREGIONS; i++){
++              region = regions[i];
++              if(region == NULL) continue;
++              if((region->start <= addr) && 
++                 (addr <= region->start + region->len))
++                      return(mk_phys(addr - region->start, i));
++      }
++      panic("region_pa : no region for virtual address");
++      return(0);
++}
++
++extern void *region_va(unsigned long phys)
++{
++      return((void *) (phys_region(phys)->start + phys_addr(phys)));
++}
++
++unsigned long page_to_phys(struct page *page)
++{
++      int n;
++      struct mem_region *region = page_region(page, &n);
++      struct page *map = region->mem_map;
++      return(mk_phys((page - map) << PAGE_SHIFT, n));
++}
++
++int setup_mem_maps(void)
++{
++      struct mem_region *region;
++      int i;
++
++      for(i = 0; i < NREGIONS; i++){
++              region = regions[i];
++              if((region != NULL) && (region->fd > 0)) init_maps(region);
++      }
++      return(0);
++}
++
++__initcall(setup_mem_maps);
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/mem_user.c    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,274 @@
++/*
++ * 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 <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <sys/mman.h>
++#include "kern_util.h"
++#include "user.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "init.h"
++#include "os.h"
++
++struct mem_region physmem_region;
++
++struct mem_region *mem_list = &physmem_region;
++
++#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
++
++int create_mem_file(unsigned long len)
++{
++      int fd;
++      char zero;
++
++      fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
++      if (fchmod(fd, 0777) < 0){
++              perror("fchmod");
++              exit(1);
++      }
++      if(os_seek_file(fd, len) < 0){
++              perror("lseek");
++              exit(1);
++      }
++      zero = 0;
++      if(write(fd, &zero, 1) != 1){
++              perror("write");
++              exit(1);
++      }
++      if(fcntl(fd, F_SETFD, 1) != 0)
++              perror("Setting FD_CLOEXEC failed");
++      return(fd);
++}
++
++void setup_one_range(int n, int fd, char *driver, unsigned long start, 
++                   unsigned long len, struct mem_region *region)
++{
++      if(fd == -1)
++              fd = create_mem_file(len);
++      if(region == NULL){
++              region = malloc(sizeof(*region));
++              if(region == NULL){
++                      perror("Allocating mem_region");
++                      exit(1);
++              }
++      }
++      *region = ((struct mem_region) { driver :       driver, 
++                                       start :        start, 
++                                       len :          len, 
++                                       fd :           fd } );
++      regions[n] = region;
++}
++
++int setup_region(struct mem_region *region, void *entry)
++{
++      void *loc, *start;
++      char *driver;
++      int err, offset;
++
++      if(region->start != -1){
++              err = reserve_vm(region->start, 
++                               region->start + region->len, entry);
++              if(err){
++                      printk("setup_region : failed to reserve "
++                             "0x%x - 0x%x for driver '%s'\n",
++                             region->start, 
++                             region->start + region->len,
++                             region->driver);
++                      return(-1);
++              }
++      }
++      else region->start = get_vm(region->len);
++      if(region->start == 0){
++              if(region->driver == NULL) driver = "physmem";
++              else driver = region->driver;
++              printk("setup_region : failed to find vm for "
++                     "driver '%s' (length %d)\n", driver, region->len);
++              return(-1);
++      }
++      if(region->start == uml_physmem){
++              start = (void *) uml_reserved;
++              offset = uml_reserved - uml_physmem;
++      }
++      else {
++              start = (void *) region->start;
++              offset = 0;
++      }
++
++      loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, 
++                 MAP_SHARED | MAP_FIXED, region->fd, offset);
++      if(loc != start){
++              perror("Mapping memory");
++              exit(1);
++      }
++      return(0);
++}
++
++static int __init parse_iomem(char *str, int *add)
++{
++      struct stat buf;
++      char *file, *driver;
++      int fd;
++
++      driver = str;
++      file = strchr(str,',');
++      if(file == NULL){
++              printk("parse_iomem : failed to parse iomem\n");
++              return(1);
++      }
++      *file = '\0';
++      file++;
++      fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("parse_iomem - Couldn't open io file, errno = %d\n", 
++                     errno);
++              return(1);
++      }
++      if(fstat(fd, &buf) < 0) {
++              printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
++              return(1);
++      }
++      add_iomem(driver, fd, buf.st_size);
++      return(0);
++}
++
++__uml_setup("iomem=", parse_iomem,
++"iomem=<name>,<file>\n"
++"    Configure <file> as an IO memory region named <name>.\n\n"
++);
++
++#ifdef notdef
++int logging = 0;
++int logging_fd = -1;
++
++int logging_line = 0;
++char logging_buf[256];
++
++void log(char *fmt, ...)
++{
++      va_list ap;
++      struct timeval tv;
++      struct openflags flags;
++
++      if(logging == 0) return;
++      if(logging_fd < 0){
++              flags = of_create(of_trunc(of_rdrw(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
++
++void map(unsigned long virt, unsigned long phys, unsigned long len, 
++       int r, int w, int x)
++{
++      struct mem_region *region;
++      void *loc;
++      int prot;
++
++      prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++              (x ? PROT_EXEC : 0);
++      region = phys_region(phys);
++
++      loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
++                 region->fd, phys_offset(phys));
++      if(loc != (void *) virt){
++              panic("Error mapping a page - errno = %d", errno);
++      }
++}
++
++int unmap(void *addr, int len)
++{
++      int err;
++
++      err = munmap(addr, len);
++      if(err < 0) return(-errno);
++      else return(err);
++}
++
++int protect(unsigned long addr, unsigned long len, int r, int w, int x,
++          int must_succeed)
++{
++      int prot;
++
++      prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++              (x ? PROT_EXEC : 0);
++      if(mprotect((void *) addr, len, prot) == -1){
++              if(must_succeed)
++                      panic("protect failed, errno = %d", errno);
++              else return(-errno);
++      }
++      return(0);
++}
++
++unsigned long find_iomem(char *driver, unsigned long *len_out)
++{
++      struct mem_region *region;
++      int i, n;
++
++      n = nregions();
++      for(i = 0; i < n; i++){
++              region = regions[i];
++              if(region == NULL) continue;
++              if((region->driver != NULL) &&
++                 !strcmp(region->driver, driver)){
++                      *len_out = region->len;
++                      return(region->start);
++              }
++      }
++      *len_out = 0;
++      return 0;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/mprot.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __MPROT_H__
++#define __MPROT_H__
++
++extern void no_access(unsigned long addr, unsigned int len);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/process.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,253 @@
++/* 
++ * 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 <fcntl.h>
++#include <stdlib.h>
++#include <setjmp.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/ioctl.h>
++#include <sys/wait.h>
++#include <sys/mman.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include <asm/unistd.h>
++#include <asm/page.h>
++#ifdef PROFILING
++#include <sys/gmon.h>
++#endif
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++#include "irq_user.h"
++#include "syscall_user.h"
++#include "ptrace_user.h"
++#include "init.h"
++#include "os.h"
++
++void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
++{
++      int flags = 0;
++
++      if(sig_stack != NULL){
++              set_sigstack(sig_stack, 2 * page_size());
++              flags = SA_ONSTACK;
++      }
++      set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
++                  SA_NOMASK | flags, -1);
++      if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
++      signal(SIGCHLD, SIG_IGN);
++      signal(SIGHUP, SIG_IGN);
++      set_timers(1);  /* XXX A bit of a race here */
++      init_irq_signals(sig_stack != NULL);
++}
++
++struct tramp {
++      int (*tramp)(void *);
++      void *tramp_data;
++      unsigned long temp_stack;
++      int flags;
++      int pid;
++};
++
++/* See above for why sigkill is here */
++
++int sigkill = SIGKILL;
++
++int outer_tramp(void *arg)
++{
++      struct tramp *t;
++      int sig = sigkill;
++
++      t = arg;
++      t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
++                     t->flags, t->tramp_data);
++      if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
++      kill(os_getpid(), sig);
++      _exit(0);
++}
++
++int ssss;
++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 = 0, err = -1;
++
++      /* The trampoline will run on the temporary stack */
++      sp = stack_sp(temp_stack);
++
++      clone_flags |= CLONE_FILES | SIGCHLD;
++
++      arg.tramp = tramp;
++      arg.tramp_data = thread_arg;
++      arg.temp_stack = temp_stack;
++      arg.flags = clone_flags;
++
++      /* Start the process and wait for it to kill itself */
++      new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
++      if(new_pid < 0) return(-errno);
++      while(((err = waitpid(new_pid, &status, __WALL)) < 0) && (errno == EINTR));
++      /*
++       * this is very special hack. sometimes just cloned thread dies before
++       * we call waitpid() -bzzz
++       */
++      if (err < 0 && errno == ECHILD)
++              return(arg.pid);
++
++      if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", 
++                        errno);
++      if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) 
++              panic("outer trampoline didn't exit with SIGKILL");
++
++      return(arg.pid);
++}
++
++void trace_myself(void)
++{
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
++              panic("ptrace failed in trace_myself");
++}
++
++void attach_process(int pid)
++{
++      if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
++         (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
++              tracer_panic("OP_FORK failed to attach pid");
++      wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
++              tracer_panic("OP_FORK failed to continue process");
++}
++
++void tracer_panic(char *format, ...)
++{
++      va_list ap;
++
++      va_start(ap, format);
++      vprintf(format, ap);
++      printf("\n");
++      while(1) sleep(10);
++}
++
++void suspend_new_thread(int fd)
++{
++      char c;
++
++      os_stop_process(os_getpid());
++
++      if(read(fd, &c, sizeof(c)) != sizeof(c))
++              panic("read failed in suspend_new_thread");
++}
++
++static int ptrace_child(void *arg)
++{
++      int pid = os_getpid();
++
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++              perror("ptrace");
++              _exit(1);
++      }
++      os_stop_process(pid);
++      _exit(os_getpid() == pid);
++}
++
++void __init check_ptrace(void)
++{
++      void *stack;
++      unsigned long sp;
++      int status, pid, n, syscall;
++
++      printk("Checking that ptrace can change system call numbers...");
++      stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      if(stack == MAP_FAILED)
++              panic("check_ptrace : mmap failed, errno = %d", errno);
++      sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++      pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
++      if(pid < 0)
++              panic("check_ptrace : clone failed, errno = %d", errno);
++      n = waitpid(pid, &status, WUNTRACED);
++      if(n < 0)
++              panic("check_ptrace : wait failed, errno = %d", errno);
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
++              panic("check_ptrace : expected SIGSTOP, got status = %d",
++                    status);
++      while(1){
++              if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
++                      panic("check_ptrace : ptrace failed, errno = %d", 
++                            errno);
++              n = waitpid(pid, &status, WUNTRACED);
++              if(n < 0)
++                      panic("check_ptrace : wait failed, errno = %d", errno);
++              if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
++                      panic("check_ptrace : expected SIGTRAP, "
++                            "got status = %d", status);
++              
++              syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
++                               0);
++              if(syscall == __NR_getpid){
++                      n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
++                                 __NR_getppid);
++                      if(n < 0)
++                              panic("check_ptrace : failed to modify system "
++                                    "call, errno = %d", errno);
++                      break;
++              }
++      }
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
++              panic("check_ptrace : ptrace failed, errno = %d", errno);
++      n = waitpid(pid, &status, 0);
++      if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
++              panic("check_ptrace : child exited with status 0x%x", status);
++
++      if(munmap(stack, PAGE_SIZE) < 0)
++              panic("check_ptrace : munmap failed, errno = %d", errno);
++      printk("OK\n");
++}
++
++int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
++{
++      jmp_buf buf;
++
++      *jmp_ptr = &buf;
++      if(setjmp(buf)) return(1);
++      (*fn)(arg);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/process_kern.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,765 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/interrupt.h"
++#include "linux/mm.h"
++#include "linux/slab.h"
++#include "linux/utsname.h"
++#include "linux/fs.h"
++#include "linux/utime.h"
++#include "linux/smp_lock.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/capability.h"
++#include "asm/unistd.h"
++#include "asm/mman.h"
++#include "asm/segment.h"
++#include "asm/stat.h"
++#include "asm/pgtable.h"
++#include "asm/processor.h"
++#include "asm/pgalloc.h"
++#include "asm/spinlock.h"
++#include "asm/uaccess.h"
++#include "asm/user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "init.h"
++#include "irq_user.h"
++#include "mem_user.h"
++#include "tlb.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "2_5compat.h"
++#include "os.h"
++
++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 *task, *ret;
++
++        ret = NULL;
++        read_lock(&tasklist_lock);
++        for_each_task(task){
++                if(task->pid == pid){
++                        ret = task;
++                        break;
++                }
++        }
++        read_unlock(&tasklist_lock);
++        if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
++        return(ret);
++}
++
++int is_valid_pid(int pid)
++{
++      struct task_struct *task;
++
++        read_lock(&tasklist_lock);
++        for_each_task(task){
++                if(task->thread.extern_pid == pid){
++                      read_unlock(&tasklist_lock);
++                      return(1);
++                }
++        }
++      read_unlock(&tasklist_lock);
++      return(0);
++}
++
++int external_pid(void *t)
++{
++      struct task_struct *task = t ? t : current;
++
++      return(task->thread.extern_pid);
++}
++
++int pid_to_processor_id(int pid)
++{
++      int i;
++
++      for(i = 0; i < smp_num_cpus; i++){
++              if(cpu_tasks[i].pid == pid) return(i);
++      }
++      return(-1);
++}
++
++void free_stack(unsigned long stack, int order)
++{
++      free_pages(stack, order);
++}
++
++void set_init_pid(int pid)
++{
++      int err;
++
++      init_task.thread.extern_pid = pid;
++      err = os_pipe(init_task.thread.switch_pipe, 1, 1);
++      if(err) panic("Can't create switch pipe for init_task, errno = %d", 
++                    err);
++}
++
++int set_user_mode(void *t)
++{
++      struct task_struct *task;
++
++      task = t ? t : current;
++      if(task->thread.tracing) return(1);
++      task->thread.request.op = OP_TRACE_ON;
++      os_usr1_process(os_getpid());
++      return(0);
++}
++
++void set_tracing(void *task, int tracing)
++{
++      ((struct task_struct *) task)->thread.tracing = tracing;
++}
++
++int is_tracing(void *t)
++{
++      return (((struct task_struct *) t)->thread.tracing);
++}
++
++unsigned long alloc_stack(int order, int atomic)
++{
++      unsigned long page;
++      int flags = GFP_KERNEL;
++
++      if(atomic) flags |= GFP_ATOMIC;
++      if((page = __get_free_pages(flags, order)) == 0)
++              return(0);
++      stack_protections(page);
++      return(page);
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++static void new_thread_handler(int sig)
++{
++      int (*fn)(void *);
++      void *arg;
++
++      fn = current->thread.request.u.thread.proc;
++      arg = current->thread.request.u.thread.arg;
++      current->thread.regs.regs.sc = (void *) (&sig + 1);
++      suspend_new_thread(current->thread.switch_pipe[0]);
++
++      free_page(current->thread.temp_stack);
++      set_cmdline("(kernel thread)");
++      force_flush_all();
++#ifdef SMP
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++#endif
++      current->thread.prev_sched = NULL;
++      change_sig(SIGUSR1, 1);
++      unblock_signals();
++      if(!run_kernel_thread(fn, arg, &current->thread.jmp))
++              do_exit(0);
++}
++
++static int new_thread_proc(void *stack)
++{
++      block_signals();
++      init_new_thread(stack, new_thread_handler);
++      os_usr1_process(os_getpid());
++      return(0);
++}
++
++long arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++      int pid;
++
++      current->thread.request.u.thread.proc = fn;
++      current->thread.request.u.thread.arg = arg;
++      pid = do_fork(CLONE_VM | flags, 0, NULL, 0);
++      if(pid < 0) panic("do_fork failed in kernel_thread");
++      return(pid);
++}
++
++void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
++             struct task_struct *tsk, unsigned cpu)
++{
++      if (prev != next) 
++              clear_bit(cpu, &prev->cpu_vm_mask);
++      set_bit(cpu, &next->cpu_vm_mask);
++}
++
++void set_current(void *t)
++{
++      struct task_struct *task = t;
++
++      cpu_tasks[task->cpu] = ((struct cpu_task) 
++              { task->thread.extern_pid, task });
++}
++
++void *_switch_to(void *prev, void *next)
++{
++      struct task_struct *from, *to;
++      unsigned long flags;
++      int vtalrm, alrm, prof, err;
++      char c;
++      static int reading;
++
++      from = prev;
++      to = next;
++
++      to->thread.prev_sched = from;
++
++      if(from->cpu == 0) forward_interrupts(to->thread.extern_pid);
++      forward_ipi(cpu_data[from->cpu].ipi_pipe[0], to->thread.extern_pid);
++      local_irq_save(flags);
++
++      vtalrm = change_sig(SIGVTALRM, 0);
++      alrm = change_sig(SIGALRM, 0);
++      prof = change_sig(SIGPROF, 0);
++
++      c = 0;
++      set_current(to);
++
++      reading = 0;
++      err = user_write(to->thread.switch_pipe[1], &c, sizeof(c));
++      if(err != sizeof(c))
++              panic("write of switch_pipe failed, errno = %d", -err);
++
++      reading = 1;
++      if(from->state == TASK_ZOMBIE) os_kill_process(os_getpid());
++
++      err = user_read(from->thread.switch_pipe[0], &c, sizeof(c));
++      if(err != sizeof(c))
++              panic("read of switch_pipe failed, errno = %d", -err);
++
++      /* This works around a nasty race with 'jail'.  If we are switching
++       * between two threads of a threaded app and the incoming process 
++       * runs before the outgoing process reaches the read, and it makes
++       * it all the way out to userspace, then it will have write-protected 
++       * the outgoing process stack.  Then, when the outgoing process 
++       * returns from the write, it will segfault because it can no longer
++       * write its own stack.  So, in order to avoid that, the incoming 
++       * thread sits in a loop yielding until 'reading' is set.  This 
++       * isn't entirely safe, since there may be a reschedule from a timer
++       * happening between setting 'reading' and sleeping in read.  But,
++       * it should get a whole quantum in which to reach the read and sleep,
++       * which should be enough.
++       */
++
++      if(jail){
++              while(!reading) sched_yield();
++      }
++
++      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 interrupt_end(void)
++{
++      if(current->need_resched) schedule();
++      if(current->sigpending != 0) do_signal(0);
++}
++
++void release_thread(struct task_struct *task)
++{
++      os_kill_process(task->thread.extern_pid);
++}
++
++void exit_thread(void)
++{
++      close(current->thread.switch_pipe[0]);
++      close(current->thread.switch_pipe[1]);
++      unprotect_stack((unsigned long) current);
++}
++
++/* 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 signcontext, including the signal mask
++ * onto the signal frame.
++ */
++
++extern int hit_me;
++
++void finish_fork_handler(int sig)
++{
++      current->thread.regs.regs.sc = (void *) (&sig + 1);
++      suspend_new_thread(current->thread.switch_pipe[0]);
++      
++      force_flush_all();
++      if(current->mm != current->p_pptr->mm)
++              protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
++      task_protections((unsigned long) current);
++#ifdef SMP
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++#endif
++      current->thread.prev_sched = NULL;
++
++      free_page(current->thread.temp_stack);
++      block_signals();
++      change_sig(SIGUSR1, 0);
++      set_user_mode(current);
++}
++
++void *get_current(void)
++{
++      return(current);
++}
++
++/* This sigusr1 business works around a bug in gcc's -pg support.  
++ * Normally a procedure's mcount call comes after esp has been copied to 
++ * ebp and the new frame is constructed.  With procedures with no locals,
++ * the mcount comes before, as the first thing that the procedure does.
++ * When that procedure is main for a thread, ebp comes in as NULL.  So,
++ * when mcount dereferences it, it segfaults.  So, UML works around this
++ * by adding a non-optimizable local to the various trampolines, fork_tramp
++ * and outer_tramp below, and exec_tramp.
++ */
++
++static int sigusr1 = SIGUSR1;
++
++int fork_tramp(void *stack)
++{
++      int sig = sigusr1;
++
++      block_signals();
++      init_new_thread(stack, finish_fork_handler);
++
++      kill(os_getpid(), sig);
++      return(0);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
++              unsigned long stack_top, struct task_struct * p, 
++              struct pt_regs *regs)
++{
++      int new_pid, err;
++      unsigned long stack;
++      int (*tramp)(void *);
++
++      p->thread = (struct thread_struct) INIT_THREAD;
++      p->thread.kernel_stack = (unsigned long) p + 2 * PAGE_SIZE;
++
++      if(current->thread.forking)
++              tramp = fork_tramp;
++      else {
++              tramp = new_thread_proc;
++              p->thread.request.u.thread = current->thread.request.u.thread;
++      }
++
++      err = os_pipe(p->thread.switch_pipe, 1, 1);
++      if(err){
++              printk("copy_thread : pipe failed, errno = %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((void *) p->thread.kernel_stack, stack,
++                                 clone_flags, tramp);
++      if(new_pid < 0){
++              printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
++                     -new_pid);
++              return(new_pid);
++      }
++
++      if(current->thread.forking){
++              sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc);
++              PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
++              if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp;
++      }
++      p->thread.extern_pid = new_pid;
++
++      current->thread.request.op = OP_FORK;
++      current->thread.request.u.fork.pid = new_pid;
++      os_usr1_process(os_getpid());
++      return(0);
++}
++
++void tracing_reboot(void)
++{
++      current->thread.request.op = OP_REBOOT;
++      os_usr1_process(os_getpid());
++}
++
++void tracing_halt(void)
++{
++      current->thread.request.op = OP_HALT;
++      os_usr1_process(os_getpid());
++}
++
++void tracing_cb(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());
++      }
++}
++
++int do_proc_op(void *t, int proc_id)
++{
++      struct task_struct *task;
++      struct thread_struct *thread;
++      int op, pid;
++
++      task = t;
++      thread = &task->thread;
++      op = thread->request.op;
++      switch(op){
++      case OP_NONE:
++      case OP_TRACE_ON:
++              break;
++      case OP_EXEC:
++              pid = thread->request.u.exec.pid;
++              do_exec(thread->extern_pid, pid);
++              thread->extern_pid = pid;
++              cpu_tasks[task->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);
++}
++
++unsigned long stack_sp(unsigned long page)
++{
++      return(page + PAGE_SIZE - sizeof(void *));
++}
++
++int current_pid(void)
++{
++      return(current->pid);
++}
++
++void cpu_idle(void)
++{
++      if(current->cpu == 0) idle_timer();
++
++      atomic_inc(&init_mm.mm_count);
++      current->mm = &init_mm;
++      current->active_mm = &init_mm;
++
++      while(1){
++              /* endless idle loop with no priority at all */
++              SET_PRI(current);
++
++              /*
++               * although we are an idle CPU, we do not want to
++               * get into the scheduler unnecessarily.
++               */
++              if (current->need_resched) {
++                      schedule();
++                      check_pgt_cache();
++              }
++              idle_sleep(10);
++      }
++}
++
++int page_size(void)
++{
++      return(PAGE_SIZE);
++}
++
++int page_mask(void)
++{
++      return(PAGE_MASK);
++}
++
++unsigned long um_virt_to_phys(void *t, unsigned long addr)
++{
++      struct task_struct *task;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++
++      task = t;
++      if(task->mm == NULL) return(0xffffffff);
++      pgd = pgd_offset(task->mm, addr);
++      pmd = pmd_offset(pgd, addr);
++      if(!pmd_present(*pmd)) return(0xffffffff);
++      pte = pte_offset(pmd, addr);
++      if(!pte_present(*pte)) return(0xffffffff);
++      return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
++}
++
++char *current_cmd(void)
++{
++#ifdef CONFIG_SMP
++      return("(Unknown)");
++#else
++      unsigned long addr = um_virt_to_phys(current, current->mm->arg_start);
++      return addr == 0xffffffff? "(Unknown)": __va(addr);
++#endif
++}
++
++void force_sigbus(void)
++{
++      printk(KERN_ERR "Killing pid %d because of a lack of memory\n", 
++             current->pid);
++      lock_kernel();
++      sigaddset(&current->pending.signal, SIGBUS);
++      recalc_sigpending(current);
++      current->flags |= PF_SIGNALED;
++      do_exit(SIGBUS | 0x80);
++}
++
++void dump_thread(struct pt_regs *regs, struct user *u)
++{
++}
++
++void enable_hlt(void)
++{
++      panic("enable_hlt");
++}
++
++void disable_hlt(void)
++{
++      panic("disable_hlt");
++}
++
++extern int signal_frame_size;
++
++void *um_kmalloc(int size)
++{
++      return(kmalloc(size, GFP_KERNEL));
++}
++
++void *um_kmalloc_atomic(int size)
++{
++      return(kmalloc(size, GFP_ATOMIC));
++}
++
++unsigned long get_fault_addr(void)
++{
++      return((unsigned long) current->thread.fault_addr);
++}
++
++EXPORT_SYMBOL(get_fault_addr);
++
++void clear_singlestep(void *t)
++{
++      struct task_struct *task = (struct task_struct *) t;
++
++      task->ptrace &= ~PT_DTRACE;
++}
++
++int singlestepping(void *t)
++{
++      struct task_struct *task = (struct task_struct *) t;
++
++      if(task->thread.singlestep_syscall)
++              return(0);
++      return(task->ptrace & PT_DTRACE);
++}
++
++void not_implemented(void)
++{
++      printk(KERN_DEBUG "Something isn't implemented in here\n");
++}
++
++EXPORT_SYMBOL(not_implemented);
++
++int user_context(unsigned long sp)
++{
++      return((sp & (PAGE_MASK << 1)) != current->thread.kernel_stack);
++}
++
++extern void remove_umid_dir(void);
++__uml_exitcall(remove_umid_dir);
++
++extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
++
++void do_uml_exitcalls(void)
++{
++      exitcall_t *call;
++
++      call = &__uml_exitcall_end;
++      while (--call >= &__uml_exitcall_begin)
++              (*call)();
++}
++
++void *round_up(unsigned long addr)
++{
++      return(ROUND_UP(addr));
++}
++
++void *round_down(unsigned long addr)
++{
++      return(ROUND_DOWN(addr));
++}
++
++char *uml_strdup(char *string)
++{
++      char *new;
++
++      new = kmalloc(strlen(string) + 1, GFP_KERNEL);
++      if(new == NULL) return(NULL);
++      strcpy(new, string);
++      return(new);
++}
++
++int jail = 0;
++
++int __init jail_setup(char *line, int *add)
++{
++      int ok = 1;
++
++      if(jail) return(0);
++#ifdef CONFIG_SMP
++      printf("'jail' may not used used in a kernel with CONFIG_SMP "
++             "enabled\n");
++      ok = 0;
++#endif
++#ifdef CONFIG_HOSTFS
++      printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
++             "enabled\n");
++      ok = 0;
++#endif
++#ifdef CONFIG_MODULES
++      printf("'jail' may not used used in a kernel with CONFIG_MODULES "
++             "enabled\n");
++      ok = 0;
++#endif        
++      if(!ok) exit(1);
++
++      /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
++       * Removing it from the bounding set eliminates the ability of anything
++       * to acquire it, and thus read or write kernel memory.
++       */
++      cap_lower(cap_bset, CAP_SYS_RAWIO);
++      jail = 1;
++      return(0);
++}
++
++__uml_setup("jail", jail_setup,
++"jail\n"
++"    Enables the protection of kernel memory from processes.\n\n"
++);
++
++static void mprotect_kernel_mem(int w)
++{
++      unsigned long start, end;
++
++      if(!jail || (current == &init_task)) return;
++
++      start = (unsigned long) current + PAGE_SIZE;
++      end = (unsigned long) current + PAGE_SIZE * 4;
++      protect(uml_reserved, start - uml_reserved, 1, w, 1, 1);
++      protect(end, high_physmem - end, 1, w, 1, 1);
++
++      start = (unsigned long) ROUND_DOWN(&_stext);
++      end = (unsigned long) ROUND_UP(&_etext);
++      protect(start, end - start, 1, w, 1, 1);
++
++      start = (unsigned long) ROUND_DOWN(&_unprotected_end);
++      end = (unsigned long) ROUND_UP(&_edata);
++      protect(start, end - start, 1, w, 1, 1);
++
++      start = (unsigned long) ROUND_DOWN(&__bss_start);
++      end = (unsigned long) ROUND_UP(brk_start);
++      protect(start, end - start, 1, w, 1, 1);
++
++      mprotect_kernel_vm(w);
++}
++
++int jail_timer_off = 0;
++
++void unprotect_kernel_mem(void)
++{
++      mprotect_kernel_mem(1);
++      jail_timer_off = 0;
++}
++
++void protect_kernel_mem(void)
++{
++      jail_timer_off = 1;
++      mprotect_kernel_mem(0);
++}
++
++void *get_init_task(void)
++{
++      return(&init_task_union.task);
++}
++
++int copy_to_user_proc(void *to, void *from, int size)
++{
++      return(copy_to_user(to, from, size));
++}
++
++int copy_from_user_proc(void *to, void *from, int size)
++{
++      return(copy_from_user(to, from, size));
++}
++
++int clear_user_proc(void *buf, int size)
++{
++      return(clear_user(buf, size));
++}
++
++void set_thread_sc(void *sc)
++{
++      current->thread.regs.regs.sc = sc;
++}
++
++int smp_sigio_handler(void)
++{
++#ifdef CONFIG_SMP
++      IPI_handler(hard_smp_processor_id());
++      if (hard_smp_processor_id() != 0) return(1);
++#endif
++      return(0);
++}
++
++int um_in_interrupt(void)
++{
++      return(in_interrupt());
++}
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/ptrace.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,266 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/mm.h"
++#include "linux/errno.h"
++#include "linux/smp_lock.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++#include "ptrace_user.h"
++
++/*
++ * Called by kernel/ptrace.c when detaching..
++ */
++void ptrace_disable(struct task_struct *child)
++{ 
++}
++
++int sys_ptrace(long request, long pid, long addr, long data)
++{
++      struct task_struct *child;
++      int i, ret;
++
++      lock_kernel();
++      ret = -EPERM;
++      if (request == PTRACE_TRACEME) {
++              /* are we already being traced? */
++              if (current->ptrace & PT_PTRACED)
++                      goto out;
++              /* set the ptrace bit in the process flags. */
++              current->ptrace |= PT_PTRACED;
++              ret = 0;
++              goto out;
++      }
++      ret = -ESRCH;
++      read_lock(&tasklist_lock);
++      child = find_task_by_pid(pid);
++      if (child)
++              get_task_struct(child);
++      read_unlock(&tasklist_lock);
++      if (!child)
++              goto out;
++
++      ret = -EPERM;
++      if (pid == 1)           /* you may not mess with init */
++              goto out_tsk;
++
++      if (request == PTRACE_ATTACH) {
++              ret = ptrace_attach(child);
++              goto out_tsk;
++      }
++
++      ret = ptrace_check_attach(child, request == PTRACE_KILL);
++      if (ret < 0)
++              goto out_tsk;
++
++      switch (request) {
++              /* when I and D space are separate, these will need to be fixed. */
++      case PTRACE_PEEKTEXT: /* read word at location addr. */ 
++      case PTRACE_PEEKDATA: {
++              unsigned long tmp;
++              int copied;
++
++              ret = -EIO;
++              copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
++              if (copied != sizeof(tmp))
++                      break;
++              ret = put_user(tmp,(unsigned long *) data);
++              break;
++      }
++
++      /* read the word at location addr in the USER area. */
++      case PTRACE_PEEKUSR: {
++              unsigned long tmp;
++
++              ret = -EIO;
++              if ((addr & 3) || addr < 0) 
++                      break;
++
++              tmp = 0;  /* Default return condition */
++              if(addr < FRAME_SIZE_OFFSET){
++                      tmp = getreg(child, addr);
++              }
++              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 *) data);
++              break;
++      }
++
++      /* when I and D space are separate, this will have to be fixed. */
++      case PTRACE_POKETEXT: /* write the word at location addr. */
++      case PTRACE_POKEDATA:
++              ret = -EIO;
++              if (access_process_vm(child, addr, &data, sizeof(data), 
++                                    1) != sizeof(data))
++                      break;
++              ret = 0;
++              break;
++
++      case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
++              ret = -EIO;
++              if ((addr & 3) || addr < 0)
++                      break;
++
++              if (addr < FRAME_SIZE_OFFSET) {
++                      ret = putreg(child, addr, data);
++                      break;
++              }
++              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;
++              }
++
++              break;
++
++      case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
++      case PTRACE_CONT: { /* restart after signal. */
++              ret = -EIO;
++              if ((unsigned long) data > _NSIG)
++                      break;
++              if (request == PTRACE_SYSCALL)
++                      child->ptrace |= PT_TRACESYS;
++              else
++                      child->ptrace &= ~PT_TRACESYS;
++              child->exit_code = data;
++              wake_up_process(child);
++              ret = 0;
++              break;
++      }
++
++/*
++ * make the child exit.  Best I can do is send it a sigkill. 
++ * perhaps it should be put in the status that it wants to 
++ * exit.
++ */
++      case PTRACE_KILL: {
++              ret = 0;
++              if (child->state == TASK_ZOMBIE)        /* already dead */
++                      break;
++              child->exit_code = SIGKILL;
++              wake_up_process(child);
++              break;
++      }
++
++      case PTRACE_SINGLESTEP: {  /* set the trap flag. */
++              ret = -EIO;
++              if ((unsigned long) data > _NSIG)
++                      break;
++              child->ptrace &= ~PT_TRACESYS;
++              child->ptrace |= PT_DTRACE;
++              child->exit_code = data;
++              /* give it a chance to run. */
++              wake_up_process(child);
++              ret = 0;
++              break;
++      }
++
++      case PTRACE_DETACH:
++              /* detach a process that was attached. */
++              ret = ptrace_detach(child, data);
++              break;
++
++#ifdef PTRACE_GETREGS
++      case PTRACE_GETREGS: { /* Get all gp regs from the child. */
++              if (!access_ok(VERIFY_WRITE, (unsigned *)data, 
++                             FRAME_SIZE_OFFSET)) {
++                      ret = -EIO;
++                      break;
++              }
++              for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
++                      __put_user(getreg(child, i),(unsigned long *) data);
++                      data += sizeof(long);
++              }
++              ret = 0;
++              break;
++      }
++#endif
++#ifdef PTRACE_SETREGS
++      case PTRACE_SETREGS: { /* Set all gp regs in the child. */
++              unsigned long tmp = 0;
++              if (!access_ok(VERIFY_READ, (unsigned *)data, 
++                             FRAME_SIZE_OFFSET)) {
++                      ret = -EIO;
++                      break;
++              }
++              for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
++                      __get_user(tmp, (unsigned long *) data);
++                      putreg(child, i, tmp);
++                      data += sizeof(long);
++              }
++              ret = 0;
++              break;
++      }
++#endif
++#ifdef PTRACE_GETFPREGS
++      case PTRACE_GETFPREGS: /* Get the child FPU state. */
++              ret = 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
++      default:
++              ret = -EIO;
++              break;
++      }
++ out_tsk:
++      free_task_struct(child);
++ out:
++      unlock_kernel();
++      return ret;
++}
++
++void syscall_trace(void)
++{
++      if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
++          != (PT_PTRACED|PT_TRACESYS))
++              return;
++      current->exit_code = SIGTRAP;
++      current->state = TASK_STOPPED;
++      notify_parent(current, SIGCHLD);
++      schedule();
++      /*
++       * this isn't the same as continuing with a signal, but it will do
++       * for normal use.  strace only continues with a signal if the
++       * stopping signal is not SIGTRAP.  -brl
++       */
++      if (current->exit_code) {
++              send_sig(current->exit_code, current, 1);
++              current->exit_code = 0;
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/reboot.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,62 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "os.h"
++
++static void kill_off_processes(void)
++{
++      struct task_struct *p;
++      int me;
++
++      me = os_getpid();
++      for_each_task(p){
++              if(p->thread.extern_pid != me) 
++                      os_kill_process(p->thread.extern_pid);
++      }
++      if(init_task.thread.extern_pid != me) 
++              os_kill_process(init_task.thread.extern_pid);
++}
++
++void uml_cleanup(void)
++{
++      kill_off_processes();
++      do_uml_exitcalls();
++}
++
++void machine_restart(char * __unused)
++{
++      do_uml_exitcalls();
++      kill_off_processes();
++      tracing_reboot();
++      os_kill_process(os_getpid());
++}
++
++void machine_power_off(void)
++{
++      do_uml_exitcalls();
++      kill_off_processes();
++      tracing_halt();
++      os_kill_process(os_getpid());
++}
++
++void machine_halt(void)
++{
++      machine_power_off();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/resource.c    2003-09-09 16:15:18.000000000 +0400
+@@ -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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/setup.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,19 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/processor.h"
++
++struct cpuinfo_um boot_cpu_data = { 0, 0, 0, 0 };
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/sigio_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,43 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/list.h"
++#include "linux/slab.h"
++#include "asm/irq.h"
++#include "init.h"
++#include "sigio.h"
++#include "irq_user.h"
++
++static int sigio_irq_fd = -1;
++
++void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      read_sigio_fd(sigio_irq_fd);
++      reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
++}
++
++int write_sigio_irq(int fd)
++{
++      if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
++                        SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", 
++                        NULL)){
++              printk("write_sigio_irq : um_request_irq failed\n");
++              return(-1);
++      }
++      sigio_irq_fd = fd;
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/sigio_user.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,413 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <termios.h>
++#include <pty.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <errno.h>
++#include <string.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include <sys/poll.h>
++#include "init.h"
++#include "user.h"
++#include "kern_util.h"
++#include "sigio.h"
++#include "helper.h"
++#include "os.h"
++
++int pty_output_sigio = 0;
++int pty_close_sigio = 0;
++
++static int got_sigio = 0;
++
++void __init handler(int sig)
++{
++      got_sigio = 1;
++}
++
++struct openpty_arg {
++      int master;
++      int slave;
++      int err;
++};
++
++static int openpty_cb(void *arg)
++{
++      struct openpty_arg *info = arg;
++
++      info->err = 0;
++      if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
++              info->err = errno;
++      return(0);
++}
++
++void __init check_one_sigio(void (*proc)(int, int))
++{
++      struct sigaction old, new;
++      struct termios tt;
++      struct openpty_arg pty = { master : -1, slave : -1 };
++      int master, slave, flags, err;
++
++      err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2);
++      if(err < 0){
++              printk("run_helper_thread failed, errno = %d\n", -err);
++              return;
++      }
++      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;
++      }
++
++      if(tcgetattr(master, &tt) < 0)
++              panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
++      cfmakeraw(&tt);
++      if(tcsetattr(master, TCSADRAIN, &tt) < 0)
++              panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
++
++      if((flags = fcntl(master, F_GETFL)) < 0)
++              panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
++
++      if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
++         (fcntl(master, F_SETOWN, os_getpid()) < 0))
++              panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
++                    "errno = %d\n", errno);
++
++      if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
++              panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", 
++                    errno);
++
++      if(sigaction(SIGIO, NULL, &old) < 0)
++              panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
++      new = old;
++      new.sa_handler = handler;
++      if(sigaction(SIGIO, &new, NULL) < 0)
++              panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
++
++      got_sigio = 0;
++      (*proc)(master, slave);
++              
++      close(master);
++      close(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...");
++
++      while(write(master, buf, sizeof(buf)) > 0) ;
++      if(errno != EAGAIN)
++              panic("check_sigio : write failed, errno = %d\n", errno);
++
++      while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
++
++      if(got_sigio){
++              printk("Yes\n");
++              pty_output_sigio = 1;
++      }
++      else if(errno == EAGAIN) printk("No, enabling workaround\n");
++      else panic("check_sigio : read failed, errno = %d\n", errno);
++}
++
++static void tty_close(int master, int slave)
++{
++      printk("Checking that host ptys support SIGIO on close...");
++
++      close(slave);
++      if(got_sigio){
++              printk("Yes\n");
++              pty_close_sigio = 1;
++      }
++      else printk("No, enabling workaround\n");
++}
++
++void __init check_sigio(void)
++{
++      if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){
++              printk("No pseudo-terminals available - skipping pty SIGIO "
++                     "check\n");
++              return;
++      }
++      check_one_sigio(tty_output);
++      check_one_sigio(tty_close);
++}
++
++static int write_sigio_pid = -1;
++static int write_sigio_fds[2] = { -1, -1 };
++static int sigio_private[2] = { -1, -1 };
++
++struct pollfds {
++      struct pollfd *poll;
++      int size;
++      int used;
++};
++
++struct pollfds current_poll = {
++      poll :          NULL,
++      size :          0,
++      used :          0
++};
++
++struct pollfds next_poll = {
++      poll :          NULL,
++      size :          0,
++      used :          0
++};
++
++static int write_sigio_thread(void *unused)
++{
++      struct pollfds *fds, tmp;
++      struct pollfd *p;
++      int i, n, respond_fd;
++      char c;
++
++      fds = &current_poll;
++      while(1){
++              n = poll(fds->poll, fds->used, -1);
++              if(n < 0){
++                      if(errno == EINTR) continue;
++                      printk("write_sigio_thread : poll returned %d, "
++                             "errno = %d\n", n, errno);
++              }
++              for(i = 0; i < fds->used; i++){
++                      p = &fds->poll[i];
++                      if(p->revents == 0) continue;
++                      if(p->fd == sigio_private[1]){
++                              n = read(sigio_private[1], &c, sizeof(c));
++                              if(n != sizeof(c))
++                                      printk("write_sigio_thread : "
++                                             "read failed, errno = %d\n",
++                                             errno);
++                              tmp = current_poll;
++                              current_poll = next_poll;
++                              next_poll = tmp;
++                              respond_fd = sigio_private[1];
++                      }
++                      else {
++                              respond_fd = write_sigio_fds[1];
++                              fds->used--;
++                              memmove(&fds->poll[i], &fds->poll[i + 1],
++                                      (fds->used - i) * sizeof(*fds->poll));
++                      }
++
++                      n = write(respond_fd, &c, sizeof(c));
++                      if(n != sizeof(c))
++                              printk("write_sigio_thread : write failed, "
++                                     "errno = %d\n", errno);
++              }
++      }
++}
++
++/* XXX SMP locking needed here too */
++
++static int need_poll(int n)
++{
++      if(n <= next_poll.size){
++              next_poll.used = n;
++              return(0);
++      }
++      if(next_poll.poll != NULL) kfree(next_poll.poll);
++      next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
++      if(next_poll.poll == NULL){
++              printk("need_poll : failed to allocate new pollfds\n");
++              next_poll.size = 0;
++              next_poll.used = 0;
++              return(-1);
++      }
++      next_poll.size = n;
++      next_poll.used = n;
++      return(0);
++}
++
++static void update_thread(void)
++{
++      unsigned long flags;
++      int n;
++      char c;
++
++      flags = set_signals(0);
++      n = write(sigio_private[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("update_thread : write failed, errno = %d\n", errno);
++              goto fail;
++      }
++
++      n = read(sigio_private[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("update_thread : read failed, errno = %d\n", errno);
++              goto fail;
++      }
++
++      set_signals(flags);
++      return;
++ fail:
++      if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
++      write_sigio_pid = -1;
++      close(sigio_private[0]);
++      close(sigio_private[1]);        
++      close(write_sigio_fds[0]);
++      close(write_sigio_fds[1]);
++      set_signals(flags);
++}
++
++int add_sigio_fd(int fd, int read)
++{
++      int err, i, n, events;
++
++      for(i = 0; i < current_poll.used; i++)
++              if(current_poll.poll[i].fd == fd) return(0);
++
++      n = current_poll.used + 1;
++      err = need_poll(n);
++      if(err) return(err);
++
++      for(i = 0; i < current_poll.used; i++)
++              next_poll.poll[i] = current_poll.poll[i];
++
++      if(read) events = POLLIN;
++      else events = POLLOUT;
++
++      next_poll.poll[n - 1] = ((struct pollfd) { fd :         fd,
++                                                 events :     events,
++                                                 revents :    0 });
++      update_thread();
++      return(0);
++}
++
++int ignore_sigio_fd(int fd)
++{
++      struct pollfd *p;
++      int err, i, n = 0;
++
++      for(i = 0; i < current_poll.used; i++){
++              if(current_poll.poll[i].fd == fd) break;
++      }
++      if(i == current_poll.used) return(0);
++      
++      err = need_poll(current_poll.used - 1);
++      if(err) return(err);
++
++      for(i = 0; i < current_poll.used; i++){
++              p = &current_poll.poll[i];
++              if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
++      }
++      if(n == i){
++              printk("ignore_sigio_fd : fd %d not found\n", fd);
++              return(-1);
++      }
++
++      update_thread();
++      return(0);
++}
++
++static int setup_initial_poll(int fd)
++{
++      struct pollfd *p;
++
++      p = um_kmalloc(sizeof(struct pollfd));
++      if(p == NULL){
++              printk("setup_initial_poll : failed to allocate poll\n");
++              return(-1);
++      }
++      *p = ((struct pollfd) { fd :    fd,
++                              events :        POLLIN,
++                              revents :       0 });
++      current_poll = ((struct pollfds) { poll :       p,
++                                         used :       1,
++                                         size :       1 });
++      return(0);
++}
++
++void write_sigio_workaround(void)
++{
++      unsigned long stack;
++      int err;
++
++      if(write_sigio_pid != -1) return;
++
++      /* XXX This needs SMP locking */
++      err = os_pipe(write_sigio_fds, 1, 1);
++      if(err){
++              printk("write_sigio_workaround - os_pipe 1 failed, "
++                     "errno = %d\n", -err);
++              return;
++      }
++      err = os_pipe(sigio_private, 1, 1);
++      if(err){
++              printk("write_sigio_workaround - os_pipe 2 failed, "
++                     "errno = %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, &stack, 0);
++
++      if(write_sigio_pid < 0) goto out_close2;
++
++      if(write_sigio_irq(write_sigio_fds[0])) 
++              goto out_kill;
++
++      return;
++
++ out_kill:
++      kill(write_sigio_pid, SIGKILL);
++      write_sigio_pid = -1;
++ out_close2:
++      close(sigio_private[0]);
++      close(sigio_private[1]);        
++ out_close1:
++      close(write_sigio_fds[0]);
++      close(write_sigio_fds[1]);
++}
++
++int read_sigio_fd(int fd)
++{
++      int n;
++      char c;
++
++      n = read(fd, &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("read_sigio_fd - read failed, errno = %d\n", errno);
++              return(-errno);
++      }
++      return(n);
++}
++
++static void sigio_cleanup(void)
++{
++      if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
++}
++
++__uml_exitcall(sigio_cleanup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/signal_kern.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,368 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/stddef.h"
++#include "linux/sys.h"
++#include "linux/sched.h"
++#include "linux/wait.h"
++#include "linux/kernel.h"
++#include "linux/smp_lock.h"
++#include "linux/module.h"
++#include "linux/slab.h"
++#include "asm/signal.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "kern.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++
++EXPORT_SYMBOL(block_signals);
++EXPORT_SYMBOL(unblock_signals);
++
++int probe_stack(unsigned long sp, int delta)
++{
++      int n;
++
++      if((get_user(n, (int *) sp) != 0) ||
++         (put_user(n, (int *) sp) != 0) ||
++         (get_user(n, (int *) (sp - delta)) != 0) ||
++         (put_user(n, (int *) (sp - delta)) != 0))
++              return(-EFAULT);
++      return(0);
++}
++
++static void force_segv(int sig)
++{
++      if(sig == SIGSEGV){
++              struct k_sigaction *ka;
++
++              ka = &current->sig->action[SIGSEGV - 1];
++              ka->sa.sa_handler = SIG_DFL;
++      }
++      force_sig(SIGSEGV, current);
++}
++
++#define _S(nr) (1<<((nr)-1))
++
++#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
++
++/*
++ * OK, we're invoking a handler
++ */   
++static int handle_signal(struct pt_regs *regs, unsigned long signr, 
++                       struct k_sigaction *ka, siginfo_t *info, 
++                       sigset_t *oldset, int error)
++{
++        __sighandler_t handler;
++      void (*restorer)(void);
++      unsigned long sp;
++      sigset_t save;
++      int err, ret;
++
++      ret = 0;
++      switch(error){
++      case -ERESTARTNOHAND:
++              ret = -EINTR;
++              break;
++
++      case -ERESTARTSYS:
++              if (!(ka->sa.sa_flags & SA_RESTART)) {
++                      ret = -EINTR;
++                      break;
++              }
++              /* fallthrough */
++      case -ERESTARTNOINTR:
++              PT_REGS_RESTART_SYSCALL(regs);
++              PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
++
++              /* This is because of the UM_SET_SYSCALL_RETURN and the fact
++               * that on i386 the system call number and return value are
++               * in the same register.  When the system call restarts, %eax
++               * had better have the system call number in it.  Since the
++               * return value doesn't matter (except that it shouldn't be
++               * -ERESTART*), we'll stick the system call number there.
++               */
++              ret = PT_REGS_SYSCALL_NR(regs);
++              break;
++      }
++
++      handler = ka->sa.sa_handler;
++      save = *oldset;
++
++      if (ka->sa.sa_flags & SA_ONESHOT)
++              ka->sa.sa_handler = SIG_DFL;
++
++      if (!(ka->sa.sa_flags & SA_NODEFER)) {
++              spin_lock_irq(&current->sigmask_lock);
++              sigorsets(&current->blocked, &current->blocked, 
++                        &ka->sa.sa_mask);
++              sigaddset(&current->blocked, signr);
++              recalc_sigpending(current);
++              spin_unlock_irq(&current->sigmask_lock);
++      }
++
++      sp = PT_REGS_SP(regs);
++
++      if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
++              sp = current->sas_ss_sp + current->sas_ss_size;
++      
++      if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret);
++
++      if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
++      else restorer = NULL;
++
++      if(ka->sa.sa_flags & SA_SIGINFO)
++              err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
++                                          restorer, regs, info, &save);
++      else
++              err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
++                                          restorer, regs, &save);
++      if(err) goto segv;
++
++      return(0);
++ segv:
++      force_segv(signr);
++      return(1);
++}
++
++/*
++ * Note that 'init' is a special process: it doesn't get signals it doesn't
++ * want to handle. Thus you cannot kill init even with a SIGKILL even by
++ * mistake.
++ */
++
++static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
++{
++      siginfo_t info;
++      struct k_sigaction *ka;
++      int err;
++
++      if (!oldset)
++              oldset = &current->blocked;
++
++      for (;;) {
++              unsigned long signr;
++
++              spin_lock_irq(&current->sigmask_lock);
++              signr = dequeue_signal(&current->blocked, &info);
++              spin_unlock_irq(&current->sigmask_lock);
++
++              if (!signr)
++                      break;
++
++              if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
++                      /* Let the debugger run.  */
++                      current->exit_code = signr;
++                      current->state = TASK_STOPPED;
++                      notify_parent(current, SIGCHLD);
++                      schedule();
++
++                      /* We're back.  Did the debugger cancel the sig?  */
++                      if (!(signr = current->exit_code))
++                              continue;
++                      current->exit_code = 0;
++
++                      /* The debugger continued.  Ignore SIGSTOP.  */
++                      if (signr == SIGSTOP)
++                              continue;
++
++                      /* Update the siginfo structure.  Is this good?  */
++                      if (signr != info.si_signo) {
++                              info.si_signo = signr;
++                              info.si_errno = 0;
++                              info.si_code = SI_USER;
++                              info.si_pid = current->p_pptr->pid;
++                              info.si_uid = current->p_pptr->uid;
++                      }
++
++                      /* If the (new) signal is now blocked, requeue it.  */
++                      if (sigismember(&current->blocked, signr)) {
++                              send_sig_info(signr, &info, current);
++                              continue;
++                      }
++              }
++
++              ka = &current->sig->action[signr-1];
++              if (ka->sa.sa_handler == SIG_IGN) {
++                      if (signr != SIGCHLD)
++                              continue;
++                      /* Check for SIGCHLD: it's special.  */
++                      while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
++                              /* nothing */;
++                      continue;
++              }
++
++              if (ka->sa.sa_handler == SIG_DFL) {
++                      int exit_code = signr;
++
++                      /* Init gets no signals it doesn't want.  */
++                      if (current->pid == 1)
++                              continue;
++
++                      switch (signr) {
++                      case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
++                              continue;
++
++                      case SIGTSTP: case SIGTTIN: case SIGTTOU:
++                              if (is_orphaned_pgrp(current->pgrp))
++                                      continue;
++                              /* FALLTHRU */
++
++                        case SIGSTOP: {
++                                struct signal_struct *sig;
++                              current->state = TASK_STOPPED;
++                              current->exit_code = signr;
++                                sig = current->p_pptr->sig;
++                                if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
++                                      notify_parent(current, SIGCHLD);
++                              schedule();
++                              continue;
++                      }
++                      case SIGQUIT: case SIGILL: case SIGTRAP:
++                      case SIGABRT: case SIGFPE: case SIGSEGV:
++                      case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
++                              if (do_coredump(signr, &current->thread.regs))
++                                      exit_code |= 0x80;
++                              /* FALLTHRU */
++
++                      default:
++                              sigaddset(&current->pending.signal, signr);
++                              recalc_sigpending(current);
++                              current->flags |= PF_SIGNALED;
++                              do_exit(exit_code);
++                              /* NOTREACHED */
++                      }
++              }
++
++              /* Whee!  Actually deliver the signal.  */
++              err = handle_signal(regs, signr, ka, &info, oldset, error);
++              if(!err) return(1);
++      }
++
++      /* Did we come from a system call? */
++      if(PT_REGS_SYSCALL_NR(regs) >= 0){
++              /* Restart the system call - no handlers present */
++              if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
++                 PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
++                 PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
++                      PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
++                      PT_REGS_RESTART_SYSCALL(regs);
++              }
++      }
++
++      /* 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) && 
++         is_syscall(PT_REGS_IP(&current->thread.regs)))
++              current->thread.singlestep_syscall = 1;
++      return(0);
++}
++
++int do_signal(int error)
++{
++      return(kern_do_signal(&current->thread.regs, NULL, error));
++}
++
++/*
++ * Atomically swap in the new signal mask, and wait for a signal.
++ */
++int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
++{
++      sigset_t saveset;
++
++      mask &= _BLOCKABLE;
++      spin_lock_irq(&current->sigmask_lock);
++      saveset = current->blocked;
++      siginitset(&current->blocked, mask);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      while (1) {
++              current->state = TASK_INTERRUPTIBLE;
++              schedule();
++              if(kern_do_signal(&current->thread.regs, &saveset, -EINTR))
++                      return(-EINTR);
++      }
++}
++
++int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
++{
++      sigset_t saveset, newset;
++
++      /* XXX: Don't preclude handling different sized sigset_t's.  */
++      if (sigsetsize != sizeof(sigset_t))
++              return -EINVAL;
++
++      if (copy_from_user(&newset, unewset, sizeof(newset)))
++              return -EFAULT;
++      sigdelsetmask(&newset, ~_BLOCKABLE);
++
++      spin_lock_irq(&current->sigmask_lock);
++      saveset = current->blocked;
++      current->blocked = newset;
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      while (1) {
++              current->state = TASK_INTERRUPTIBLE;
++              schedule();
++              if (kern_do_signal(&current->thread.regs, &saveset, -EINTR))
++                      return(-EINTR);
++      }
++}
++
++int sys_sigreturn(struct pt_regs regs)
++{
++      void *sc = sp_to_sc(PT_REGS_SP(&regs));
++      void *mask = sp_to_mask(PT_REGS_SP(&regs));
++      int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
++
++      spin_lock_irq(&current->sigmask_lock);
++      copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
++                     sizeof(current->blocked.sig[0]));
++      copy_from_user(&current->blocked.sig[1], mask, sig_size);
++      sigdelsetmask(&current->blocked, ~_BLOCKABLE);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++      copy_sc_from_user(current->thread.regs.regs.sc, sc,
++                        &signal_frame_sc.arch);
++      return(PT_REGS_SYSCALL_RET(&current->thread.regs));
++}
++
++int sys_rt_sigreturn(struct pt_regs regs)
++{
++      void *sc = sp_to_rt_sc(PT_REGS_SP(&regs));
++      void *mask = sp_to_rt_mask(PT_REGS_SP(&regs));
++      int sig_size = _NSIG_WORDS * sizeof(unsigned long);
++
++      spin_lock_irq(&current->sigmask_lock);
++      copy_from_user(&current->blocked, mask, sig_size);
++      sigdelsetmask(&current->blocked, ~_BLOCKABLE);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++      copy_sc_from_user(current->thread.regs.regs.sc, sc,
++                        &signal_frame_sc.arch);
++      return(PT_REGS_SYSCALL_RET(&current->thread.regs));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/signal_user.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,138 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <sys/mman.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "signal_user.h"
++#include "signal_kern.h"
++#include "sysdep/sigcontext.h"
++#include "sigcontext.h"
++
++extern int kern_timer_on;
++
++void set_sigstack(void *sig_stack, int size)
++{
++      stack_t stack;
++
++      stack.ss_sp = (__ptr_t) sig_stack;
++      stack.ss_flags = 0;
++      stack.ss_size = size - sizeof(void *);
++      if(sigaltstack(&stack, NULL) != 0)
++              panic("sigaltstack failed");
++}
++
++void set_handler(int sig, void (*handler)(int), int flags, ...)
++{
++      struct sigaction action;
++      va_list ap;
++      int mask;
++
++      va_start(ap, flags);
++      action.sa_handler = handler;
++      sigemptyset(&action.sa_mask);
++      while((mask = va_arg(ap, int)) != -1){
++              sigaddset(&action.sa_mask, mask);
++      }
++      action.sa_flags = flags;
++      action.sa_restorer = NULL;
++      if(sigaction(sig, &action, NULL) < 0)
++              panic("sigaction failed");
++}
++
++int change_sig(int signal, int on)
++{
++      sigset_t sigset, old;
++
++      sigemptyset(&sigset);
++      sigaddset(&sigset, signal);
++      sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
++      return(sigismember(&old, signal));
++}
++
++static void change_signals(int type)
++{
++      sigset_t mask;
++
++      sigemptyset(&mask);
++      if(type == SIG_BLOCK) kern_timer_on = 0;
++      else {
++              kern_timer_on = 1;
++              sigaddset(&mask, SIGVTALRM);
++              sigaddset(&mask, SIGALRM);
++      }
++      sigaddset(&mask, SIGIO);
++      sigaddset(&mask, SIGPROF);
++      if(sigprocmask(type, &mask, NULL) < 0)
++              panic("Failed to change signal mask - errno = %d", errno);
++}
++
++void block_signals(void)
++{
++      change_signals(SIG_BLOCK);
++}
++
++void unblock_signals(void)
++{
++      change_signals(SIG_UNBLOCK);
++}
++
++#define SIGIO_BIT 0
++#define SIGVTALRM_BIT 1
++
++static int enable_mask(sigset_t *mask)
++{
++      int sigs;
++
++      sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
++      sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
++      sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
++      if(kern_timer_on) sigs |= 1 << SIGVTALRM_BIT;
++      return(sigs);
++}
++
++int set_signals(int enable)
++{
++      sigset_t mask;
++      int ret;
++
++      sigemptyset(&mask);
++      if(enable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO);
++      if(enable & (1 << SIGVTALRM_BIT)){
++              kern_timer_on = 1;
++              sigaddset(&mask, SIGVTALRM);
++              sigaddset(&mask, SIGALRM);
++      }
++      if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
++              panic("Failed to enable signals");
++      ret = enable_mask(&mask);
++      sigemptyset(&mask);
++      if((enable & (1 << SIGIO_BIT)) == 0) sigaddset(&mask, SIGIO);
++      if((enable & (1 << SIGVTALRM_BIT)) == 0){
++              kern_timer_on = 0;
++      }
++      if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
++              panic("Failed to block signals");
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/smp.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,302 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++
++
++#ifdef CONFIG_SMP
++
++#include "linux/sched.h"
++#include "linux/threads.h"
++#include "linux/interrupt.h"
++#include "asm/smp.h"
++#include "asm/processor.h"
++#include "asm/spinlock.h"
++#include "asm/softirq.h"
++#include "asm/hardirq.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++
++/* Total count of live CPUs */
++int smp_num_cpus = 1;
++
++/* The 'big kernel lock' */
++spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
++
++/* Per CPU bogomips and other parameters */
++struct cpuinfo_um cpu_data[NR_CPUS];
++
++/* CPU online map */
++unsigned long cpu_online_map;
++
++spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
++
++atomic_t global_bh_count;
++
++unsigned char global_irq_holder = NO_PROC_ID;
++unsigned volatile long global_irq_lock;
++
++/* Set when the idlers are all forked */
++int smp_threads_ready = 0;
++int num_reschedules_sent = 0;
++
++void smp_send_reschedule(int cpu)
++{
++      write(cpu_data[cpu].ipi_pipe[1], "R", 1);
++      num_reschedules_sent++;
++}
++
++static void show(char * str)
++{
++      int cpu = smp_processor_id();
++
++      printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
++}
++      
++#define MAXCOUNT 100000000
++
++static inline void wait_on_bh(void)
++{
++      int count = MAXCOUNT;
++      do {
++              if (!--count) {
++                      show("wait_on_bh");
++                      count = ~0;
++              }
++              /* nothing .. wait for the other bh's to go away */
++      } while (atomic_read(&global_bh_count) != 0);
++}
++
++/*
++ * This is called when we want to synchronize with
++ * bottom half handlers. We need to wait until
++ * no other CPU is executing any bottom half handler.
++ *
++ * Don't wait if we're already running in an interrupt
++ * context or are inside a bh handler. 
++ */
++void synchronize_bh(void)
++{
++      if (atomic_read(&global_bh_count) && !in_interrupt())
++              wait_on_bh();
++}
++
++void smp_send_stop(void)
++{
++      printk(KERN_INFO "Stopping all CPUs\n");
++}
++
++
++static atomic_t smp_commenced = ATOMIC_INIT(0);
++static volatile unsigned long smp_callin_map = 0;
++
++void smp_commence(void)
++{
++      printk("All CPUs are go!\n");
++
++      wmb();
++      atomic_set(&smp_commenced, 1);
++}
++
++static int idle_proc(void *unused)
++{
++      int cpu, err;
++
++      set_current(current);
++      del_from_runqueue(current);
++      unhash_process(current);
++
++      cpu = current->processor;
++      err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
++      if(err){
++              panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, 
++                    -err);
++
++      activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid);
++ 
++      wmb();
++      if (test_and_set_bit(current->processor, &smp_callin_map)) {
++              printk("huh, CPU#%d already present??\n", current->processor);
++              BUG();
++      }
++
++      while (!atomic_read(&smp_commenced))
++              cpu_relax();
++
++      init_idle();
++      cpu_idle();
++      return(0);
++}
++
++int inited_cpus = 1;
++
++static int idle_thread(int (*fn)(void *), int cpu)
++{
++      struct task_struct *new_task;
++      int pid;
++      unsigned char c;
++
++        current->thread.request.u.thread.proc = fn;
++        current->thread.request.u.thread.arg = NULL;
++      pid = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0);
++      if(pid < 0) panic("do_fork failed in idle_thread");
++      new_task = get_task(pid, 1);
++
++      cpu_tasks[cpu].pid = new_task->thread.extern_pid;
++      cpu_tasks[cpu].task = new_task;
++      inited_cpus++;
++      init_tasks[cpu] = new_task;
++      new_task->processor = cpu;
++      new_task->cpus_allowed = 1 << cpu;
++      new_task->cpus_runnable = new_task->cpus_allowed;
++      write(new_task->thread.switch_pipe[1], &c, sizeof(c));
++      return(new_task->thread.extern_pid);
++}
++
++void smp_boot_cpus(void)
++{
++      int err;
++
++      set_bit(0, &cpu_online_map);
++      set_bit(0, &smp_callin_map);
++
++      err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
++      if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
++
++      activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid);
++
++      if(ncpus < 1){
++              printk(KERN_INFO "ncpus set to 1\n");
++              ncpus = 1;
++      }
++      else if(ncpus > NR_CPUS){
++              printk(KERN_INFO 
++                     "ncpus can't be greater than NR_CPUS, set to %d\n",
++                     NR_CPUS);
++              ncpus = NR_CPUS;
++      }
++
++      if(ncpus > 1){
++              int i, pid;
++
++              printk(KERN_INFO "Starting up other processors:\n");
++              for(i=1;i<ncpus;i++){
++                      int waittime;
++
++                      /* Do this early, for hard_smp_processor_id()  */
++                      cpu_tasks[i].pid = -1;
++                      set_bit(i, &cpu_online_map);
++                      smp_num_cpus++;
++
++                      pid = idle_thread(idle_proc, i);
++                      printk(KERN_INFO "\t#%d - idle thread pid = %d.. ",
++                             i, pid);
++
++                      waittime = 200000000;
++                      while (waittime-- && !test_bit(i, &smp_callin_map))
++                              cpu_relax();
++
++                      if (test_bit(i, &smp_callin_map))
++                              printk("online\n");
++                      else {
++                              printk("failed\n");
++                              clear_bit(i, &cpu_online_map);
++                      }
++              }
++      }
++}
++
++int setup_profiling_timer(unsigned int multiplier)
++{
++      printk(KERN_INFO "setup_profiling_timer\n");
++      return(0);
++}
++
++void smp_call_function_slave(int cpu);
++
++void IPI_handler(int cpu)
++{
++      unsigned char c;
++      int fd;
++
++      fd = cpu_data[cpu].ipi_pipe[0];
++      while (read(fd, &c, 1) == 1) {
++              switch (c) {
++              case 'C':
++                      smp_call_function_slave(cpu);
++                      break;
++
++              case 'R':
++                      current->need_resched = 1;
++                      break;
++
++              default:
++                      printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
++                      break;
++              }
++      }
++}
++
++int hard_smp_processor_id(void)
++{
++      return(pid_to_processor_id(os_getpid()));
++}
++
++static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
++static atomic_t scf_started;
++static atomic_t scf_finished;
++static void (*func)(void *info);
++static void *info;
++
++void smp_call_function_slave(int cpu)
++{
++      atomic_inc(&scf_started);
++      (*func)(info);
++      atomic_inc(&scf_finished);
++}
++
++int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
++                    int wait)
++{
++      int cpus = smp_num_cpus - 1;
++      int i;
++
++      if (!cpus)
++              return 0;
++
++      spin_lock_bh(&call_lock);
++      atomic_set(&scf_started, 0);
++      atomic_set(&scf_finished, 0);
++      func = _func;
++      info = _info;
++
++      for (i=0;i<NR_CPUS;i++)
++              if (i != current->processor && test_bit(i, &cpu_online_map))
++                      write(cpu_data[i].ipi_pipe[1], "C", 1);
++
++      while (atomic_read(&scf_started) != cpus)
++              barrier();
++
++      if (wait)
++              while (atomic_read(&scf_finished) != cpus)
++                      barrier();
++
++      spin_unlock_bh(&call_lock);
++      return 0;
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/syscall_kern.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,446 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/file.h"
++#include "linux/smp_lock.h"
++#include "linux/mm.h"
++#include "linux/utsname.h"
++#include "linux/msg.h"
++#include "linux/shm.h"
++#include "linux/sys.h"
++#include "linux/unistd.h"
++#include "linux/slab.h"
++#include "linux/utime.h"
++#include "asm/mman.h"
++#include "asm/uaccess.h"
++#include "asm/ipc.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "sysdep/syscalls.h"
++
++long um_mount(char * dev_name, char * dir_name, char * type,
++            unsigned long new_flags, void * data)
++{
++      if(type == NULL) type = "";
++      return(sys_mount(dev_name, dir_name, type, new_flags, data));
++}
++
++long sys_fork(void)
++{
++      long ret;
++
++      current->thread.forking = 1;
++        ret = do_fork(SIGCHLD, 0, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++long sys_clone(unsigned long clone_flags, unsigned long newsp)
++{
++      long ret;
++
++      current->thread.forking = 1;
++      ret = do_fork(clone_flags, newsp, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++long sys_vfork(void)
++{
++      long ret;
++
++      current->thread.forking = 1;
++      ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++/* common code for old and new mmaps */
++static inline long do_mmap2(
++      unsigned long addr, unsigned long len,
++      unsigned long prot, unsigned long flags,
++      unsigned long fd, unsigned long pgoff)
++{
++      int error = -EBADF;
++      struct file * file = NULL;
++
++      flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
++      if (!(flags & MAP_ANONYMOUS)) {
++              file = fget(fd);
++              if (!file)
++                      goto out;
++      }
++
++      down_write(&current->mm->mmap_sem);
++      error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++      up_write(&current->mm->mmap_sem);
++
++      if (file)
++              fput(file);
++ out:
++      return error;
++}
++
++long sys_mmap2(unsigned long addr, unsigned long len,
++             unsigned long prot, unsigned long flags,
++             unsigned long fd, unsigned long pgoff)
++{
++      return do_mmap2(addr, len, prot, flags, fd, pgoff);
++}
++
++/*
++ * Perform the select(nd, in, out, ex, tv) and mmap() system
++ * calls. Linux/i386 didn't use to be able to handle more than
++ * 4 system call parameters, so these system calls used a memory
++ * block for parameter passing..
++ */
++
++struct mmap_arg_struct {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++int old_mmap(unsigned long addr, unsigned long len,
++           unsigned long prot, unsigned long flags,
++           unsigned long fd, unsigned long offset)
++{
++      int err = -EINVAL;
++      if (offset & ~PAGE_MASK)
++              goto out;
++
++      err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
++ out:
++      return err;
++}
++/*
++ * sys_pipe() is the normal C calling standard for creating
++ * a pipe. It's not the way unix traditionally does this, though.
++ */
++int sys_pipe(unsigned long * fildes)
++{
++        int fd[2];
++        int error;
++
++        error = do_pipe(fd);
++        if (!error) {
++                if (copy_to_user(fildes, fd, 2*sizeof(int)))
++                        error = -EFAULT;
++        }
++        return error;
++}
++
++int sys_pause(void)
++{
++      current->state = TASK_INTERRUPTIBLE;
++      schedule();
++      return -ERESTARTNOHAND;
++}
++
++int sys_sigaction(int sig, const struct old_sigaction *act,
++                       struct old_sigaction *oact)
++{
++      struct k_sigaction new_ka, old_ka;
++      int ret;
++
++      if (act) {
++              old_sigset_t mask;
++              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
++                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++                      return -EFAULT;
++              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
++              __get_user(mask, &act->sa_mask);
++              siginitset(&new_ka.sa.sa_mask, mask);
++      }
++
++      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++      if (!ret && oact) {
++              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
++                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++                      return -EFAULT;
++              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++      }
++
++      return ret;
++}
++
++/*
++ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
++ *
++ * This is really horribly ugly.
++ */
++int sys_ipc (uint call, int first, int second,
++           int third, void *ptr, long fifth)
++{
++      int version, ret;
++
++      version = call >> 16; /* hack for backward compatibility */
++      call &= 0xffff;
++
++      switch (call) {
++      case SEMOP:
++              return sys_semop (first, (struct sembuf *)ptr, second);
++      case SEMGET:
++              return sys_semget (first, second, third);
++      case SEMCTL: {
++              union semun fourth;
++              if (!ptr)
++                      return -EINVAL;
++              if (get_user(fourth.__pad, (void **) ptr))
++                      return -EFAULT;
++              return sys_semctl (first, second, third, fourth);
++      }
++
++      case MSGSND:
++              return sys_msgsnd (first, (struct msgbuf *) ptr, 
++                                 second, third);
++      case MSGRCV:
++              switch (version) {
++              case 0: {
++                      struct ipc_kludge tmp;
++                      if (!ptr)
++                              return -EINVAL;
++                      
++                      if (copy_from_user(&tmp,
++                                         (struct ipc_kludge *) ptr, 
++                                         sizeof (tmp)))
++                              return -EFAULT;
++                      return sys_msgrcv (first, tmp.msgp, second,
++                                         tmp.msgtyp, third);
++              }
++              default:
++                      panic("msgrcv with version != 0");
++                      return sys_msgrcv (first,
++                                         (struct msgbuf *) ptr,
++                                         second, fifth, third);
++              }
++      case MSGGET:
++              return sys_msgget ((key_t) first, second);
++      case MSGCTL:
++              return sys_msgctl (first, second, (struct msqid_ds *) ptr);
++
++      case SHMAT:
++              switch (version) {
++              default: {
++                      ulong raddr;
++                      ret = sys_shmat (first, (char *) ptr, second, &raddr);
++                      if (ret)
++                              return ret;
++                      return put_user (raddr, (ulong *) third);
++              }
++              case 1: /* iBCS2 emulator entry point */
++                      if (!segment_eq(get_fs(), get_ds()))
++                              return -EINVAL;
++                      return sys_shmat (first, (char *) ptr, second, (ulong *) third);
++              }
++      case SHMDT: 
++              return sys_shmdt ((char *)ptr);
++      case SHMGET:
++              return sys_shmget (first, second, third);
++      case SHMCTL:
++              return sys_shmctl (first, second,
++                                 (struct shmid_ds *) ptr);
++      default:
++              return -EINVAL;
++      }
++}
++
++int sys_uname(struct old_utsname * name)
++{
++      int err;
++      if (!name)
++              return -EFAULT;
++      down_read(&uts_sem);
++      err=copy_to_user(name, &system_utsname, sizeof (*name));
++      up_read(&uts_sem);
++      return err?-EFAULT:0;
++}
++
++int sys_olduname(struct oldold_utsname * name)
++{
++      int error;
++
++      if (!name)
++              return -EFAULT;
++      if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
++              return -EFAULT;
++  
++      down_read(&uts_sem);
++      
++      error = __copy_to_user(&name->sysname,&system_utsname.sysname,
++                             __OLD_UTS_LEN);
++      error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->release,&system_utsname.release,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->release+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->version,&system_utsname.version,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->version+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->machine,&system_utsname.machine,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->machine+__OLD_UTS_LEN);
++      
++      up_read(&uts_sem);
++      
++      error = error ? -EFAULT : 0;
++
++      return error;
++}
++
++int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
++{
++      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
++}
++
++static inline int check_area(void *ptr, int size)
++{
++      return(verify_area(VERIFY_WRITE, ptr, size));
++}
++
++static int check_readlink(struct pt_regs *regs)
++{
++      return(check_area((void *) regs->regs.args[1], regs->regs.args[2]));
++}
++
++static int check_utime(struct pt_regs *regs)
++{
++      return(check_area((void *) regs->regs.args[1],
++                        sizeof(struct utimbuf)));
++}
++
++static int check_oldstat(struct pt_regs *regs)
++{
++      return(check_area((void *) regs->regs.args[1], 
++                        sizeof(struct __old_kernel_stat)));
++}
++
++static int check_stat(struct pt_regs *regs)
++{
++      return(check_area((void *) regs->regs.args[1], sizeof(struct stat)));
++}
++
++static int check_stat64(struct pt_regs *regs)
++{
++      return(check_area((void *) regs->regs.args[1], sizeof(struct stat64)));
++}
++
++struct bogus {
++      int kernel_ds;
++      int (*check_params)(struct pt_regs *);
++};
++
++struct bogus this_is_bogus[256] = {
++      [ __NR_mknod ] = { 1, NULL },
++      [ __NR_mkdir ] = { 1, NULL },
++      [ __NR_rmdir ] = { 1, NULL },
++      [ __NR_unlink ] = { 1, NULL },
++      [ __NR_symlink ] = { 1, NULL },
++      [ __NR_link ] = { 1, NULL },
++      [ __NR_rename ] = { 1, NULL },
++      [ __NR_umount ] = { 1, NULL },
++      [ __NR_mount ] = { 1, NULL },
++      [ __NR_pivot_root ] = { 1, NULL },
++      [ __NR_chdir ] = { 1, NULL },
++      [ __NR_chroot ] = { 1, NULL },
++      [ __NR_open ] = { 1, NULL },
++      [ __NR_quotactl ] = { 1, NULL },
++      [ __NR_sysfs ] = { 1, NULL },
++      [ __NR_readlink ] = { 1, check_readlink },
++      [ __NR_acct ] = { 1, NULL },
++      [ __NR_execve ] = { 1, NULL },
++      [ __NR_uselib ] = { 1, NULL },
++      [ __NR_statfs ] = { 1, NULL },
++      [ __NR_truncate ] = { 1, NULL },
++      [ __NR_access ] = { 1, NULL },
++      [ __NR_chmod ] = { 1, NULL },
++      [ __NR_chown ] = { 1, NULL },
++      [ __NR_lchown ] = { 1, NULL },
++      [ __NR_utime ] = { 1, check_utime },
++      [ __NR_oldlstat ] = { 1, check_oldstat },
++      [ __NR_oldstat ] = { 1, check_oldstat },
++      [ __NR_stat ] = { 1, check_stat },
++      [ __NR_lstat ] = { 1, check_stat },
++      [ __NR_stat64 ] = { 1, check_stat64 },
++      [ __NR_lstat64 ] = { 1, check_stat64 },
++      [ __NR_chown32 ] = { 1, NULL },
++};
++
++/* sys_utimes */
++
++static int check_bogosity(struct pt_regs *regs)
++{
++      struct bogus *bogon = &this_is_bogus[regs->regs.syscall];
++
++      if(!bogon->kernel_ds) return(0);
++      if(bogon->check_params && (*bogon->check_params)(regs))
++              return(-EFAULT);
++      set_fs(KERNEL_DS);
++      return(0);
++}
++
++int nsyscalls = 0;
++
++extern syscall_handler_t *sys_call_table[];
++
++long execute_syscall(void *r)
++{
++      struct pt_regs *regs = r;
++      long res;
++      int syscall;
++
++      current->thread.nsyscalls++;
++      nsyscalls++;
++      syscall = regs->regs.syscall;
++
++      if((syscall >= NR_syscalls) || (syscall < 0))
++              res = -ENOSYS;
++      else if(honeypot && check_bogosity(regs))
++              res = -EFAULT;
++      else res = EXECUTE_SYSCALL(syscall, regs);
++
++      set_fs(USER_DS);
++
++      if(current->thread.singlestep_syscall){
++              current->thread.singlestep_syscall = 0;
++              current->ptrace &= ~PT_DTRACE;
++              force_sig(SIGTRAP, current);
++      }
++
++      return(res);
++}
++
++spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
++
++void lock_syscall(void)
++{
++      spin_lock(&syscall_lock);
++}
++
++void unlock_syscall(void)
++{
++      spin_unlock(&syscall_lock);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/sys_call_table.c      2003-09-09 16:43:08.000000000 +0400
+@@ -0,0 +1,470 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/unistd.h"
++#include "linux/version.h"
++#include "linux/sys.h"
++#include "asm/signal.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_exit;
++extern syscall_handler_t sys_fork;
++extern syscall_handler_t sys_creat;
++extern syscall_handler_t sys_link;
++extern syscall_handler_t sys_unlink;
++//extern syscall_handler_t sys_chdir;
++extern syscall_handler_t sys_mknod;
++extern syscall_handler_t sys_chmod;
++extern syscall_handler_t sys_lchown16;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_stat;
++extern syscall_handler_t sys_getpid;
++extern syscall_handler_t sys_oldumount;
++extern syscall_handler_t sys_setuid16;
++extern syscall_handler_t sys_getuid16;
++extern syscall_handler_t sys_ptrace;
++extern syscall_handler_t sys_alarm;
++extern syscall_handler_t sys_fstat;
++extern syscall_handler_t sys_pause;
++extern syscall_handler_t sys_utime;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_access;
++extern syscall_handler_t sys_nice;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_sync;
++extern syscall_handler_t sys_kill;
++extern syscall_handler_t sys_rename;
++extern syscall_handler_t sys_mkdir;
++extern syscall_handler_t sys_rmdir;
++extern syscall_handler_t sys_pipe;
++extern syscall_handler_t sys_times;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_brk;
++extern syscall_handler_t sys_setgid16;
++extern syscall_handler_t sys_getgid16;
++extern syscall_handler_t sys_signal;
++extern syscall_handler_t sys_geteuid16;
++extern syscall_handler_t sys_getegid16;
++extern syscall_handler_t sys_acct;
++extern syscall_handler_t sys_umount;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ioctl;
++extern syscall_handler_t sys_fcntl;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_setpgid;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_olduname;
++extern syscall_handler_t sys_umask;
++//extern syscall_handler_t sys_chroot;
++extern syscall_handler_t sys_ustat;
++extern syscall_handler_t sys_dup2;
++extern syscall_handler_t sys_getppid;
++extern syscall_handler_t sys_getpgrp;
++extern syscall_handler_t sys_sigaction;
++extern syscall_handler_t sys_sgetmask;
++extern syscall_handler_t sys_ssetmask;
++extern syscall_handler_t sys_setreuid16;
++extern syscall_handler_t sys_setregid16;
++extern syscall_handler_t sys_sigsuspend;
++extern syscall_handler_t sys_sigpending;
++extern syscall_handler_t sys_sethostname;
++extern syscall_handler_t sys_setrlimit;
++extern syscall_handler_t sys_old_getrlimit;
++extern syscall_handler_t sys_getrusage;
++extern syscall_handler_t sys_gettimeofday;
++extern syscall_handler_t sys_settimeofday;
++extern syscall_handler_t sys_getgroups16;
++extern syscall_handler_t sys_setgroups16;
++extern syscall_handler_t sys_symlink;
++extern syscall_handler_t sys_lstat;
++extern syscall_handler_t sys_readlink;
++extern syscall_handler_t sys_uselib;
++extern syscall_handler_t sys_swapon;
++extern syscall_handler_t sys_reboot;
++extern syscall_handler_t old_readdir;
++extern syscall_handler_t sys_munmap;
++extern syscall_handler_t sys_truncate;
++extern syscall_handler_t sys_ftruncate;
++extern syscall_handler_t sys_fchmod;
++extern syscall_handler_t sys_fchown16;
++extern syscall_handler_t sys_getpriority;
++extern syscall_handler_t sys_setpriority;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_statfs;
++extern syscall_handler_t sys_fstatfs;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_socketcall;
++extern syscall_handler_t sys_syslog;
++extern syscall_handler_t sys_setitimer;
++extern syscall_handler_t sys_getitimer;
++extern syscall_handler_t sys_newstat;
++extern syscall_handler_t sys_newlstat;
++extern syscall_handler_t sys_newfstat;
++extern syscall_handler_t sys_uname;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_vhangup;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_swapoff;
++extern syscall_handler_t sys_sysinfo;
++extern syscall_handler_t sys_ipc;
++extern syscall_handler_t sys_fsync;
++extern syscall_handler_t sys_sigreturn;
++extern syscall_handler_t sys_rt_sigreturn;
++extern syscall_handler_t sys_clone;
++extern syscall_handler_t sys_setdomainname;
++extern syscall_handler_t sys_newuname;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_adjtimex;
++extern syscall_handler_t sys_mprotect;
++extern syscall_handler_t sys_sigprocmask;
++extern syscall_handler_t sys_create_module;
++extern syscall_handler_t sys_init_module;
++extern syscall_handler_t sys_delete_module;
++extern syscall_handler_t sys_get_kernel_syms;
++extern syscall_handler_t sys_quotactl;
++extern syscall_handler_t sys_getpgid;
++extern syscall_handler_t sys_fchdir;
++extern syscall_handler_t sys_bdflush;
++extern syscall_handler_t sys_sysfs;
++extern syscall_handler_t sys_personality;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_setfsuid16;
++extern syscall_handler_t sys_setfsgid16;
++extern syscall_handler_t sys_llseek;
++extern syscall_handler_t sys_getdents;
++extern syscall_handler_t sys_flock;
++extern syscall_handler_t sys_msync;
++extern syscall_handler_t sys_readv;
++extern syscall_handler_t sys_writev;
++extern syscall_handler_t sys_getsid;
++extern syscall_handler_t sys_fdatasync;
++extern syscall_handler_t sys_sysctl;
++extern syscall_handler_t sys_mlock;
++extern syscall_handler_t sys_munlock;
++extern syscall_handler_t sys_mlockall;
++extern syscall_handler_t sys_munlockall;
++extern syscall_handler_t sys_sched_setparam;
++extern syscall_handler_t sys_sched_getparam;
++extern syscall_handler_t sys_sched_setscheduler;
++extern syscall_handler_t sys_sched_getscheduler;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
++//extern syscall_handler_t sys_sched_yield;
++#endif
++extern syscall_handler_t sys_sched_get_priority_max;
++extern syscall_handler_t sys_sched_get_priority_min;
++extern syscall_handler_t sys_sched_rr_get_interval;
++extern syscall_handler_t sys_nanosleep;
++extern syscall_handler_t sys_mremap;
++extern syscall_handler_t sys_setresuid16;
++extern syscall_handler_t sys_getresuid16;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_query_module;
++extern syscall_handler_t sys_poll;
++extern syscall_handler_t sys_nfsservctl;
++extern syscall_handler_t sys_setresgid16;
++extern syscall_handler_t sys_getresgid16;
++extern syscall_handler_t sys_prctl;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_rt_sigaction;
++extern syscall_handler_t sys_rt_sigprocmask;
++extern syscall_handler_t sys_rt_sigpending;
++extern syscall_handler_t sys_rt_sigtimedwait;
++extern syscall_handler_t sys_rt_sigqueueinfo;
++extern syscall_handler_t sys_rt_sigsuspend;
++extern syscall_handler_t sys_pread;
++extern syscall_handler_t sys_pwrite;
++extern syscall_handler_t sys_chown16;
++extern syscall_handler_t sys_getcwd;
++extern syscall_handler_t sys_capget;
++extern syscall_handler_t sys_capset;
++extern syscall_handler_t sys_sigaltstack;
++extern syscall_handler_t sys_sendfile;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_vfork;
++extern syscall_handler_t sys_getrlimit;
++extern syscall_handler_t sys_mmap2;
++extern syscall_handler_t sys_truncate64;
++extern syscall_handler_t sys_ftruncate64;
++extern syscall_handler_t sys_stat64;
++extern syscall_handler_t sys_lstat64;
++extern syscall_handler_t sys_fstat64;
++extern syscall_handler_t sys_lchown;
++extern syscall_handler_t sys_getuid;
++extern syscall_handler_t sys_getgid;
++extern syscall_handler_t sys_geteuid;
++extern syscall_handler_t sys_getegid;
++extern syscall_handler_t sys_setreuid;
++extern syscall_handler_t sys_setregid;
++extern syscall_handler_t sys_getgroups;
++extern syscall_handler_t sys_setgroups;
++extern syscall_handler_t sys_fchown;
++extern syscall_handler_t sys_setresuid;
++extern syscall_handler_t sys_getresuid;
++extern syscall_handler_t sys_setresgid;
++extern syscall_handler_t sys_getresgid;
++extern syscall_handler_t sys_chown;
++extern syscall_handler_t sys_setuid;
++extern syscall_handler_t sys_setgid;
++extern syscall_handler_t sys_setfsuid;
++extern syscall_handler_t sys_setfsgid;
++extern syscall_handler_t sys_pivot_root;
++extern syscall_handler_t sys_mincore;
++extern syscall_handler_t sys_madvise;
++extern syscall_handler_t sys_fcntl64;
++extern syscall_handler_t sys_getdents64;
++extern syscall_handler_t sys_gettid;
++extern syscall_handler_t sys_readahead;
++
++extern syscall_handler_t um_mount;
++extern syscall_handler_t um_time;
++extern syscall_handler_t um_stime;
++
++#define LAST_GENERIC_SYSCALL __NR_fremovexattr
++
++#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
++#define LAST_SYSCALL LAST_GENERIC_SYSCALL
++#else
++#define LAST_SYSCALL LAST_ARCH_SYSCALL
++#endif
++
++syscall_handler_t *sys_call_table[] = {
++      [ 0 ] = sys_ni_syscall,
++      [ __NR_exit ] = sys_exit,
++      [ __NR_fork ] = sys_fork,
++      [ __NR_read ] = (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_waitpid ] = (syscall_handler_t *) sys_waitpid,
++      [ __NR_creat ] = sys_creat,
++      [ __NR_link ] = sys_link,
++      [ __NR_unlink ] = sys_unlink,
++
++      /* declared differently in kern_util.h */
++      [ __NR_execve ] = (syscall_handler_t *) sys_execve,
++      [ __NR_chdir ] = (syscall_handler_t *) sys_chdir,
++      [ __NR_time ] = um_time,
++      [ __NR_mknod ] = sys_mknod,
++      [ __NR_chmod ] = sys_chmod,
++      [ __NR_lchown ] = sys_lchown16,
++      [ __NR_break ] = sys_ni_syscall,
++      [ __NR_oldstat ] = sys_stat,
++      [ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
++      [ __NR_getpid ] = sys_getpid,
++      [ __NR_mount ] = um_mount,
++      [ __NR_umount ] = sys_oldumount,
++      [ __NR_setuid ] = sys_setuid16,
++      [ __NR_getuid ] = sys_getuid16,
++      [ __NR_stime ] = um_stime,
++      [ __NR_ptrace ] = sys_ptrace,
++      [ __NR_alarm ] = sys_alarm,
++      [ __NR_oldfstat ] = sys_fstat,
++      [ __NR_pause ] = sys_pause,
++      [ __NR_utime ] = sys_utime,
++      [ __NR_stty ] = sys_ni_syscall,
++      [ __NR_gtty ] = sys_ni_syscall,
++      [ __NR_access ] = sys_access,
++      [ __NR_nice ] = sys_nice,
++      [ __NR_ftime ] = sys_ni_syscall,
++      [ __NR_sync ] = sys_sync,
++      [ __NR_kill ] = sys_kill,
++      [ __NR_rename ] = sys_rename,
++      [ __NR_mkdir ] = sys_mkdir,
++      [ __NR_rmdir ] = sys_rmdir,
++
++      /* Declared differently in asm/unistd.h */
++      [ __NR_dup ] = (syscall_handler_t *) sys_dup,
++      [ __NR_pipe ] = sys_pipe,
++      [ __NR_times ] = sys_times,
++      [ __NR_prof ] = sys_ni_syscall,
++      [ __NR_brk ] = sys_brk,
++      [ __NR_setgid ] = sys_setgid16,
++      [ __NR_getgid ] = sys_getgid16,
++      [ __NR_signal ] = sys_signal,
++      [ __NR_geteuid ] = sys_geteuid16,
++      [ __NR_getegid ] = sys_getegid16,
++      [ __NR_acct ] = sys_acct,
++      [ __NR_umount2 ] = sys_umount,
++      [ __NR_lock ] = sys_ni_syscall,
++      [ __NR_ioctl ] = sys_ioctl,
++      [ __NR_fcntl ] = sys_fcntl,
++      [ __NR_mpx ] = sys_ni_syscall,
++      [ __NR_setpgid ] = sys_setpgid,
++      [ __NR_ulimit ] = sys_ni_syscall,
++      [ __NR_oldolduname ] = sys_olduname,
++      [ __NR_umask ] = sys_umask,
++      [ __NR_chroot ] = (syscall_handler_t *) sys_chroot,
++      [ __NR_ustat ] = sys_ustat,
++      [ __NR_dup2 ] = sys_dup2,
++      [ __NR_getppid ] = sys_getppid,
++      [ __NR_getpgrp ] = sys_getpgrp,
++      [ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
++      [ __NR_sigaction ] = sys_sigaction,
++      [ __NR_sgetmask ] = sys_sgetmask,
++      [ __NR_ssetmask ] = sys_ssetmask,
++      [ __NR_setreuid ] = sys_setreuid16,
++      [ __NR_setregid ] = sys_setregid16,
++      [ __NR_sigsuspend ] = sys_sigsuspend,
++      [ __NR_sigpending ] = sys_sigpending,
++      [ __NR_sethostname ] = sys_sethostname,
++      [ __NR_setrlimit ] = sys_setrlimit,
++      [ __NR_getrlimit ] = sys_old_getrlimit,
++      [ __NR_getrusage ] = sys_getrusage,
++      [ __NR_gettimeofday ] = sys_gettimeofday,
++      [ __NR_settimeofday ] = sys_settimeofday,
++      [ __NR_getgroups ] = sys_getgroups16,
++      [ __NR_setgroups ] = sys_setgroups16,
++      [ __NR_symlink ] = sys_symlink,
++      [ __NR_oldlstat ] = sys_lstat,
++      [ __NR_readlink ] = sys_readlink,
++      [ __NR_uselib ] = sys_uselib,
++      [ __NR_swapon ] = sys_swapon,
++      [ __NR_reboot ] = sys_reboot,
++      [ __NR_readdir ] = old_readdir,
++      [ __NR_munmap ] = sys_munmap,
++      [ __NR_truncate ] = sys_truncate,
++      [ __NR_ftruncate ] = sys_ftruncate,
++      [ __NR_fchmod ] = sys_fchmod,
++      [ __NR_fchown ] = sys_fchown16,
++      [ __NR_getpriority ] = sys_getpriority,
++      [ __NR_setpriority ] = sys_setpriority,
++      [ __NR_profil ] = sys_ni_syscall,
++      [ __NR_statfs ] = sys_statfs,
++      [ __NR_fstatfs ] = sys_fstatfs,
++      [ __NR_ioperm ] = sys_ni_syscall,
++      [ __NR_socketcall ] = sys_socketcall,
++      [ __NR_syslog ] = sys_syslog,
++      [ __NR_setitimer ] = sys_setitimer,
++      [ __NR_getitimer ] = sys_getitimer,
++      [ __NR_stat ] = sys_newstat,
++      [ __NR_lstat ] = sys_newlstat,
++      [ __NR_fstat ] = sys_newfstat,
++      [ __NR_olduname ] = sys_uname,
++      [ __NR_iopl ] = sys_ni_syscall,
++      [ __NR_vhangup ] = sys_vhangup,
++      [ __NR_idle ] = sys_ni_syscall,
++      [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
++      [ __NR_swapoff ] = sys_swapoff,
++      [ __NR_sysinfo ] = sys_sysinfo,
++      [ __NR_ipc ] = sys_ipc,
++      [ __NR_fsync ] = sys_fsync,
++      [ __NR_sigreturn ] = sys_sigreturn,
++      [ __NR_clone ] = sys_clone,
++      [ __NR_setdomainname ] = sys_setdomainname,
++      [ __NR_uname ] = sys_newuname,
++      [ __NR_adjtimex ] = sys_adjtimex,
++      [ __NR_mprotect ] = sys_mprotect,
++      [ __NR_sigprocmask ] = sys_sigprocmask,
++      [ __NR_create_module ] = sys_create_module,
++      [ __NR_init_module ] = sys_init_module,
++      [ __NR_delete_module ] = sys_delete_module,
++      [ __NR_get_kernel_syms ] = sys_get_kernel_syms,
++      [ __NR_quotactl ] = sys_quotactl,
++      [ __NR_getpgid ] = sys_getpgid,
++      [ __NR_fchdir ] = sys_fchdir,
++      [ __NR_bdflush ] = sys_bdflush,
++      [ __NR_sysfs ] = sys_sysfs,
++      [ __NR_personality ] = sys_personality,
++      [ __NR_afs_syscall ] = sys_ni_syscall,
++      [ __NR_setfsuid ] = sys_setfsuid16,
++      [ __NR_setfsgid ] = sys_setfsgid16,
++      [ __NR__llseek ] = sys_llseek,
++      [ __NR_getdents ] = sys_getdents,
++      [ __NR__newselect ] = (syscall_handler_t *) sys_select,
++      [ __NR_flock ] = sys_flock,
++      [ __NR_msync ] = sys_msync,
++      [ __NR_readv ] = sys_readv,
++      [ __NR_writev ] = sys_writev,
++      [ __NR_getsid ] = sys_getsid,
++      [ __NR_fdatasync ] = sys_fdatasync,
++      [ __NR__sysctl ] = sys_sysctl,
++      [ __NR_mlock ] = sys_mlock,
++      [ __NR_munlock ] = sys_munlock,
++      [ __NR_mlockall ] = sys_mlockall,
++      [ __NR_munlockall ] = sys_munlockall,
++      [ __NR_sched_setparam ] = sys_sched_setparam,
++      [ __NR_sched_getparam ] = sys_sched_getparam,
++      [ __NR_sched_setscheduler ] = sys_sched_setscheduler,
++      [ __NR_sched_getscheduler ] = sys_sched_getscheduler,
++      [ __NR_sched_yield ] = (syscall_handler_t *) sys_sched_yield,
++      [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max,
++      [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min,
++      [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval,
++      [ __NR_nanosleep ] = sys_nanosleep,
++      [ __NR_mremap ] = sys_mremap,
++      [ __NR_setresuid ] = sys_setresuid16,
++      [ __NR_getresuid ] = sys_getresuid16,
++      [ __NR_vm86 ] = sys_ni_syscall,
++      [ __NR_query_module ] = sys_query_module,
++      [ __NR_poll ] = sys_poll,
++      [ __NR_nfsservctl ] = sys_nfsservctl,
++      [ __NR_setresgid ] = sys_setresgid16,
++      [ __NR_getresgid ] = sys_getresgid16,
++      [ __NR_prctl ] = sys_prctl,
++      [ __NR_rt_sigreturn ] = sys_rt_sigreturn,
++      [ __NR_rt_sigaction ] = sys_rt_sigaction,
++      [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask,
++      [ __NR_rt_sigpending ] = sys_rt_sigpending,
++      [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait,
++      [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo,
++      [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend,
++      [ __NR_pread ] = sys_pread,
++      [ __NR_pwrite ] = sys_pwrite,
++      [ __NR_chown ] = sys_chown16,
++      [ __NR_getcwd ] = sys_getcwd,
++      [ __NR_capget ] = sys_capget,
++      [ __NR_capset ] = sys_capset,
++      [ __NR_sigaltstack ] = sys_sigaltstack,
++      [ __NR_sendfile ] = sys_sendfile,
++      [ __NR_getpmsg ] = sys_ni_syscall,
++      [ __NR_putpmsg ] = sys_ni_syscall,
++      [ __NR_vfork ] = sys_vfork,
++      [ __NR_ugetrlimit ] = sys_getrlimit,
++      [ __NR_mmap2 ] = sys_mmap2,
++      [ __NR_truncate64 ] = sys_truncate64,
++      [ __NR_ftruncate64 ] = sys_ftruncate64,
++      [ __NR_stat64 ] = sys_stat64,
++      [ __NR_lstat64 ] = sys_lstat64,
++      [ __NR_fstat64 ] = sys_fstat64,
++      [ __NR_fcntl64 ] = sys_fcntl64,
++      [ __NR_getdents64 ] = sys_getdents64,
++        [ __NR_security ] = sys_ni_syscall,
++      [ __NR_gettid ] = sys_gettid,
++      [ __NR_readahead ] = sys_readahead,
++      [ __NR_setxattr ] = sys_ni_syscall,
++      [ __NR_lsetxattr ] = sys_ni_syscall,
++      [ __NR_fsetxattr ] = sys_ni_syscall,
++      [ __NR_getxattr ] = sys_ni_syscall,
++      [ __NR_lgetxattr ] = sys_ni_syscall,
++      [ __NR_fgetxattr ] = sys_ni_syscall,
++      [ __NR_listxattr ] = sys_ni_syscall,
++      [ __NR_llistxattr ] = sys_ni_syscall,
++      [ __NR_flistxattr ] = sys_ni_syscall,
++      [ __NR_removexattr ] = sys_ni_syscall,
++      [ __NR_lremovexattr ] = sys_ni_syscall,
++      [ __NR_fremovexattr ] = sys_ni_syscall,
++
++      ARCH_SYSCALLS
++      [ LAST_SYSCALL + 1 ... NR_syscalls ] = 
++              (syscall_handler_t *) sys_ni_syscall
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/syscall_user.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,116 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately
++ * after setting up syscall stack
++ * block SIGVTALRM in any code that's under wait_for_stop
++ */
++
++#include <unistd.h>
++#include <sys/time.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/ptrace.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"
++
++/* XXX Bogus */
++#define ERESTARTSYS   512
++#define ERESTARTNOINTR        513
++#define ERESTARTNOHAND        514
++
++struct {
++      int syscall;
++      int pid;
++      int result;
++      struct timeval start;
++      struct timeval end;
++} syscall_record[1024];
++
++int syscall_index = 0;
++
++extern int kern_timer_on;
++
++void syscall_handler(int sig, struct uml_pt_regs *regs)
++{
++      void *sc;
++      long result;
++      int index, syscall;
++
++      lock_syscall();
++      if(syscall_index == 1024) syscall_index = 0;
++      index = syscall_index;
++      syscall_index++;
++      unlock_syscall();
++
++      syscall = regs->syscall;
++      sc = regs->sc;
++      sc_to_regs(regs, sc, syscall);
++      SC_START_SYSCALL(sc);
++
++      syscall_record[index].syscall = syscall;
++      syscall_record[index].pid = current_pid();
++      syscall_record[index].result = 0xdeadbeef;
++      gettimeofday(&syscall_record[index].start, NULL);
++      syscall_trace();
++      result = execute_syscall(regs);
++
++      /* regs->sc may have changed while the system call ran (there may
++       * have been an interrupt or segfault), so it needs to be refreshed.
++       */
++      regs->sc = sc;
++
++      SC_SET_SYSCALL_RETURN(sc, result);
++      if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || 
++         (result == -ERESTARTNOINTR))
++              do_signal(result);
++
++      syscall_trace();
++      syscall_record[index].result = result;
++      gettimeofday(&syscall_record[index].end, NULL);
++}
++
++int do_syscall(void *task, int pid)
++{
++      unsigned long proc_regs[FRAME_SIZE];
++      struct uml_pt_regs *regs;
++      int syscall;
++
++      if(ptrace_getregs(pid, proc_regs) < 0)
++              tracer_panic("Couldn't read registers");
++      syscall = PT_SYSCALL_NR(proc_regs);
++
++      regs = TASK_REGS(task);
++      UPT_SYSCALL_NR(regs) = syscall;
++
++      if(syscall < 1) return(0);
++
++      if((syscall != __NR_sigreturn) &&
++         ((unsigned long *) PT_IP(proc_regs) >= &_stext) && 
++         ((unsigned long *) PT_IP(proc_regs) <= &_etext))
++              tracer_panic("I'm tracing myself and I can't get out");
++
++      if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
++                __NR_getpid) < 0)
++              tracer_panic("do_syscall : Nullifying syscall failed, "
++                           "errno = %d", errno);
++      return(1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/sysrq.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,98 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/kernel.h"
++#include "linux/module.h"
++#include "asm/page.h"
++#include "asm/processor.h"
++#include "sysrq.h"
++#include "user_util.h"
++
++ /*
++  * If the address is either in the .text section of the
++  * kernel, or in the vmalloc'ed module regions, it *may* 
++  * be the address of a calling routine
++  */
++ 
++#ifdef CONFIG_MODULES
++
++extern struct module *module_list;
++extern struct module kernel_module;
++
++static inline int kernel_text_address(unsigned long addr)
++{
++      int retval = 0;
++      struct module *mod;
++
++      if (addr >= (unsigned long) &_stext &&
++          addr <= (unsigned long) &_etext)
++              return 1;
++
++      for (mod = module_list; mod != &kernel_module; mod = mod->next) {
++              /* mod_bound tests for addr being inside the vmalloc'ed
++               * module area. Of course it'd be better to test only
++               * for the .text subset... */
++              if (mod_bound(addr, 0, mod)) {
++                      retval = 1;
++                      break;
++              }
++      }
++
++      return retval;
++}
++
++#else
++
++static inline int kernel_text_address(unsigned long addr)
++{
++      return (addr >= (unsigned long) &_stext &&
++              addr <= (unsigned long) &_etext);
++}
++
++#endif
++
++void show_trace(unsigned long * stack)
++{
++        int i;
++        unsigned long addr;
++
++        if (!stack)
++                stack = (unsigned long*) &stack;
++
++        printk("Call Trace: ");
++        i = 1;
++        while (((long) stack & (THREAD_SIZE-1)) != 0) {
++                addr = *stack++;
++              if (kernel_text_address(addr)) {
++                      if (i && ((i % 6) == 0))
++                              printk("\n   ");
++                      printk("[<%08lx>] ", addr);
++                      i++;
++                }
++        }
++        printk("\n");
++}
++
++void show_trace_task(struct task_struct *tsk)
++{
++      unsigned long esp = PT_REGS_SP(&tsk->thread.regs);
++
++      /* User space on another CPU? */
++      if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
++              return;
++      show_trace((unsigned long *)esp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/time.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,121 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <time.h>
++#include <sys/time.h>
++#include <signal.h>
++#include <errno.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++
++extern struct timeval xtime;
++
++void timer_handler(int sig, struct uml_pt_regs *regs)
++{
++      timer_irq(regs);
++}
++
++void timer(void)
++{
++      gettimeofday(&xtime, NULL);
++}
++
++static struct itimerval profile_interval;
++
++void get_profile_timer(void)
++{
++      getitimer(ITIMER_PROF, &profile_interval);
++      profile_interval.it_value = profile_interval.it_interval;
++}
++
++void disable_profile_timer(void)
++{
++      struct itimerval interval = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
++      setitimer(ITIMER_PROF, &interval, NULL);
++}
++
++static void set_interval(int timer_type)
++{
++      struct itimerval interval;
++
++      interval.it_interval.tv_sec = 0;
++      interval.it_interval.tv_usec = 1000000/hz();
++      interval.it_value.tv_sec = 0;
++      interval.it_value.tv_usec = 1000000/hz();
++      if(setitimer(timer_type, &interval, NULL) == -1)
++              panic("setitimer failed - errno = %d\n", errno);
++}
++
++void idle_timer(void)
++{
++      if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
++              panic("Couldn't unset SIGVTALRM handler");
++      set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
++                  SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1);
++      set_interval(ITIMER_REAL);
++}
++
++void user_time_init(void)
++{
++      if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++              panic("Couldn't set SIGVTALRM handler");
++      set_interval(ITIMER_VIRTUAL);
++}
++
++void time_init(void)
++{
++      if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
++              panic("Couldn't set SIGVTALRM handler");
++      set_interval(ITIMER_VIRTUAL);
++}
++
++void set_timers(int set_signal)
++{
++      if(set_signal)
++              set_interval(ITIMER_VIRTUAL);
++      if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1)
++              panic("setitimer ITIMER_PROF failed - errno = %d\n", errno);
++}
++
++struct timeval local_offset = { 0, 0 };
++
++void do_gettimeofday(struct timeval *tv)
++{
++      gettimeofday(tv, NULL);
++      timeradd(tv, &local_offset, tv);
++}
++
++void do_settimeofday(struct timeval *tv)
++{
++      struct timeval now;
++
++      gettimeofday(&now, NULL);
++      timersub(tv, &now, &local_offset);
++}
++
++void idle_sleep(int secs)
++{
++      struct timespec ts;
++
++      ts.tv_sec = secs;
++      ts.tv_nsec = 0;
++      nanosleep(&ts, &ts);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/time_kern.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,141 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/unistd.h"
++#include "linux/stddef.h"
++#include "linux/spinlock.h"
++#include "linux/sched.h"
++#include "linux/interrupt.h"
++#include "linux/init.h"
++#include "linux/delay.h"
++#include "asm/irq.h"
++#include "asm/param.h"
++#include "asm/current.h"
++#include "kern_util.h"
++#include "user_util.h"
++
++extern rwlock_t xtime_lock;
++
++int hz(void)
++{
++      return(HZ);
++}
++
++int timer_irq_inited = 0;
++
++/* kern_timer_on and missed_ticks are modified after kernel memory has been 
++ * write-protected, so this puts it in a section which will be left 
++ * write-enabled.
++ */
++int __attribute__ ((__section__ (".unprotected"))) kern_timer_on = 0;
++int __attribute__ ((__section__ (".unprotected"))) missed_ticks = 0;
++
++void timer_irq(struct uml_pt_regs *regs)
++{
++      int ticks = missed_ticks;
++
++        if(!timer_irq_inited) return;
++      missed_ticks = 0;
++      while(ticks--) do_IRQ(TIMER_IRQ, regs);
++}
++
++void boot_timer_handler(int sig)
++{
++      struct pt_regs regs;
++
++      regs.regs.is_user = 0;
++      do_timer(&regs);
++}
++
++void um_timer(int irq, void *dev, struct pt_regs *regs)
++{
++      do_timer(regs);
++      write_lock(&xtime_lock);
++      timer();
++      write_unlock(&xtime_lock);
++}
++
++long um_time(int * tloc)
++{
++      struct timeval now;
++
++      do_gettimeofday(&now);
++      if (tloc) {
++              if (put_user(now.tv_sec,tloc))
++                      now.tv_sec = -EFAULT;
++      }
++      return now.tv_sec;
++}
++
++long um_stime(int * tptr)
++{
++      int value;
++      struct timeval new;
++
++      if (get_user(value, tptr))
++                return -EFAULT;
++      new.tv_sec = value;
++      new.tv_usec = 0;
++      do_settimeofday(&new);
++      return 0;
++}
++
++void __delay(um_udelay_t time)
++{
++      /* Stolen from the i386 __loop_delay */
++      int d0;
++      __asm__ __volatile__(
++              "\tjmp 1f\n"
++              ".align 16\n"
++              "1:\tjmp 2f\n"
++              ".align 16\n"
++              "2:\tdecl %0\n\tjns 2b"
++              :"=&a" (d0)
++              :"0" (time));
++}
++
++void __udelay(um_udelay_t usecs)
++{
++      int i, n;
++
++      n = (loops_per_jiffy * HZ * usecs) / 1000000;
++      for(i=0;i<n;i++) ;
++}
++
++void __const_udelay(um_udelay_t usecs)
++{
++      int i, n;
++
++      n = (loops_per_jiffy * HZ * usecs) / 1000000;
++      for(i=0;i<n;i++) ;
++}
++
++int __init timer_init(void)
++{
++      int err;
++
++      user_time_init();
++      if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", 
++                            NULL)) != 0)
++              printk(KERN_ERR "timer_init : request_irq failed - "
++                     "errno = %d\n", -err);
++      timer_irq_inited = 1;
++      return(0);
++}
++
++__initcall(timer_init);
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/tlb.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,251 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/bootmem.h"
++#include "asm-generic/tlb.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/a.out.h"
++#include "asm/processor.h"
++#include "asm/mmu_context.h"
++#include "asm/uaccess.h"
++#include "asm/atomic.h"
++#include "mem_user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "tlb.h"
++#include "os.h"
++
++static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
++                    unsigned long end_addr, int force)
++{
++      pgd_t *npgd;
++      pmd_t *npmd;
++      pte_t *npte;
++      unsigned long addr;
++      int r, w, x, err;
++
++      if((current->thread.extern_pid != -1) && 
++         (current->thread.extern_pid != os_getpid()))
++              panic("fix_range fixing wrong address space, current = 0x%p",
++                    current);
++      if(mm == NULL) return;
++      for(addr=start_addr;addr<end_addr;){
++              if(addr == TASK_SIZE){
++                      /* Skip over kernel text, kernel data, and physical
++                       * memory, which don't have ptes, plus kernel virtual
++                       * memory, which is flushed separately, and remap
++                       * the process stack.  The only way to get here is
++                       * if (end_addr == STACK_TOP) > TASK_SIZE, which is
++                       * only true in the honeypot case.
++                       */
++                      addr = STACK_TOP - ABOVE_KMEM;
++                      continue;
++              }
++              npgd = pgd_offset(mm, addr);
++              npmd = pmd_offset(npgd, addr);
++              if(pmd_present(*npmd)){
++                      npte = pte_offset(npmd, addr);
++                      r = pte_read(*npte);
++                      w = pte_write(*npte);
++                      x = pte_exec(*npte);
++                      if(!pte_dirty(*npte)) w = 0;
++                      if(!pte_young(*npte)){
++                              r = 0;
++                              w = 0;
++                      }
++                      if(force || pte_newpage(*npte)){
++                              err = unmap((void *) addr, PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*npte))
++                                      map(addr, pte_val(*npte) & PAGE_MASK,
++                                          PAGE_SIZE, r, w, x);
++                      }
++                      else if(pte_newprot(*npte)){
++                              protect(addr, PAGE_SIZE, r, w, x, 1);
++                      }
++                      *npte = pte_mkuptodate(*npte);
++                      addr += PAGE_SIZE;
++              }
++              else {
++                      if(force || pmd_newpage(*npmd)){
++                              err = unmap((void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              pmd_mkuptodate(*npmd);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++}
++
++atomic_t vmchange_seq = ATOMIC_INIT(1);
++
++static void flush_kernel_vm_range(unsigned long start, unsigned long end,
++                                int update_seq)
++{
++      struct mm_struct *mm;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long addr;
++      int updated = 0, err;
++
++      mm = &init_mm;
++      for(addr = start_vm; addr < end_vm;){
++              pgd = pgd_offset(mm, addr);
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_present(*pmd)){
++                      pte = pte_offset(pmd, addr);
++                      if(!pte_present(*pte) || pte_newpage(*pte)){
++                              updated = 1;
++                              err = unmap((void *) addr, PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*pte))
++                                      map(addr, pte_val(*pte) & PAGE_MASK,
++                                          PAGE_SIZE, 1, 1, 1);
++                      }
++                      else if(pte_newprot(*pte)){
++                              updated = 1;
++                              protect(addr, PAGE_SIZE, 1, 1, 1, 1);
++                      }
++                      addr += PAGE_SIZE;
++
++              }
++              else {
++                      if(pmd_newpage(*pmd)){
++                              updated = 1;
++                              err = unmap((void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++      if(updated && update_seq) atomic_inc(&vmchange_seq);
++}
++
++static void protect_vm_page(unsigned long addr, int w, int must_succeed)
++{
++      int err;
++
++      err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed);
++      if(err == 0) return;
++      else if((err == -EFAULT) || (err == -ENOMEM)){
++              flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1);
++              protect_vm_page(addr, w, 1);
++      }
++      else panic("protect_vm_page : protect failed, errno = %d\n", err);
++}
++
++void mprotect_kernel_vm(int w)
++{
++      struct mm_struct *mm;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long addr;
++      
++      mm = &init_mm;
++      for(addr = start_vm; addr < end_vm;){
++              pgd = pgd_offset(mm, addr);
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_present(*pmd)){
++                      pte = pte_offset(pmd, addr);
++                      if(pte_present(*pte)) protect_vm_page(addr, w, 0);
++                      addr += PAGE_SIZE;
++              }
++              else addr += PMD_SIZE;
++      }
++}
++
++void flush_tlb_kernel_vm(void)
++{
++      flush_kernel_vm_range(start_vm, end_vm, 1);
++}
++
++void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
++                   unsigned long end)
++{
++      if(mm != current->mm) return;
++
++      /* Assumes that the range start ... end is entirely within
++       * either process memory or kernel vm
++       */
++      if((start >= start_vm) && (start < end_vm)) 
++              flush_kernel_vm_range(start, end, 1);
++      else fix_range(mm, start, end, 0);
++}
++
++void flush_tlb_mm(struct mm_struct *mm)
++{
++      unsigned long seq;
++
++      if(mm != current->mm) return;
++
++      fix_range(mm, 0, STACK_TOP, 0);
++
++      seq = atomic_read(&vmchange_seq);
++      if(current->thread.vm_seq == seq) return;
++      current->thread.vm_seq = seq;
++      flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
++{
++      address &= PAGE_MASK;
++      flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE);
++}
++
++void flush_tlb_all(void)
++{
++      flush_tlb_mm(current->mm);
++}
++
++void force_flush_all(void)
++{
++      fix_range(current->mm, 0, STACK_TOP, 1);
++      flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
++{
++      return(pgd_offset(mm, address));
++}
++
++pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address)
++{
++      return(pmd_offset(pgd, address));
++}
++
++pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
++{
++      return(pte_offset(pmd, address));
++}
++
++pte_t *addr_pte(struct task_struct *task, unsigned long addr)
++{
++      return(pte_offset(pmd_offset(pgd_offset(task->mm, addr), addr), addr));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/trap_kern.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,407 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/mm.h"
++#include "linux/spinlock.h"
++#include "linux/config.h"
++#include "linux/init.h"
++#include "asm/semaphore.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/a.out.h"
++#include "asm/current.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "chan_kern.h"
++#include "debug.h"
++#include "mconsole_kern.h"
++#include "2_5compat.h"
++
++extern int nsyscalls;
++
++unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
++                 int is_user, void *sc)
++{
++      struct mm_struct *mm = current->mm;
++      struct vm_area_struct *vma;
++      struct siginfo si;
++      void *catcher;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long page;
++
++      if((address >= start_vm) && (address < end_vm)){
++              flush_tlb_kernel_vm();
++              return(0);
++      }
++      if(mm == NULL) panic("Segfault with no mm");
++      catcher = current->thread.fault_catcher;
++      si.si_code = SEGV_MAPERR;
++      down_read(&mm->mmap_sem);
++      vma = find_vma(mm, address);
++      if(!vma) goto bad;
++      else if(vma->vm_start <= address) goto good_area;
++      else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad;
++      else if(expand_stack(vma, address)) goto bad;
++
++ good_area:
++      si.si_code = SEGV_ACCERR;
++      if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad;
++      page = address & PAGE_MASK;
++      if(page == (unsigned long) current + PAGE_SIZE)
++              panic("Kernel stack overflow");
++      pgd = pgd_offset(mm, page);
++      pmd = pmd_offset(pgd, page);
++      do {
++      survive:
++              switch (handle_mm_fault(mm, vma, address, is_write)) {
++              case 1:
++                      current->min_flt++;
++                      break;
++              case 2:
++                      current->maj_flt++;
++                      break;
++              default:
++                      if (current->pid == 1) {
++                              up_read(&mm->mmap_sem);
++                              yield();
++                              down_read(&mm->mmap_sem);
++                              goto survive;
++                      }
++                      /* Fall through to bad area case */
++              case 0:
++                      goto bad;
++              }
++              pte = pte_offset(pmd, page);
++      } while(!pte_present(*pte));
++      *pte = pte_mkyoung(*pte);
++      if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
++      flush_tlb_page(vma, page);
++      up_read(&mm->mmap_sem);
++      return(0);
++ bad:
++      if(catcher != NULL){
++              current->thread.fault_addr = (void *) address;
++              up_read(&mm->mmap_sem);
++              do_longjmp(catcher);
++      } 
++      else if(current->thread.fault_addr != NULL){
++              panic("fault_addr set but no fault catcher");
++      }
++      else if(arch_fixup(ip, sc))
++              return(0);
++
++      if(!is_user) 
++              panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
++                    address, ip);
++      si.si_signo = SIGSEGV;
++      si.si_addr = (void *) address;
++      current->thread.cr2 = address;
++      current->thread.err = is_write;
++      force_sig_info(SIGSEGV, &si, current);
++      up_read(&mm->mmap_sem);
++      return(0);
++}
++
++void bad_segv(unsigned long address, unsigned long ip, int is_write)
++{
++      struct siginfo si;
++
++      printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
++             "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
++      si.si_signo = SIGSEGV;
++      si.si_code = SEGV_ACCERR;
++      si.si_addr = (void *) address;
++      current->thread.cr2 = address;
++      current->thread.err = is_write;
++      force_sig_info(SIGSEGV, &si, current);
++}
++
++void relay_signal(int sig, struct uml_pt_regs *regs)
++{
++      if(arch_handle_signal(sig, regs)) return;
++      if(!regs->is_user) panic("Kernel mode signal %d", sig);
++      force_sig(sig, current);
++}
++
++void bus_handler(int sig, struct uml_pt_regs *regs)
++{
++      if(current->thread.fault_catcher != NULL)
++              do_longjmp(current->thread.fault_catcher);
++      else relay_signal(sig, regs);
++}
++
++void trap_init(void)
++{
++}
++
++spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
++
++void lock_trap(void)
++{
++      spin_lock(&trap_lock);
++}
++
++void unlock_trap(void)
++{
++      spin_unlock(&trap_lock);
++}
++
++extern int debugger_pid;
++extern int debugger_fd;
++extern int debugger_parent;
++
++#ifdef CONFIG_PT_PROXY
++
++int debugger_signal(int status, pid_t pid)
++{
++      return(debugger_proxy(status, pid));
++}
++
++void child_signal(pid_t pid, int status)
++{
++      child_proxy(pid, status);
++}
++
++static void gdb_announce(char *dev_name, int dev)
++{
++      printf("gdb assigned device '%s'\n", dev_name);
++}
++
++static struct chan_opts opts = {
++      announce :      gdb_announce,
++      xterm_title :   "UML kernel debugger",
++      raw :           0,
++      tramp_stack :   0,
++};
++
++static void *xterm_data;
++static int xterm_fd;
++
++extern void *xterm_init(char *, int, struct chan_opts *);
++extern int xterm_open(int, int, int, void *);
++extern void xterm_close(int, void *);
++
++int open_gdb_chan(void)
++{
++      char stack[PAGE_SIZE];
++
++      opts.tramp_stack = (unsigned long) stack;
++      xterm_data = xterm_init("", 0, &opts);
++      xterm_fd = xterm_open(1, 1, 1, xterm_data);
++      return(xterm_fd);
++}
++
++static void exit_debugger_cb(void *unused)
++{
++      if(debugger_pid != -1){
++              if(gdb_pid != -1){
++                      fake_child_exit();
++                      gdb_pid = -1;
++              }
++              else kill_child_dead(debugger_pid);
++              debugger_pid = -1;
++              if(debugger_parent != -1)
++                      detach(debugger_parent, SIGINT);
++      }
++      if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
++}
++
++static void exit_debugger(void)
++{
++      tracing_cb(exit_debugger_cb, NULL);
++}
++
++__uml_exitcall(exit_debugger);
++
++struct gdb_data {
++      char *str;
++      int err;
++};
++
++static void config_gdb_cb(void *arg)
++{
++      struct gdb_data *data = arg;
++      struct task_struct *task;
++      int pid;
++
++      data->err = -1;
++      if(debugger_pid != -1) exit_debugger_cb(NULL);
++      if(!strncmp(data->str, "pid,", strlen("pid,"))){
++              data->str += strlen("pid,");
++              pid = simple_strtoul(data->str, NULL, 0);
++              task = cpu_tasks[0].task;
++              debugger_pid = attach_debugger(task->thread.extern_pid,
++                                             pid, 0);
++              if(debugger_pid != -1){
++                      data->err = 0;
++                      gdb_pid = pid;
++              }
++              return;
++      }
++      data->err = 0;
++      debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
++      init_proxy(debugger_pid, 0, 0);
++}
++
++int gdb_config(char *str)
++{
++      struct gdb_data data;
++
++      if(*str++ != '=') return(-1);
++      data.str = str;
++      tracing_cb(config_gdb_cb, &data);
++      return(data.err);
++}
++
++void remove_gdb_cb(void *unused)
++{
++      exit_debugger_cb(NULL);
++}
++
++int gdb_remove(char *unused)
++{
++      tracing_cb(remove_gdb_cb, NULL);
++      return(0);
++}
++
++#ifdef CONFIG_MCONSOLE
++
++static struct mc_device gdb_mc = {
++      name:           "gdb",
++      config:         gdb_config,
++      remove:         gdb_remove,
++};
++
++int gdb_mc_init(void)
++{
++      mconsole_register_dev(&gdb_mc);
++      return(0);
++}
++
++__initcall(gdb_mc_init);
++
++#endif
++
++void signal_usr1(int sig)
++{
++      if(debugger_pid != -1){
++              printk(KERN_ERR "The debugger is already running\n");
++              return;
++      }
++      debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
++      init_proxy(debugger_pid, 0, 0);
++}
++
++int init_ptrace_proxy(int idle_pid, int startup, int stop)
++{
++      int pid, status;
++
++      pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
++      status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, 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 = simple_strtoul(line, NULL, 0);
++      *add = 0;
++      return 0;
++}
++
++__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
++"gdb-pid=<pid>\n"
++"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
++"    an already-running gdb or a debugger-like process like strace.\n\n"
++);
++
++#else
++
++int debugger_signal(int status, pid_t pid){ return(0); }
++void child_signal(pid_t pid, int status){ }
++int init_ptrace_proxy(int idle_pid, int startup, int stop)
++{
++      printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++      kill_child_dead(idle_pid);
++      exit(1);
++}
++
++void signal_usr1(int sig)
++{
++      printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++}
++
++int attach_debugger(int idle_pid, int pid, int stop)
++{
++      printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
++             "is off\n");
++      return(-1);
++}
++
++int config_gdb(char *str)
++{
++      return(-1);
++}
++
++int remove_gdb(void)
++{
++      return(-1);
++}
++
++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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/trap_user.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,568 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <sched.h>
++#include <fcntl.h>
++#include <setjmp.h>
++#include <string.h>
++#include <sys/ptrace.h>
++#include <sys/time.h>
++#include <sys/wait.h>
++#include <sys/mman.h>
++#include <sys/ioctl.h>
++#include <asm/page.h>
++#include <asm/unistd.h>
++#include <asm/ptrace.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "signal_user.h"
++#include "mem_user.h"
++#include "user.h"
++#include "process.h"
++#include "sigcontext.h"
++#include "sysdep/sigcontext.h"
++#include "init.h"
++#include "chan_user.h"
++#include "irq_user.h"
++#include "frame_user.h"
++#include "syscall_user.h"
++#include "ptrace_user.h"
++#include "task.h"
++#include "os.h"
++
++static void signal_segv(int sig)
++{
++      write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n"));
++      for(;;) ;
++}
++
++int detach(int pid, int sig)
++{
++      return(ptrace(PTRACE_DETACH, pid, 0, sig));
++}
++
++int attach(int pid)
++{
++      int err;
++
++      err = ptrace(PTRACE_ATTACH, pid, 0, 0);
++      if(err < 0) return(-errno);
++      else return(err);
++}
++
++int cont(int pid)
++{
++      return(ptrace(PTRACE_CONT, pid, 0, 0));
++}
++
++void kill_child_dead(int pid)
++{
++      kill(pid, SIGKILL);
++      kill(pid, SIGCONT);
++      while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
++}
++
++int debug = 0;
++int debug_stop = 1;
++int 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_timers(0);
++      set_cmdline("(idle thread)");
++      set_init_pid(os_getpid());
++      proc = arg;
++      return((*proc)(NULL));
++}
++
++static void last_ditch_exit(int sig)
++{
++      signal(SIGINT, SIG_DFL);
++      signal(SIGTERM, SIG_DFL);
++      signal(SIGHUP, SIG_DFL);
++      uml_cleanup();
++      exit(1);
++}
++
++static void sleeping_process_signal(int pid, int sig)
++{
++      switch(sig){
++      /* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
++       * right because the process must be in the kernel already.
++       */
++      case SIGCONT:
++      case SIGTSTP:
++              if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
++                      tracer_panic("sleeping_process_signal : Failed to "
++                                   "continue pid %d, errno = %d\n", pid,
++                                   sig);
++              break;
++
++      /* This happens when the debugger (e.g. strace) is doing system call 
++       * tracing on the kernel.  During a context switch, the current task
++       * will be set to the incoming process and the outgoing process will
++       * hop into write and then read.  Since it's not the current process
++       * any more, the trace of those will land here.  So, we need to just 
++       * PTRACE_SYSCALL it.
++       */
++      case SIGTRAP:
++              if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
++                      tracer_panic("sleeping_process_signal : Failed to "
++                                   "PTRACE_SYSCALL pid %d, errno = %d\n",
++                                   pid, sig);
++              break;
++      case SIGSTOP:
++              break;
++      default:
++              tracer_panic("sleeping process %d got unexpected "
++                           "signal : %d\n", pid, sig);
++              break;
++      }
++}
++
++#ifdef CONFIG_SMP
++#error need to make these arrays
++#endif
++
++int debugger_pid = -1;
++int debugger_parent = -1;
++int debugger_fd = -1;
++int gdb_pid = -1;
++
++struct {
++      unsigned long address;
++      int is_write;
++      int pid;
++      unsigned long sp;
++      int is_user;
++} segfault_record[1024];
++
++int segfault_index = 0;
++
++struct {
++      int pid;
++      int signal;
++      unsigned long addr;
++      struct timeval time;
++} signal_record[1024];
++
++int signal_index = 0;
++int nsignals = 0;
++int debug_trace = 0;
++extern int io_nsignals, io_count, intr_count;
++
++extern void signal_usr1(int sig);
++
++int tracing_pid = -1;
++
++int signals(int (*init_proc)(void *), void *sp)
++{
++      void *task = NULL;
++      unsigned long eip = 0;
++      int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
++      int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
++
++      capture_signal_stack();
++      signal(SIGPIPE, SIG_IGN);
++      setup_tracer_winch();
++      tracing_pid = os_getpid();
++      printk("tracing thread pid = %d\n", tracing_pid);
++
++      pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
++      n = waitpid(pid, &status, WUNTRACED);
++      if(n < 0){
++              printf("waitpid on idle thread failed, errno = %d\n", errno);
++              exit(1);
++      }
++      if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
++              printf("Failed to continue idle thread, errno = %d\n", errno);
++              exit(1);
++      }
++
++      signal(SIGSEGV, signal_segv);
++      signal(SIGUSR1, signal_usr1);
++      set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++      set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++      set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++      if(debug_trace){
++              printk("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){
++                              printk("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){
++                                      printk("Failed to continue debugger "
++                                             "parent, errno = %d\n", errno);
++                                      debugger_parent = -1;
++                              }
++                      }
++              }
++      }
++      set_cmdline("(tracing thread)");
++      while(1){
++              if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
++                      if(errno != ECHILD){
++                              printk("wait failed - errno = %d\n", errno);
++                      }
++                      continue;
++              }
++              if(pid == debugger_pid){
++                      int cont = 0;
++
++                      if(WIFEXITED(status) || WIFSIGNALED(status))
++                              debugger_pid = -1;
++                      /* XXX Figure out how to deal with gdb and SMP */
++                      else cont = debugger_signal(status, cpu_tasks[0].pid);
++                      if(cont == PTRACE_SYSCALL) strace = 1;
++                      continue;
++              }
++              else if(pid == debugger_parent){
++                      debugger_parent_signal(status, pid);
++                      continue;
++              }
++              nsignals++;
++              if(WIFEXITED(status)) ;
++#ifdef notdef
++              {
++                      printk("Child %d exited with status %d\n", pid, 
++                             WEXITSTATUS(status));
++              }
++#endif
++              else if(WIFSIGNALED(status)){
++                      sig = WTERMSIG(status);
++                      if(sig != 9){
++                              printk("Child %d exited with signal %d\n", pid,
++                                     sig);
++                      }
++              }
++              else if(WIFSTOPPED(status)){
++                      sig = WSTOPSIG(status);
++                      if(signal_index == 1024){
++                              signal_index = 0;
++                              last_index = 1023;
++                      }
++                      else last_index = signal_index - 1;
++                      if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
++                          (sig == SIGALRM)) &&
++                         (signal_record[last_index].signal == sig) &&
++                         (signal_record[last_index].pid == pid))
++                              signal_index = last_index;
++                      signal_record[signal_index].pid = pid;
++                      gettimeofday(&signal_record[signal_index].time, NULL);
++                      eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++                      signal_record[signal_index].addr = eip;
++                      signal_record[signal_index++].signal = sig;
++                      
++                      proc_id = pid_to_processor_id(pid);
++                      if(proc_id == -1){
++                              sleeping_process_signal(pid, sig);
++                              continue;
++                      }
++
++                      task = cpu_tasks[proc_id].task;
++                      tracing = is_tracing(task);
++                      old_tracing = tracing;
++
++                      switch(sig){
++                      case SIGUSR1:
++                              sig = 0;
++                              op = do_proc_op(task, proc_id);
++                              switch(op){
++                              case OP_TRACE_ON:
++                                      arch_leave_kernel(task, pid);
++                                      tracing = 1;
++                                      break;
++                              case OP_REBOOT:
++                              case OP_HALT:
++                                      unmap_physmem();
++                                      kmalloc_ok = 0;
++                                      ptrace(PTRACE_KILL, pid, 0, 0);
++                                      return(op == OP_REBOOT);
++                              case OP_NONE:
++                                      printk("Detaching pid %d\n", pid);
++                                      detach(pid, SIGSTOP);
++                                      continue;
++                              default:
++                                      break;
++                              }
++                              /* OP_EXEC switches host processes on us,
++                               * we want to continue the new one.
++                               */
++                              pid = cpu_tasks[proc_id].pid;
++                              break;
++                      case SIGTRAP:
++                              if(!tracing && (debugger_pid != -1)){
++                                      child_signal(pid, status);
++                                      continue;
++                              }
++                              tracing = 0;
++                              if(do_syscall(task, pid)) sig = SIGUSR2;
++                              else clear_singlestep(task);
++                              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)){
++                              child_signal(pid, status);
++                              continue;
++                      }
++
++                      if(tracing){
++                              if(singlestepping(task))
++                                      cont_type = PTRACE_SINGLESTEP;
++                              else cont_type = PTRACE_SYSCALL;
++                      }
++                      else cont_type = PTRACE_CONT;
++
++                      if((cont_type == PTRACE_CONT) && 
++                         (debugger_pid != -1) && strace)
++                              cont_type = PTRACE_SYSCALL;
++
++                      if(ptrace(cont_type, pid, 0, sig) != 0){
++                              tracer_panic("ptrace failed to continue "
++                                           "process - errno = %d\n", 
++                                           errno);
++                      }
++              }
++      }
++      return(0);
++}
++
++static int __init uml_debugtrace_setup(char *line, int *add)
++{
++      debug_trace = 1;
++      return 0;
++}
++__uml_setup("debugtrace", uml_debugtrace_setup,
++"debugtrace\n"
++"    Causes the tracing thread to pause until it is attached by a\n"
++"    debugger and continued.  This is mostly for debugging crashes\n"
++"    early during boot, and should be pretty much obsoleted by\n"
++"    the debug switch.\n\n"
++);
++
++static int __init uml_honeypot_setup(char *line, int *add)
++{
++      jail_setup("", add);
++      honeypot = 1;
++      return 0;
++}
++__uml_setup("honeypot", uml_honeypot_setup, 
++"honeypot\n"
++"    This makes UML put process stacks in the same location as they are\n"
++"    on the host, allowing expoits such as stack smashes to work against\n"
++"    UML.  This implies 'jail'.\n\n"
++);
++
++int nsegfaults = 0;
++
++void segv_handler(int sig, struct uml_pt_regs *regs)
++{
++      struct sigcontext_struct *context = regs->sc;
++      int index;
++
++      if(regs->is_user && !SEGV_IS_FIXABLE(context)){
++              bad_segv(SC_FAULT_ADDR(context), SC_IP(context), 
++                       SC_FAULT_WRITE(context));
++              return;
++      }
++      lock_trap();
++      index = segfault_index++;
++      if(segfault_index == 1024) segfault_index = 0;
++      unlock_trap();
++      nsegfaults++;
++      segfault_record[index].address = SC_FAULT_ADDR(context);
++      segfault_record[index].pid = os_getpid();
++      segfault_record[index].is_write = SC_FAULT_WRITE(context);
++      segfault_record[index].sp = SC_SP(context);
++      segfault_record[index].is_user = regs->is_user;
++      segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context),
++           regs->is_user, context);
++}
++
++extern int kern_timer_on;
++
++struct signal_info {
++      void (*handler)(int, struct uml_pt_regs *);
++      int is_irq;
++};
++
++static 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 },
++      [ 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 :         syscall_handler,
++                    is_irq :          0 },
++};
++
++void sig_handler_common(int sig, struct sigcontext *sc)
++{
++      struct uml_pt_regs save_regs, *r;
++      struct signal_info *info;
++      int save_errno = errno, save_timer = kern_timer_on, is_user;
++
++      unprotect_kernel_mem();
++
++      r = (struct uml_pt_regs *) TASK_REGS(get_current());
++      save_regs = *r;
++      is_user = user_context(SC_SP(sc));
++      r->is_user = is_user;
++      r->sc = sc;
++      if(sig != SIGUSR2) r->syscall = -1;
++
++      change_sig(SIGUSR1, 1);
++      info = &sig_info[sig];
++      if(!info->is_irq) unblock_signals();
++
++      (*info->handler)(sig, r);
++
++      kern_timer_on = save_timer;
++      if(is_user){
++              interrupt_end();
++              block_signals();
++              change_sig(SIGUSR1, 0);
++              set_user_mode(NULL);
++      }
++      *r = save_regs;
++      errno = save_errno;
++      if(is_user) protect_kernel_mem();
++}
++
++void sig_handler(int sig, struct sigcontext sc)
++{
++      sig_handler_common(sig, &sc);
++}
++
++extern int timer_irq_inited, missed_ticks;
++
++extern int jail_timer_off;
++
++void alarm_handler(int sig, struct sigcontext sc)
++{
++      int user;
++
++      if(!timer_irq_inited) return;
++      missed_ticks++;
++      user = user_context(SC_SP(&sc));
++      if(!user && !kern_timer_on) return;
++      if(!user && jail_timer_off) return;
++      sig_handler_common(sig, &sc);
++}
++
++void do_longjmp(void *p)
++{
++    jmp_buf *jbuf = (jmp_buf *) p;
++
++    longjmp(*jbuf, 1);
++}
++
++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 printk("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"
++);
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/tty_log.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,130 @@
++/* 
++ * 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 <fcntl.h>
++#include <sys/time.h>
++#include "init.h"
++#include "user.h"
++#include "os.h"
++
++#define TTY_LOG_DIR "./"
++
++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
++
++struct tty_log_buf {
++      int what;
++      unsigned long tty;
++      int len;
++};
++
++int open_tty_log(void *tty)
++{
++      struct timeval tv;
++      struct tty_log_buf data;
++      char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
++      int fd;
++
++      if(tty_log_fd != -1){
++              data = ((struct tty_log_buf) { what :   TTY_LOG_OPEN,
++                                             tty : (unsigned long) tty,
++                                             len : 0 });
++              write(tty_log_fd, &data, sizeof(data));
++              return(tty_log_fd);
++      }
++
++      gettimeofday(&tv, NULL);
++      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;
++
++      if(tty_log_fd != -1){
++              data = ((struct tty_log_buf) { what :   TTY_LOG_CLOSE,
++                                             tty : (unsigned long) tty,
++                                             len : 0 });
++              write(tty_log_fd, &data, sizeof(data));
++              return;
++      }
++      close(fd);
++}
++
++int write_tty_log(int fd, char *buf, int len, void *tty)
++{
++      struct tty_log_buf data;
++
++      if(fd == tty_log_fd){
++              data = ((struct tty_log_buf) { what :   TTY_LOG_WRITE,
++                                             tty : (unsigned long) tty,
++                                             len : len });
++              write(tty_log_fd, &data, sizeof(data));
++      }
++      return(write(fd, buf, len));
++}
++
++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'){
++              printk("set_tty_log_dir - strtoul failed on '%s'\n", name);
++              tty_log_fd = -1;
++      }
++      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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/uaccess_user.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,126 @@
++/* 
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <setjmp.h>
++#include <string.h>
++#include "user_util.h"
++
++static unsigned long __do_user_copy(void *to, const void *from, int n,
++                                  void **fault_addr, void **fault_catcher,
++                                  void (*op)(void *to, const void *from,
++                                             int n), int *faulted_out)
++{
++      unsigned long *faddrp = (unsigned long *) fault_addr, ret;
++
++      jmp_buf jbuf;
++      *fault_catcher = &jbuf;
++      if(setjmp(jbuf) == 0){
++              (*op)(to, from, n);
++              ret = 0;
++              *faulted_out = 0;
++      } 
++      else {
++              ret = *faddrp;
++              *faulted_out = 1;
++      }
++      *fault_addr = NULL;
++      *fault_catcher = NULL;
++      return ret;
++}
++
++static void __do_copy(void *to, const void *from, int n)
++{
++      memcpy(to, from, n);
++}     
++
++int __do_copy_from_user(void *to, const void *from, int n,
++                      void **fault_addr, void **fault_catcher)
++{
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++                             __do_copy, &faulted);
++      if(!faulted) return(0);
++      else return(n - (fault - (unsigned long) from));
++}
++
++
++int __do_copy_to_user(void *to, const void *from, int n,
++                    void **fault_addr, void **fault_catcher)
++{
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++                             __do_copy, &faulted);
++      if(!faulted) return(0);
++      else return(n - (fault - (unsigned long) to));
++}
++
++static void __do_strncpy(void *dst, const void *src, int count)
++{
++      strncpy(dst, src, count);
++}     
++
++int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
++                         void **fault_addr, void **fault_catcher)
++{
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
++                             __do_strncpy, &faulted);
++      if(!faulted) return(strlen(dst));
++      else return(-1);
++}
++
++static void __do_clear(void *to, const void *from, int n)
++{
++      memset(to, 0, n);
++}     
++
++int __do_clear_user(void *mem, unsigned long len,
++                  void **fault_addr, void **fault_catcher)
++{
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
++                             __do_clear, &faulted);
++      if(!faulted) return(0);
++      else return(len - (fault - (unsigned long) mem));
++}
++
++int __do_strnlen_user(const char *str, unsigned long n,
++                    void **fault_addr, void **fault_catcher)
++{
++      int ret;
++      unsigned long *faddrp = (unsigned long *)fault_addr;
++      jmp_buf jbuf;
++
++      *fault_catcher = &jbuf;
++      if(setjmp(jbuf) == 0){
++              ret = strlen(str) + 1;
++      } 
++      else {
++              ret = *faddrp - (unsigned long) str;
++      }
++      *fault_addr = NULL;
++      *fault_catcher = NULL;
++      return ret;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/um_arch.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,388 @@
++/* 
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.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 "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 "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mprot.h"
++#include "mem_user.h"
++#include "mem.h"
++#include "umid.h"
++#include "initrd.h"
++#include "init.h"
++#include "os.h"
++
++#define DEFAULT_COMMAND_LINE "root=/dev/ubd0"
++
++unsigned long thread_saved_pc(struct thread_struct *thread)
++{
++      return(os_process_pc(thread->extern_pid));
++}
++
++static int show_cpuinfo(struct seq_file *m, void *v)
++{
++      int index;
++
++      index = (struct cpuinfo_um *)v - cpu_data;
++#ifdef CONFIG_SMP
++      if (!(cpu_online_map & (1 << index)))
++              return 0;
++#endif
++
++      seq_printf(m, "bogomips\t: %lu.%02lu\n",
++                 loops_per_jiffy/(500000/HZ),
++                 (loops_per_jiffy/(5000/HZ)) % 100);
++      seq_printf(m, "host\t\t: %s\n", host_info);
++
++      return(0);
++}
++
++static void *c_start(struct seq_file *m, loff_t *pos)
++{
++      return *pos < NR_CPUS ? cpu_data + *pos : NULL;
++}
++
++static void *c_next(struct seq_file *m, void *v, loff_t *pos)
++{
++      ++*pos;
++      return c_start(m, pos);
++}
++
++static void c_stop(struct seq_file *m, void *v)
++{
++}
++
++struct seq_operations cpuinfo_op = {
++      start:  c_start,
++      next:   c_next,
++      stop:   c_stop,
++      show:   show_cpuinfo,
++};
++
++pte_t * __bad_pagetable(void)
++{
++      panic("Someone should implement __bad_pagetable");
++      return(NULL);
++}
++
++extern void start_kernel(void);
++
++extern int debug;
++extern int debug_stop;
++
++static int start_kernel_proc(void *unused)
++{
++      int pid;
++
++      block_signals();
++      pid = os_getpid();
++
++      cpu_tasks[0].pid = pid;
++      cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++      cpu_online_map = 1;
++#endif
++      if(debug) os_stop_process(pid);
++      start_kernel();
++      return(0);
++}
++
++extern unsigned long high_physmem;
++
++#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 host_task_size;
++unsigned long task_size;
++
++void set_task_sizes(int arg)
++{
++      /* Round up to the nearest 4M */
++      host_task_size = ROUND_4M((unsigned long) &arg);
++      task_size = START;
++}
++
++unsigned long uml_physmem;
++unsigned long uml_reserved;
++
++unsigned long start_vm;
++unsigned long end_vm;
++
++int ncpus = 1;
++
++static char *argv1_begin = NULL;
++static char *argv1_end = NULL;
++
++static int have_root __initdata = 0;
++long physmem_size = 32 * 1024 * 1024;
++
++void set_cmdline(char *cmd)
++{
++      char *umid, *ptr;
++      if(honeypot) 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));  
++}
++
++static char *usage_string = 
++"User Mode Linux v%s\n"
++"     available at http://user-mode-linux.sourceforge.net/\n\n";
++
++static int __init uml_version_setup(char *line, int *add)
++{
++      printf("%s\n", system_utsname.release);
++      exit(0);
++}
++
++__uml_setup("--version", uml_version_setup,
++"--version\n"
++"    Prints the version number of the kernel.\n\n"
++);
++
++static int __init uml_root_setup(char *line, int *add)
++{
++      have_root = 1;
++      return 0;
++}
++
++__uml_setup("root=", uml_root_setup,
++"root=<file containing the root fs>\n"
++"    This is actually used by the generic kernel in exactly the same\n"
++"    way as in any other kernel. If you configure a number of block\n"
++"    devices and want to boot off something other than ubd0, you \n"
++"    would use something like:\n"
++"        root=/dev/ubd5\n\n"
++);
++
++#ifdef CONFIG_SMP
++static int __init uml_ncpus_setup(char *line, int *add)
++{
++       if (!sscanf(line, "%d", &ncpus)) {
++               printk("Couldn't parse [%s]\n", line);
++               return -1;
++       }
++
++       return 0;
++}
++
++__uml_setup("ncpus=", uml_ncpus_setup,
++"ncpus=<# of desired CPUs>\n"
++"    This tells an SMP kernel how many virtual processors to start.\n"
++"    Currently, this has no effect because SMP isn't enabled.\n\n" 
++);
++#endif
++
++static int __init Usage(char *line, int *add)
++{
++      const char **p;
++
++      printf(usage_string, system_utsname.release);
++      p = &__uml_help_start;
++      while (p < &__uml_help_end) {
++              printf("%s", *p);
++              p++;
++      }
++      exit(0);
++}
++
++__uml_setup("--help", Usage,
++"--help\n"
++"    Prints this message.\n\n"
++);
++
++static int __init uml_checksetup(char *line, int *add)
++{
++      struct uml_param *p;
++
++      p = &__uml_setup_start;
++      while(p < &__uml_setup_end) {
++              int n;
++
++              n = strlen(p->str);
++              if(!strncmp(line, p->str, n)){
++                      if (p->setup_func(line + n, add)) return 1;
++              }
++              p++;
++      }
++      return 0;
++}
++
++static void __init uml_postsetup(void)
++{
++      initcall_t *p;
++
++      p = &__uml_postsetup_start;
++      while(p < &__uml_postsetup_end){
++              (*p)();
++              p++;
++      }
++      return;
++}
++
++extern int debug_trace;
++unsigned long brk_start;
++
++static struct vm_reserved kernel_vm_reserved;
++
++int linux_main(int argc, char **argv)
++{
++      unsigned long avail;
++      unsigned long virtmem_size;
++      unsigned int i, add, err;
++      void *sp;
++
++      for (i = 1; i < argc; i++){
++              if((i == 1) && (argv[i][0] == ' ')) continue;
++              add = 1;
++              uml_checksetup(argv[i], &add);
++              if(add) add_arg(saved_command_line, argv[i]);
++      }
++      if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
++
++      if(!jail)
++              remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
++      remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
++      brk_start = (unsigned long) sbrk(0);
++      remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1);
++
++      uml_physmem = START;
++
++      /* Reserve up to 4M after the current brk */
++      uml_reserved = ROUND_4M(brk_start) + (1 << 22);
++
++      setup_machinename(system_utsname.machine);
++
++      argv1_begin = argv[1];
++      argv1_end = &argv[1][strlen(argv[1])];
++  
++      set_usable_vm(uml_physmem, get_kmem_end());
++      high_physmem = uml_physmem + physmem_size;
++      high_memory = (void *) high_physmem;
++      setup_physmem(uml_physmem, uml_reserved, physmem_size);
++
++      /* Kernel vm starts after physical memory and is either the size
++       * of physical memory or the remaining space left in the kernel
++       * area of the address space, whichever is smaller.
++       */
++
++      start_vm = VMALLOC_START;
++      if(start_vm >= get_kmem_end())
++              panic("Physical memory too large to allow any kernel "
++                    "virtual memory");
++
++      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)
++              printk(KERN_INFO "Kernel virtual memory size shrunk to %ld "
++                     "bytes\n", virtmem_size);
++
++      err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
++      if(err) panic("Failed to reserve VM area for kernel VM\n");
++
++      uml_postsetup();
++
++      init_task.thread.kernel_stack = (unsigned long) &init_task + 
++              2 * PAGE_SIZE;
++
++      task_protections((unsigned long) &init_task);
++      sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - 
++              sizeof(unsigned long);
++      return(signals(start_kernel_proc, sp));
++}
++
++static int panic_exit(struct notifier_block *self, unsigned long unused1,
++                    void *unused2)
++{
++#ifdef CONFIG_SYSRQ
++      handle_sysrq('p', &current->thread.regs, NULL, NULL);
++#endif
++      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();
++      strcpy(command_line, saved_command_line);
++      *cmdline_p = command_line;
++      setup_hostinfo();
++}
++
++void __init check_bugs(void)
++{
++      arch_check_bugs();
++      check_ptrace();
++      check_sigio();
++}
++
++spinlock_t pid_lock = SPIN_LOCK_UNLOCKED;
++
++void lock_pid(void)
++{
++      spin_lock(&pid_lock);
++}
++
++void unlock_pid(void)
++{
++      spin_unlock(&pid_lock);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/umid.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,302 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++#include <dirent.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/param.h>
++#include "user.h"
++#include "umid.h"
++#include "init.h"
++#include "os.h"
++
++#define UMID_LEN 64
++#define UML_DIR "~/.uml/"
++
++static char umid[UMID_LEN] = { 0 };
++static char *uml_dir = UML_DIR;
++
++static int umid_is_random = 1;
++static int umid_inited = 0;
++
++static int make_umid(void);
++
++static int __init set_umid(char *name, int *add)
++{
++      if(umid_inited){
++              printk("Unique machine name can't be set twice\n");
++              return(-1);
++      }
++
++      if(strlen(name) > UMID_LEN - 1)
++              printk("Unique machine name is being truncated to %s "
++                     "characters\n", UMID_LEN);
++      strncpy(umid, name, UMID_LEN - 1);
++      umid[UMID_LEN - 1] = '\0';
++
++      umid_is_random = 0;
++      umid_inited = 1;
++      return 0;
++}
++
++__uml_setup("umid=", set_umid,
++"umid=<name>\n"
++"    This is used to assign a unique identity to this UML machine and\n"
++"    is used for naming the pid file and management console socket.\n\n"
++);
++
++int __init umid_file_name(char *name, char *buf, int len)
++{
++      int n;
++
++      if(!umid_inited && make_umid()) return(-1);
++
++      n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
++      if(n > len){
++              printk("umid_file_name : buffer too short\n");
++              return(-1);
++      }
++
++      sprintf(buf, "%s%s/%s", uml_dir, umid, name);
++      return(0);
++}
++
++extern int tracing_pid;
++
++static int __init create_pid_file(void)
++{
++      char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
++      char pid[sizeof("nnnnn\0")];
++      int fd;
++
++      if(umid_file_name("pid", file, sizeof(file))) return 0;
++
++      fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
++                        0644);
++      if(fd < 0){
++              printk("Open of machine pid file \"%s\" failed - "
++                     "errno = %d\n", file, -fd);
++              return 0;
++      }
++
++      sprintf(pid, "%d\n", (tracing_pid == -1) ? os_getpid() : tracing_pid);
++      if(write(fd, pid, strlen(pid)) != strlen(pid))
++              printk("Write of pid file failed - errno = %d\n", errno);
++      close(fd);
++      return 0;
++}
++
++static int actually_do_remove(char *dir)
++{
++      DIR *directory;
++      struct dirent *ent;
++      int len;
++      char file[256];
++
++      if((directory = opendir(dir)) == NULL){
++              printk("actually_do_remove : couldn't open directory '%s', "
++                     "errno = %d\n", dir, errno);
++              return(1);
++      }
++      while((ent = readdir(directory)) != NULL){
++              if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
++                      continue;
++              len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
++              if(len > sizeof(file)){
++                      printk("Not deleting '%s' from '%s' - name too long\n",
++                             ent->d_name, dir);
++                      continue;
++              }
++              sprintf(file, "%s/%s", dir, ent->d_name);
++              if(unlink(file) < 0){
++                      printk("actually_do_remove : couldn't remove '%s' "
++                             "from '%s', errno = %d\n", ent->d_name, dir, 
++                             errno);
++                      return(1);
++              }
++      }
++      if(rmdir(dir) < 0){
++              printk("actually_do_remove : couldn't rmdir '%s', "
++                     "errno = %d\n", dir, errno);
++              return(1);
++      }
++      return(0);
++}
++
++void remove_umid_dir(void)
++{
++      char dir[strlen(uml_dir) + UMID_LEN + 1];
++      if(!umid_inited) return;
++
++      sprintf(dir, "%s%s", uml_dir, umid);
++      actually_do_remove(dir);
++}
++
++char *get_umid(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;
++
++      sprintf(file, "%s/pid", dir);
++      dead = 0;
++      if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){
++              if(fd != -ENOENT){
++                      printk("not_dead_yet : couldn't open pid file '%s', "
++                             "errno = %d\n", file, -fd);
++                      return(1);
++              }
++              dead = 1;
++      }
++      if(fd > 0){
++              if(read(fd, pid, sizeof(pid)) < 0){
++                      printk("not_dead_yet : couldn't read pid file '%s', "
++                             "errno = %d\n", file, errno);
++                      return(1);
++              }
++              p = strtoul(pid, &end, 0);
++              if(end == pid){
++                      printk("not_dead_yet : couldn't parse pid file '%s', "
++                             "errno = %d\n", file, errno);
++                      dead = 1;
++              }
++              if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
++                 (p == tracing_pid)) 
++                      dead = 1;
++      }
++      if(!dead) return(1);
++      return(actually_do_remove(dir));
++      return(0);
++}
++
++static int __init set_uml_dir(char *name, int *add)
++{
++      if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
++              uml_dir = malloc(strlen(name) + 1);
++              if(uml_dir == NULL){
++                      printk("Failed to malloc uml_dir - error = %d\n",
++                             errno);
++                      uml_dir = name;
++                      return(0);
++              }
++              sprintf(uml_dir, "%s/", name);
++      }
++      else uml_dir = name;
++      return 0;
++}
++
++static int __init make_uml_dir(void)
++{
++      char dir[MAXPATHLEN + 1] = { '\0' };
++      int len;
++
++      if(*uml_dir == '~'){
++              char *home = getenv("HOME");
++
++              if(home == NULL){
++                      printk("make_uml_dir : no value in environment for "
++                             "$HOME\n");
++                      exit(1);
++              }
++              strncpy(dir, home, sizeof(dir));
++              uml_dir++;
++      }
++      len = strlen(dir);
++      strncat(dir, uml_dir, sizeof(dir) - len);
++      len = strlen(dir);
++      if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
++              dir[len] = '/';
++              dir[len + 1] = '\0';
++      }
++
++      if((uml_dir = malloc(strlen(dir) + 1)) == NULL){
++              printf("make_uml_dir : malloc failed, errno = %d\n", errno);
++              exit(1);
++      }
++      strcpy(uml_dir, dir);
++      
++      if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
++              printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
++              return(-1);
++      }
++      return 0;
++}
++
++static int __init make_umid(void)
++{
++      int fd, err;
++      char tmp[strlen(uml_dir) + UMID_LEN + 1];
++
++      strncpy(tmp, uml_dir, sizeof(tmp) - 1);
++      tmp[sizeof(tmp) - 1] = '\0';
++
++      if(*umid == 0){
++              strcat(tmp, "XXXXXX");
++              fd = mkstemp(tmp);
++              if(fd < 0){
++                      printk("set_umid - mkstemp failed, errno = %d\n",
++                             errno);
++                      return(1);
++              }
++
++              close(fd);
++              /* There's a nice tiny little race between this unlink and
++               * the mkdir below.  It'd be nice if there were a mkstemp
++               * for directories.
++               */
++              unlink(tmp);
++              strcpy(umid, &tmp[strlen(uml_dir)]);
++      }
++      
++      sprintf(tmp, "%s%s", uml_dir, umid);
++
++      if((err = mkdir(tmp, 0777)) < 0){
++              if(errno == EEXIST){
++                      if(not_dead_yet(tmp)){
++                              printk("umid '%s' is in use\n", umid);
++                              return(-1);
++                      }
++                      err = mkdir(tmp, 0777);
++              }
++      }
++      if(err < 0){
++              printk("Failed to create %s - errno = %d\n", umid, errno);
++              return(-1);
++      }
++
++      return(0);
++}
++
++__uml_setup("uml_dir=", set_uml_dir,
++"uml_dir=<directory>\n"
++"    The location to place the pid and umid files.\n\n"
++);
++
++__uml_postsetup(make_uml_dir);
++__uml_postsetup(make_umid);
++__uml_postsetup(create_pid_file);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/unmap.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <errno.h>
++#include <sys/mman.h>
++#include "user.h"
++
++int switcheroo(int fd, int prot, void *from, void *to, int size)
++{
++      if(munmap(to, size) < 0){
++              return(-1);
++      }
++      if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
++              return(-1);
++      }
++      if(munmap(from, size) < 0){
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/user_syms.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,116 @@
++#include <stdio.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <errno.h>
++#include <utime.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/vfs.h>
++#include <sys/ioctl.h>
++#include "user_util.h"
++#include "mem_user.h"
++
++/* XXX All the __CONFIG_* stuff is broken because this file can't include
++ * config.h
++ */
++
++/* Had to steal this from linux/module.h because that file can't be included
++ * since this includes various user-level headers.
++ */
++
++struct module_symbol
++{
++      unsigned long value;
++      const char *name;
++};
++
++/* Indirect stringification.  */
++
++#define __MODULE_STRING_1(x)  #x
++#define __MODULE_STRING(x)    __MODULE_STRING_1(x)
++
++#if !defined(__AUTOCONF_INCLUDED__)
++
++#define __EXPORT_SYMBOL(sym,str)   error config_must_be_included_before_module
++#define EXPORT_SYMBOL(var)       error config_must_be_included_before_module
++#define EXPORT_SYMBOL_NOVERS(var)  error config_must_be_included_before_module
++
++#elif !defined(__CONFIG_MODULES__)
++
++#define __EXPORT_SYMBOL(sym,str)
++#define EXPORT_SYMBOL(var)
++#define EXPORT_SYMBOL_NOVERS(var)
++
++#else
++
++#define __EXPORT_SYMBOL(sym, str)                     \
++const char __kstrtab_##sym[]                          \
++__attribute__((section(".kstrtab"))) = str;           \
++const struct module_symbol __ksymtab_##sym            \
++__attribute__((section("__ksymtab"))) =                       \
++{ (unsigned long)&sym, __kstrtab_##sym }
++
++#if defined(__MODVERSIONS__) || !defined(__CONFIG_MODVERSIONS__)
++#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
++#else
++#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
++#endif
++
++#define EXPORT_SYMBOL_NOVERS(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
++
++#endif
++
++EXPORT_SYMBOL(__errno_location);
++
++EXPORT_SYMBOL(access);
++EXPORT_SYMBOL(open);
++EXPORT_SYMBOL(open64);
++EXPORT_SYMBOL(close);
++EXPORT_SYMBOL(read);
++EXPORT_SYMBOL(write);
++EXPORT_SYMBOL(dup2);
++EXPORT_SYMBOL(__xstat);
++EXPORT_SYMBOL(__lxstat);
++EXPORT_SYMBOL(__lxstat64);
++EXPORT_SYMBOL(lseek);
++EXPORT_SYMBOL(lseek64);
++EXPORT_SYMBOL(chown);
++EXPORT_SYMBOL(truncate);
++EXPORT_SYMBOL(utime);
++EXPORT_SYMBOL(chmod);
++EXPORT_SYMBOL(rename);
++EXPORT_SYMBOL(__xmknod);
++
++EXPORT_SYMBOL(symlink);
++EXPORT_SYMBOL(link);
++EXPORT_SYMBOL(unlink);
++EXPORT_SYMBOL(readlink);
++
++EXPORT_SYMBOL(mkdir);
++EXPORT_SYMBOL(rmdir);
++EXPORT_SYMBOL(opendir);
++EXPORT_SYMBOL(readdir);
++EXPORT_SYMBOL(closedir);
++EXPORT_SYMBOL(seekdir);
++EXPORT_SYMBOL(telldir);
++
++EXPORT_SYMBOL(ioctl);
++
++extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
++                      __off64_t __offset);
++extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n,
++                       __off64_t __offset);
++EXPORT_SYMBOL(pread64);
++EXPORT_SYMBOL(pwrite64);
++
++EXPORT_SYMBOL(statfs);
++EXPORT_SYMBOL(statfs64);
++
++EXPORT_SYMBOL(memcpy);
++EXPORT_SYMBOL(getuid);
++
++EXPORT_SYMBOL(memset);
++EXPORT_SYMBOL(strstr);
++
++EXPORT_SYMBOL(find_iomem);
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/kernel/user_util.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,275 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <limits.h>
++#include <sys/mman.h> 
++#include <sys/stat.h>
++#include <sys/ptrace.h>
++#include <sys/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"
++
++#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
++
++char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
++char command_line[COMMAND_LINE_SIZE] = { 0 };
++
++void add_arg(char *cmd_line, char *arg)
++{
++      if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
++              printf("add_arg: Too much command line!\n");
++              exit(1);
++      }
++      if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
++      strcat(cmd_line, arg);
++}
++
++void remap_data(void *segment_start, void *segment_end, int w)
++{
++      void *addr;
++      unsigned long size;
++      int data, prot;
++
++      if(w) prot = PROT_WRITE;
++      else prot = 0;
++      prot |= PROT_READ | PROT_EXEC;
++      size = (unsigned long) segment_end - 
++              (unsigned long) segment_start;
++      data = create_mem_file(size);
++      if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, 
++                      MAP_SHARED, data, 0)) < 0){
++              perror("mapping new data segment");
++              exit(1);
++      }
++      memcpy(addr, segment_start, size);
++      if(switcheroo(data, prot, addr, segment_start, 
++                    size) < 0){
++              printf("switcheroo failed\n");
++              exit(1);
++      }
++}
++
++void stop(void)
++{
++      while(1) sleep(1000000);
++}
++
++void stack_protections(unsigned long address)
++{
++      int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++
++        if(mprotect((void *) address, page_size(), prot) < 0)
++              panic("protecting stack failed, errno = %d", errno);
++}
++
++void task_protections(unsigned long address)
++{
++      unsigned long guard = address + page_size();
++      unsigned long stack = guard + page_size();
++      int prot = 0;
++
++      if(mprotect((void *) stack, page_size(), prot) < 0)
++              panic("protecting guard page failed, errno = %d", errno);
++      prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++      if(mprotect((void *) stack, 2 * page_size(), prot) < 0)
++              panic("protecting stack failed, errno = %d", errno);
++}
++
++int wait_for_stop(int pid, int sig, int cont_type, void *relay)
++{
++      sigset_t *relay_signals = relay;
++      int status, ret;
++
++      while(1){
++              if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) ||
++                 !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
++                      if(ret < 0){
++                              if(errno == EINTR) continue;
++                              printk("wait failed, errno = %d\n",
++                                     errno);
++                      }
++                      else if(WIFEXITED(status)) 
++                              printk("process exited with status %d\n", 
++                                     WEXITSTATUS(status));
++                      else if(WIFSIGNALED(status))
++                              printk("process exited with signal %d\n", 
++                                     WTERMSIG(status));
++                      else if((WSTOPSIG(status) == SIGVTALRM) ||
++                              (WSTOPSIG(status) == SIGALRM) ||
++                              (WSTOPSIG(status) == SIGIO) ||
++                              (WSTOPSIG(status) == SIGPROF) ||
++                              (WSTOPSIG(status) == SIGCHLD) ||
++                              (WSTOPSIG(status) == SIGWINCH) ||
++                              (WSTOPSIG(status) == SIGINT)){
++                              ptrace(cont_type, pid, 0, WSTOPSIG(status));
++                              continue;
++                      }
++                      else if((relay_signals != NULL) &&
++                              sigismember(relay_signals, WSTOPSIG(status))){
++                              ptrace(cont_type, pid, 0, WSTOPSIG(status));
++                              continue;
++                      }
++                      else printk("process stopped with signal %d\n", 
++                                  WSTOPSIG(status));
++                      panic("wait_for_stop failed to wait for %d to stop "
++                            "with %d\n", pid, sig);
++              }
++              return(status);
++      }
++}
++
++int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
++{
++      int pid;
++
++      pid = clone(fn, sp, flags, arg);
++      if(pid < 0) return(-1);
++      wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
++      ptrace(PTRACE_CONT, pid, 0, 0);
++      return(pid);
++}
++
++int raw(int fd, int complain)
++{
++      struct termios tt;
++      int err;
++
++      tcgetattr(fd, &tt);
++      cfmakeraw(&tt);
++      err = tcsetattr(fd, TCSANOW, &tt);
++      if((err < 0) && complain){
++              printk("tcsetattr failed, errno = %d\n", errno);
++              return(-errno);
++      }
++      return(0);
++}
++
++void setup_machinename(char *machine_out)
++{
++      struct utsname host;
++
++      uname(&host);
++      strcpy(machine_out, host.machine);
++}
++
++char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
++
++void setup_hostinfo(void)
++{
++      struct utsname host;
++
++      uname(&host);
++      sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
++              host.release, host.version, host.machine);
++}
++
++void close_fd(int fd)
++{
++      close(fd);
++}
++
++char *tempdir = NULL;
++
++static void __init find_tempdir(void)
++{
++      char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
++      int i;
++      char *dir = NULL;
++
++      if(tempdir != NULL) return;     /* We've already been called */
++      for(i = 0; dirs[i]; i++){
++              dir = getenv(dirs[i]);
++              if(dir != NULL) break;
++      }
++      if(dir == NULL) dir = "/tmp";
++      else if(*dir == '\0') dir = NULL;
++      if(dir != NULL) {
++              tempdir = malloc(strlen(dir) + 2);
++              if(tempdir == NULL){
++                      fprintf(stderr, "Failed to malloc tempdir, "
++                              "errno = %d\n", errno);
++                      return;
++              }
++              strcpy(tempdir, dir);
++              strcat(tempdir, "/");
++      }
++}
++
++int make_tempfile(const char *template, char **out_tempname, int do_unlink)
++{
++      char tempname[MAXPATHLEN];
++      int fd;
++
++      find_tempdir();
++      if (*template != '/')
++              strcpy(tempname, tempdir);
++      else
++              *tempname = 0;
++      strcat(tempname, template);
++      if((fd = mkstemp(tempname)) < 0){
++              fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
++                      strerror(errno));
++              return -1;
++      }
++      if(do_unlink && (unlink(tempname) < 0)){
++              perror("unlink");
++              return -1;
++      }
++      if(out_tempname){
++              if((*out_tempname = strdup(tempname)) == NULL){
++                      perror("strdup");
++                      return -1;
++              }
++      }
++      return(fd);
++}
++
++int user_read(int fd, char *buf, int len)
++{
++      int err;
++
++      err = read(fd, buf, len);
++      if(err < 0) return(-errno);
++      else return(err);
++}
++
++int user_write(int fd, char *buf, int len)
++{
++      int err;
++
++      err = write(fd, buf, len);
++      if(err < 0) return(-errno);
++      else return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/link.ld.in   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,144 @@
++OUTPUT_FORMAT("ELF_FORMAT")
++OUTPUT_ARCH(ELF_ARCH)
++ENTRY(_start)
++jiffies = jiffies_64;
++SECTIONS
++{
++  . = START() + SIZEOF_HEADERS;
++
++  . = ALIGN(4096);
++  __binary_start = .;
++  .thread_private : {
++    __start_thread_private = .;
++    errno = .;
++    . += 4;
++    arch/um/kernel/unmap_fin.o (.data)
++    __end_thread_private = .;
++  }
++  . = ALIGN(4096);
++  .remap : { arch/um/kernel/unmap_fin.o (.text) }
++
++  . = ALIGN(4096);            /* Init code and data */
++  _stext = .;
++  __init_begin = .;
++  .text.init : { *(.text.init) }
++  . = ALIGN(4096);
++  .text      :
++  {
++    *(.text)
++    /* .gnu.warning sections are handled specially by elf32.em.  */
++    *(.gnu.warning)
++    *(.gnu.linkonce.t*)
++  }
++  .kstrtab : { *(.kstrtab) }
++
++  . = ALIGN(16);              /* Exception table */
++  __start___ex_table = .;
++  __ex_table : { *(__ex_table) }
++  __stop___ex_table = .;
++
++  __start___ksymtab = .;      /* Kernel symbol table */
++  __ksymtab : { *(__ksymtab) }
++  __stop___ksymtab = .;
++  .fini      : { *(.fini)    } =0x9090
++  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
++  .rodata1   : { *(.rodata1) }
++  _etext = .;
++  PROVIDE (etext = .);
++
++  . = ALIGN(4096);
++  PROVIDE (_sdata = .);
++
++  .unprotected : { *(.unprotected) }
++  . = ALIGN(4096);
++  PROVIDE (_unprotected_end = .);
++
++  . = ALIGN(4096);
++  __uml_setup_start = .;
++  .uml.setup.init : { *(.uml.setup.init) }
++  __uml_setup_end = .;
++  __uml_help_start = .;
++  .uml.help.init : { *(.uml.help.init) }
++  __uml_help_end = .;
++  __uml_postsetup_start = .;
++  .uml.postsetup.init : { *(.uml.postsetup.init) }
++  __uml_postsetup_end = .;
++  __setup_start = .;
++  .setup.init : { *(.setup.init) }
++  __setup_end = .;
++  __initcall_start = .;
++  .initcall.init : { *(.initcall.init) }
++  __initcall_end = .;
++  __uml_initcall_start = .;
++  .uml.initcall.init : { *(.uml.initcall.init) }
++  __uml_initcall_end = .;
++  __init_end = .;
++  __exitcall_begin = .;
++  .exitcall : { *(.exitcall.exit) }
++  __exitcall_end = .;
++  __uml_exitcall_begin = .;
++  .uml.exitcall : { *(.uml.exitcall.exit) }
++  __uml_exitcall_end = .;
++
++  __preinit_array_start = .;
++  .preinit_array : { *(.preinit_array) }
++  __preinit_array_end = .;
++  __init_array_start = .;
++  .init_array : { *(.init_array) }
++  __init_array_end = .;
++  __fini_array_start = .;
++  .fini_array : { *(.fini_array) }
++  __fini_array_end = .;
++
++  .data.init : { *(.data.init) }
++  .data    :
++  {
++    . = ALIGN(16384);         /* init_task */
++    *(.data.init_task)
++    *(.data)
++    *(.gnu.linkonce.d*)
++    CONSTRUCTORS
++  }
++  .data1   : { *(.data1) }
++  .ctors         :
++  {
++    *(.ctors)
++  }
++  .dtors         :
++  {
++    *(.dtors)
++  }
++
++  .got           : { *(.got.plt) *(.got) }
++  .dynamic       : { *(.dynamic) }
++  /* We want the small data sections together, so single-instruction offsets
++     can access them all, and initialized data all before uninitialized, so
++     we can shorten the on-disk segment size.  */
++  .sdata     : { *(.sdata) }
++  _edata  =  .;
++  PROVIDE (edata = .);
++  . = ALIGN(0x1000);
++  .sbss      : 
++  {
++   __bss_start = .;
++   PROVIDE(_bss_start = .);
++   *(.sbss) 
++   *(.scommon) 
++  }
++  .bss       :
++  {
++   *(.dynbss)
++   *(.bss)
++   *(COMMON)
++  }
++  _end = . ;
++  PROVIDE (end = .);
++  /* Stabs debugging sections.  */
++  .stab 0 : { *(.stab) }
++  .stabstr 0 : { *(.stabstr) }
++  .stab.excl 0 : { *(.stab.excl) }
++  .stab.exclstr 0 : { *(.stab.exclstr) }
++  .stab.index 0 : { *(.stab.index) }
++  .stab.indexstr 0 : { *(.stab.indexstr) }
++  .comment 0 : { *(.comment) }
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/main.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,217 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h> 
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/resource.h>
++#include <sys/mman.h>
++#include <sys/user.h>
++#include <asm/page.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "user.h"
++#include "init.h"
++
++unsigned long stacksizelim;
++
++char *linux_prog;
++
++#define PGD_BOUND (4 * 1024 * 1024)
++#define STACKSIZE (8 * 1024 * 1024)
++#define THREAD_NAME_LEN (256)
++
++char padding[THREAD_NAME_LEN] = { [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' };
++
++static void set_stklim(void)
++{
++      struct rlimit lim;
++
++      if(getrlimit(RLIMIT_STACK, &lim) < 0){
++              perror("getrlimit");
++              exit(1);
++      }
++      if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
++              lim.rlim_cur = STACKSIZE;
++              if(setrlimit(RLIMIT_STACK, &lim) < 0){
++                      perror("setrlimit");
++                      exit(1);
++              }
++      }
++      stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
++}
++
++static __init void do_uml_initcalls(void)
++{
++      initcall_t *call;
++
++      call = &__uml_initcall_start;
++      while (call < &__uml_initcall_end){;
++              (*call)();
++              call++;
++      }
++}
++
++extern int uml_exitcode;
++
++int main(int argc, char **argv, char **envp)
++{
++      sigset_t mask;
++      int ret, i;
++      char **new_argv;
++
++      /* Enable all signals - in some environments, we can enter with
++       * some signals blocked
++       */
++
++      sigemptyset(&mask);
++      if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
++              perror("sigprocmask");
++              exit(1);
++      }
++
++      /* Allocate memory for thread command lines */
++      if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
++              new_argv = malloc((argc + 2) * sizeof(char*));
++              if(!new_argv) {
++                      perror("Allocating extended argv");
++                      exit(1);
++              }       
++              
++              new_argv[0] = argv[0];
++              new_argv[1] = padding;
++              
++              for(i = 2; i <= argc; i++)
++                      new_argv[i] = argv[i - 1];
++              new_argv[argc + 1] = NULL;
++              
++#ifdef PROFILING
++              disable_profile_timer();
++#endif
++              execvp(new_argv[0], new_argv);
++              perror("execing with extended args");
++              exit(1);
++      }       
++
++      linux_prog = argv[0];
++
++      set_stklim();
++      set_task_sizes(0);
++
++      if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
++              perror("Mallocing argv");
++              exit(1);
++      }
++      for(i=0;i<argc;i++){
++              if((new_argv[i] = strdup(argv[i])) == NULL){
++                      perror("Mallocing an arg");
++                      exit(1);
++              }
++      }
++      new_argv[argc] = NULL;
++
++      do_uml_initcalls();
++      ret = linux_main(argc, argv);
++      
++      /* Reboot */
++      if(ret){
++              printf("\n");
++              execvp(new_argv[0], new_argv);
++              perror("Failed to exec kernel");
++              ret = 1;
++      }
++      printf("\n");
++      return(uml_exitcode);
++}
++
++int allocating_monbuf = 0;
++
++#ifdef PROFILING
++extern void __real___monstartup (unsigned long, unsigned long);
++
++void __wrap___monstartup (unsigned long lowpc, unsigned long highpc)
++{
++      allocating_monbuf = 1;
++      __real___monstartup(lowpc, highpc);
++      allocating_monbuf = 0;
++      get_profile_timer();
++}
++#endif
++
++extern void *__real_malloc(int);
++extern unsigned long host_task_size;
++
++static void *gmon_buf = NULL;
++
++void *__wrap_malloc(int size)
++{
++      if(allocating_monbuf){
++              unsigned long start, end;
++              int fd;
++
++              /* Turn this off now in case create_mem_file tries allocating
++               * memory
++               */
++              allocating_monbuf = 0;
++              fd = create_mem_file(size);
++
++              /* Calculate this here because linux_main hasn't run yet
++               * and host_task_size figures in STACK_TOP, which figures
++               * in kmem_end.
++               */
++              set_task_sizes(0);
++
++              /* Same with stacksizelim */
++              set_stklim();
++
++              end = get_kmem_end();
++              start = (end - size) & PAGE_MASK;
++              gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE,
++                          MAP_SHARED | MAP_FIXED, fd, 0);
++              if(gmon_buf != (void *) start){
++                      perror("Creating gprof buffer");
++                      exit(1);
++              }
++              set_kmem_end(start);
++              return(gmon_buf);
++      }
++      if(kmalloc_ok) return(um_kmalloc(size));
++      else return(__real_malloc(size));
++}
++
++void *__wrap_calloc(int n, int size)
++{
++      void *ptr = __wrap_malloc(n * size);
++
++      if(ptr == NULL) return(NULL);
++      memset(ptr, 0, n * size);
++      return(ptr);
++}
++
++extern void __real_free(void *);
++
++void __wrap_free(void *ptr)
++{
++      /* Could maybe unmap the gmon buffer, but we're just about to
++       * exit anyway
++       */
++      if(ptr == gmon_buf) return;
++      if(kmalloc_ok) kfree(ptr);
++      else __real_free(ptr);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/Makefile     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,136 @@
++ARCH_DIR = arch/um
++OS := $(shell uname -s)
++
++include $(ARCH_DIR)/Makefile-$(SUBARCH)
++include $(ARCH_DIR)/Makefile-os-$(OS)
++
++EXTRAVERSION := $(EXTRAVERSION)-53um
++include/linux/version.h: arch/$(ARCH)/Makefile
++
++# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE)
++# The way the toplevel Makefile is written EXTRAVERSION is not supposed
++# to be changed outside the toplevel Makefile, but recalculating MODLIB is
++# a sufficient workaround until we no longer need architecture dependent
++# EXTRAVERSION...
++MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
++
++MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot
++
++ifeq ($(CONFIG_DEBUGSYM),y)
++DEBUG = -g
++CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
++endif
++
++ifeq ($(CONFIG_GCOV),y)
++CFLAGS += -fprofile-arcs -ftest-coverage
++endif
++
++ifeq ($(CONFIG_GPROF), y)
++PROFILE += -pg -DPROFILING
++LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
++endif
++
++ARCH_SUBDIRS = $(ARCH_DIR)/fs $(ARCH_DIR)/drivers $(ARCH_DIR)/kernel \
++      $(ARCH_DIR)/sys-$(SUBARCH) $(ARCH_DIR)/os-$(OS)
++
++SUBDIRS += $(ARCH_SUBDIRS)
++
++LIBS += $(shell [ -e $(ARCH_DIR)/fs/fs.o ] && echo $(ARCH_DIR)/fs/fs.o) \
++      $(ARCH_DIR)/kernel/um.o $(ARCH_DIR)/drivers/drivers.o \
++      $(ARCH_DIR)/sys-$(SUBARCH)/sys.o $(ARCH_DIR)/os/os.o
++
++ifeq ($(CONFIG_PT_PROXY), y)
++SUBDIRS += $(ARCH_DIR)/ptproxy
++LIBS += $(ARCH_DIR)/ptproxy/ptproxy.a
++endif
++
++ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
++
++# -Derrno=kernel_errno - This turns all kernel references to errno into
++# kernel_errno to separate them from the libc errno.  This allows -fno-common
++# in CFLAGS.  Otherwise, it would cause ld to complain about the two different
++# errnos.
++
++CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \
++      -DSUBARCH=\"$(SUBARCH)\" -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) \
++      -Derrno=kernel_errno
++
++LINKFLAGS += -r
++
++LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
++
++SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
++
++$(ARCH_DIR)/link.ld: $(ARCH_DIR)/link.ld.in
++      m4 -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
++              -DELF_FORMAT=$(ELF_FORMAT) $< > $@
++
++SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
++      include/asm-um/sigcontext.h include/asm-um/processor.h \
++      include/asm-um/ptrace.h include/asm-um/arch-signal.h
++
++ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
++      $(SYMLINK_HEADERS)
++
++GEN_HEADERS = $(ARCH_DIR)/include/task.h
++
++linux: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) $(ARCH_DIR)/main.o \
++      vmlinux $(ARCH_DIR)/link.ld
++      mv vmlinux vmlinux.o
++      $(CC) -Wl,-T,$(ARCH_DIR)/link.ld $(LINK_PROFILE) $(LINK_WRAPS) \
++              -o linux -static $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib -lutil
++
++USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
++USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
++USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
++
++# To get a definition of F_SETSIG
++USER_CFLAGS += -D_GNU_SOURCE
++
++$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++archmrproper:
++      for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
++      do \
++              $(MAKE) -C $$d archmrproper; \
++      done
++      rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
++              $(ARCH_DIR)/link.ld \
++              $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
++
++archclean: sysclean
++      for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
++      do \
++              $(MAKE) -C $$d clean; \
++      done
++      find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
++              -o -name '*.gcov' \) -type f -print | xargs rm -f
++      rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
++      @$(MAKEBOOT) clean
++
++archdep: 
++      for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done
++      @$(MAKEBOOT) dep
++
++$(SYMLINK_HEADERS):
++      cd $(TOPDIR)/$(dir $@) ; \
++      ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
++
++include/asm-um/arch:
++      cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
++
++arch/um/include/sysdep:
++      cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
++
++arch/um/os:
++      cd $(ARCH_DIR) && ln -sf os-$(OS) os
++
++$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
++      $< > $@
++
++$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
++      $(ARCH_DIR)/util/mk_task_kern.c 
++      $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util all
++
++export SUBARCH USER_CFLAGS OS
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/Makefile-i386        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,30 @@
++ifeq ($(CONFIG_HOST_2G_2G), y)
++TOP_ADDR = 0x80000000
++else
++TOP_ADDR = 0xc0000000
++endif
++
++ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) -DUM_FASTCALL
++ELF_ARCH = $(SUBARCH)
++ELF_FORMAT = elf32-$(SUBARCH)
++
++SYS_HEADERS = $(ARCH_DIR)/include/sysdep-i386/sc.h \
++      $(ARCH_DIR)/include/sysdep-i386/thread.h
++
++$(ARCH_DIR)/include/sysdep-i386/sc.h : $(ARCH_DIR)/sys-i386/util/mk_sc
++      $(ARCH_DIR)/sys-i386/util/mk_sc > $@
++
++$(ARCH_DIR)/include/sysdep-i386/thread.h : $(ARCH_DIR)/sys-i386/util/mk_thread
++      $(ARCH_DIR)/sys-i386/util/mk_thread > $@
++
++$(ARCH_DIR)/sys-i386/util/mk_sc : $(ARCH_DIR)/sys-i386/util/mk_sc.c
++      $(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_sc
++
++$(ARCH_DIR)/sys-i386/util/mk_thread : \
++      $(ARCH_DIR)/sys-i386/util/mk_thread_user.c \
++      $(ARCH_DIR)/sys-i386/util/mk_thread_kern.c
++      $(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_thread
++
++sysclean :
++      rm -f $(SYS_HEADERS)
++      make -C $(ARCH_DIR)/sys-i386/util clean
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/Makefile-ia64        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1 @@
++START_ADDR = 0x1000000000000000
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/Makefile-os-Linux    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,7 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers
++LIBS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/Makefile-ppc 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,9 @@
++ifeq ($(CONFIG_HOST_2G_2G), y)
++START_ADDR = 0x80000000
++else
++START_ADDR = 0xc0000000
++endif
++ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
++
++# The arch is ppc, but the elf32 name is powerpc
++ELF_SUBARCH = powerpc
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/etap.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct ethertap_data {
++      char *dev_name;
++      char *gate_addr;
++      int data_fd;
++      int control_fd;
++      void *dev;
++};
++
++extern struct net_user_info ethertap_user_info;
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/etap_kern.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,24 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_ETHERTAP_KERN_H
++#define __UM_ETHERTAP_KERN_H
++
++#include "net_kern.h"
++
++extern int ethertap_setup(char *arg, struct uml_net *dev);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/ethertap_kern.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/init.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "etap.h"
++#include "etap_kern.h"
++
++struct ethertap_setup {
++      char *dev_name;
++      char *gate_addr;
++};
++
++struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = { 
++      [ 0 ... MAX_UML_NETDEV - 1 ] =
++      {
++              dev_name:       NULL,
++              gate_addr:      NULL,
++      }
++};
++
++struct net_device *etap_init(int private_size, int index)
++{
++      struct net_device *dev;
++      struct uml_net_private *pri;
++      struct ethertap_data *epri;
++
++      dev = init_etherdev(NULL, private_size);
++      if(dev == NULL) return(NULL);
++      pri = dev->priv;
++      epri = (struct ethertap_data *) pri->user;
++      epri->dev_name = ethertap_priv[index].dev_name;
++      epri->gate_addr = ethertap_priv[index].gate_addr;
++      printk("ethertap backend - %s", epri->dev_name);
++      if(epri->gate_addr != NULL) 
++              printk(", IP = %s", epri->gate_addr);
++      printk("\n");
++      epri->data_fd = -1;
++      epri->control_fd = -1;
++      return(dev);
++}
++
++static unsigned short etap_protocol(struct sk_buff *skb)
++{
++      return(eth_type_trans(skb, skb->dev));
++}
++
++static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      int len;
++
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
++      if(*skb == NULL) return(-ENOMEM);
++      len = net_recvfrom(fd, (*skb)->mac.raw, 
++                         (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
++      if(len <= 0) return(len);
++      skb_pull(*skb, 2);
++      len -= 2;
++      return(len);
++}
++
++static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      if(skb_headroom(*skb) < 2){
++              struct sk_buff *skb2;
++
++              skb2 = skb_realloc_headroom(*skb, 2);
++              dev_kfree_skb(*skb);
++              if (skb2 == NULL) return(-ENOMEM);
++              *skb = skb2;
++      }
++      skb_push(*skb, 2);
++      return(net_send(fd, (*skb)->data, (*skb)->len));
++}
++
++struct net_kern_info ethertap_kern_info = {
++      init:                   etap_init,
++      protocol:               etap_protocol,
++      read:                   etap_read,
++      write:                  etap_write,
++};
++
++static int ethertap_count = 0;
++
++int ethertap_setup(char *str, struct uml_net *dev)
++{
++      struct ethertap_setup *pri;
++      int err;
++
++      pri = &ethertap_priv[ethertap_count];
++      err = tap_setup_common(str, "ethertap", &pri->dev_name, dev->mac,
++                             &dev->have_mac, &pri->gate_addr);
++      if(err) return(err);
++      if(pri->dev_name == NULL){
++              printk("ethertap_setup : Missing tap device name\n");
++              return(1);
++      }
++
++      dev->user = &ethertap_user_info;
++      dev->kern = &ethertap_kern_info;
++      dev->private_size = sizeof(struct ethertap_data);
++      dev->transport_index = ethertap_count++;
++      return(0);
++}
++
++static struct transport ethertap_transport = {
++      list :  LIST_HEAD_INIT(ethertap_transport.list),
++      name :  "ethertap",
++      setup : ethertap_setup
++};
++
++static int register_ethertap(void)
++{
++      register_transport(&ethertap_transport);
++      return(1);
++}
++
++__initcall(register_ethertap);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/ethertap_user.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <sys/errno.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++#include <sys/un.h>
++#include <net/if.h>
++#include "user.h"
++#include "kern_util.h"
++#include "net_user.h"
++#include "etap.h"
++#include "helper.h"
++#include "os.h"
++
++#define MAX_PACKET ETH_MAX_PACKET
++
++void etap_user_init(void *data, void *dev)
++{
++      struct ethertap_data *pri = data;
++
++      pri->dev = dev;
++}
++
++struct addr_change {
++      enum { ADD_ADDR, DEL_ADDR } what;
++      unsigned char addr[4];
++      unsigned char netmask[4];
++};
++
++static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
++                      int fd)
++{
++      struct addr_change change;
++      void *output;
++
++      change.what = op;
++      memcpy(change.addr, addr, sizeof(change.addr));
++      memcpy(change.netmask, netmask, sizeof(change.netmask));
++      if(write(fd, &change, sizeof(change)) != sizeof(change))
++              printk("etap_change - request failed, errno = %d\n",
++                     errno);
++      output = um_kmalloc(page_size());
++      if(output == NULL)
++              printk("etap_change : Failed to allocate output buffer\n");
++      read_output(fd, output, page_size());
++      if(output != NULL){
++              printk("%s", output);
++              kfree(output);
++      }
++}
++
++static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
++                         void *arg)
++{
++      etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
++}
++
++static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
++                          void *arg)
++{
++      etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
++}
++
++struct etap_pre_exec_data {
++      int control_remote;
++      int control_me;
++      int data_me;
++};
++
++static void etap_pre_exec(void *arg)
++{
++      struct etap_pre_exec_data *data = arg;
++
++      dup2(data->control_remote, 1);
++      close(data->data_me);
++      close(data->control_me);
++}
++
++static int etap_tramp(char *dev, char *gate, int control_me, 
++                    int control_remote, int data_me, int data_remote)
++{
++      struct etap_pre_exec_data pe_data;
++      int pid, status, err;
++      char version_buf[sizeof("nnnnn\0")];
++      char data_fd_buf[sizeof("nnnnnn\0")];
++      char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
++      char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
++                             data_fd_buf, gate_buf, NULL };
++      char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 
++                               dev, data_fd_buf, NULL };
++      char **args, c;
++
++      sprintf(data_fd_buf, "%d", data_remote);
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++      if(gate != NULL){
++              strcpy(gate_buf, gate);
++              args = setup_args;
++      }
++      else args = nosetup_args;
++
++      err = 0;
++      pe_data.control_remote = control_remote;
++      pe_data.control_me = control_me;
++      pe_data.data_me = data_me;
++      pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
++
++      if(pid < 0) err = errno;
++      close(data_remote);
++      close(control_remote);
++      if(read(control_me, &c, sizeof(c)) != sizeof(c)){
++              printk("etap_tramp : read of status failed, errno = %d\n",
++                     errno);
++              return(EINVAL);
++      }
++      if(c != 1){
++              printk("etap_tramp : uml_net failed\n");
++              err = EINVAL;
++              if(waitpid(pid, &status, 0) < 0) err = errno;
++              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){
++                      printk("uml_net didn't exit with status 1\n");
++              }
++      }
++      return(err);
++}
++
++static int etap_open(void *data)
++{
++      struct ethertap_data *pri = data;
++      char *output;
++      int data_fds[2], control_fds[2], err, output_len;
++
++      err = tap_open_common(pri->dev, pri->gate_addr);
++      if(err) return(err);
++
++      err = os_pipe(data_fds, 0, 0);
++      if(err){
++              printk("data os_pipe failed - errno = %d\n", -err);
++              return(err);
++      }
++
++      err = os_pipe(control_fds, 1, 0);
++      if(err){
++              printk("control os_pipe failed - errno = %d\n", -err);
++              return(err);
++      }
++      
++      err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 
++                       control_fds[1], data_fds[0], data_fds[1]);
++      output_len = page_size();
++      output = um_kmalloc(output_len);
++      read_output(control_fds[0], output, output_len);
++
++      if(output == NULL)
++              printk("etap_open : failed to allocate output buffer\n");
++      else {
++              printk("%s", output);
++              kfree(output);
++      }
++
++      if(err != 0){
++              printk("etap_tramp failed - errno = %d\n", err);
++              return(-err);
++      }
++
++      pri->data_fd = data_fds[0];
++      pri->control_fd = control_fds[0];
++      iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
++      return(data_fds[0]);
++}
++
++static void etap_close(int fd, void *data)
++{
++      struct ethertap_data *pri = data;
++
++      iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
++      close(fd);
++      os_shutdown_socket(pri->data_fd, 1, 1);
++      close(pri->data_fd);
++      pri->data_fd = -1;
++      close(pri->control_fd);
++      pri->control_fd = -1;
++}
++
++static int etap_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
++                        void *data)
++{
++      struct ethertap_data *pri = data;
++
++      tap_check_ips(pri->gate_addr, addr);
++      if(pri->control_fd == -1) return;
++      etap_open_addr(addr, netmask, &pri->control_fd);
++}
++
++static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 
++                        void *data)
++{
++      struct ethertap_data *pri = data;
++
++      if(pri->control_fd == -1) return;
++      etap_close_addr(addr, netmask, &pri->control_fd);
++}
++
++struct net_user_info ethertap_user_info = {
++      init:           etap_user_init,
++      open:           etap_open,
++      close:          etap_close,
++      remove:         NULL,
++      set_mtu:        etap_set_mtu,
++      add_address:    etap_add_addr,
++      delete_address: etap_del_addr,
++      max_packet:     MAX_PACKET - ETH_HEADER_ETHERTAP
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/Makefile    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,31 @@
++# 
++# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := drivers.o
++
++list-multi := tuntap.o ethertap.o
++
++ethertap-objs := ethertap_kern.o ethertap_user.o
++tuntap-objs := tuntap_kern.o tuntap_user.o
++
++obj-y = 
++obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
++obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
++
++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
++
++USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++ethertap.o : $(ethertap-objs)
++
++tuntap.o : $(tuntap-objs)
++
++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
++      $(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs)
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/tuntap.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_TUNTAP_H
++#define __UM_TUNTAP_H
++
++#include "net_user.h"
++
++struct tuntap_data {
++      char *dev_name;
++      int fixed_config;
++      char *gate_addr;
++      int fd;
++      void *dev;
++      unsigned char hw_addr[ETH_ADDR_LEN];
++      int hw_setup;
++};
++
++extern struct net_user_info tuntap_user_info;
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/tuntap_kern.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,119 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/skbuff.h"
++#include "linux/init.h"
++#include "asm/errno.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "tuntap.h"
++
++struct tuntap_setup {
++      char *dev_name;
++      char *gate_addr;
++};
++
++struct tuntap_setup tuntap_priv[MAX_UML_NETDEV] = { 
++      [ 0 ... MAX_UML_NETDEV - 1 ] =
++      {
++              dev_name:       NULL,
++              gate_addr:      NULL,
++      }
++};
++
++struct net_device *tuntap_init(int private_size, int index)
++{
++      struct net_device *dev;
++      struct uml_net_private *pri;
++      struct tuntap_data *tpri;
++
++      dev = init_etherdev(NULL, private_size);
++      if(dev == NULL) return(NULL);
++      pri = dev->priv;
++      tpri = (struct tuntap_data *) pri->user;
++      tpri->dev_name = tuntap_priv[index].dev_name;
++      tpri->fixed_config = (tpri->dev_name != NULL);
++      tpri->gate_addr = tuntap_priv[index].gate_addr;
++      printk("TUN/TAP backend - ");
++      if(tpri->gate_addr != NULL) 
++              printk("IP = %s", tpri->gate_addr);
++      printk("\n");
++      tpri->fd = -1;
++      return(dev);
++}
++
++static unsigned short tuntap_protocol(struct sk_buff *skb)
++{
++      return(eth_type_trans(skb, skb->dev));
++}
++
++static int tuntap_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_read(fd, (*skb)->mac.raw, 
++                      (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int tuntap_write(int fd, struct sk_buff **skb, 
++                      struct uml_net_private *lp)
++{
++      return(net_write(fd, (*skb)->data, (*skb)->len));
++}
++
++struct net_kern_info tuntap_kern_info = {
++      init:                   tuntap_init,
++      protocol:               tuntap_protocol,
++      read:                   tuntap_read,
++      write:                  tuntap_write,
++};
++
++static int tuntap_count = 0;
++
++int tuntap_setup(char *str, struct uml_net *dev)
++{
++      struct tuntap_setup *pri;
++      int err;
++
++      pri = &tuntap_priv[tuntap_count];
++      err = tap_setup_common(str, "tuntap", &pri->dev_name, dev->mac,  
++                             &dev->have_mac, &pri->gate_addr);
++      if(err) return(err);
++
++      dev->user = &tuntap_user_info;
++      dev->kern = &tuntap_kern_info;
++      dev->private_size = sizeof(struct tuntap_data);
++      dev->transport_index = tuntap_count++;
++      return(0);
++}
++
++static struct transport tuntap_transport = {
++      list :  LIST_HEAD_INIT(tuntap_transport.list),
++      name :  "tuntap",
++      setup : tuntap_setup
++};
++
++static int register_tuntap(void)
++{
++      register_transport(&tuntap_transport);
++      return(1);
++}
++
++__initcall(register_tuntap);
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/tuntap_kern.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,24 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_TUNTAP_KERN_H
++#define __UM_TUNTAP_KERN_H
++
++#include "net_kern.h"
++
++extern int tuntap_setup(char *arg, struct uml_net *dev);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/drivers/tuntap_user.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,223 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/wait.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/uio.h>
++#include <sys/ioctl.h>
++#include <net/if.h>
++#include <linux/if_tun.h>
++#include "net_user.h"
++#include "tuntap.h"
++#include "kern_util.h"
++#include "user.h"
++#include "helper.h"
++#include "os.h"
++
++#define MAX_PACKET ETH_MAX_PACKET
++
++void tuntap_user_init(void *data, void *dev)
++{
++      struct tuntap_data *pri = data;
++
++      pri->dev = dev;
++}
++
++static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct tuntap_data *pri = data;
++
++      tap_check_ips(pri->gate_addr, addr);
++      if((pri->fd == -1) || pri->fixed_config) return;
++      open_addr(addr, netmask, pri->dev_name);
++}
++
++static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct tuntap_data *pri = data;
++
++      if((pri->fd == -1) || pri->fixed_config) return;
++      close_addr(addr, netmask, pri->dev_name);
++}
++
++struct tuntap_pre_exec_data {
++      int stdout;
++      int close_me;
++};
++
++static void tuntap_pre_exec(void *arg)
++{
++      struct tuntap_pre_exec_data *data = arg;
++      
++      dup2(data->stdout, 1);
++      close(data->close_me);
++}
++
++static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
++                           char *buffer, int buffer_len, int *used_out)
++{
++      struct tuntap_pre_exec_data data;
++      char version_buf[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
++                       NULL };
++      char buf[CMSG_SPACE(sizeof(*fd_out))];
++      struct msghdr msg;
++      struct cmsghdr *cmsg;
++      struct iovec iov;
++      int pid, n;
++
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++
++      data.stdout = remote;
++      data.close_me = me;
++
++      pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
++
++      if(pid < 0) return(-pid);
++
++      close(remote);
++
++      msg.msg_name = NULL;
++      msg.msg_namelen = 0;
++      if(buffer != NULL){
++              iov = ((struct iovec) { buffer, buffer_len });
++              msg.msg_iov = &iov;
++              msg.msg_iovlen = 1;
++      }
++      else {
++              msg.msg_iov = NULL;
++              msg.msg_iovlen = 0;
++      }
++      msg.msg_control = buf;
++      msg.msg_controllen = sizeof(buf);
++      msg.msg_flags = 0;
++      n = recvmsg(me, &msg, 0);
++      *used_out = n;
++      if(n < 0){
++              printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
++                     errno);
++              return(errno);
++      }
++      waitpid(pid, NULL, 0);
++
++      cmsg = CMSG_FIRSTHDR(&msg);
++      if(cmsg == NULL){
++              printk("tuntap_open_tramp : didn't receive a message\n");
++              return(EINVAL);
++      }
++      if((cmsg->cmsg_level != SOL_SOCKET) || 
++         (cmsg->cmsg_type != SCM_RIGHTS)){
++              printk("tuntap_open_tramp : didn't receive a descriptor\n");
++              return(EINVAL);
++      }
++      *fd_out = ((int *) CMSG_DATA(cmsg))[0];
++      return(0);
++}
++
++static int tuntap_open(void *data)
++{
++      struct ifreq ifr;
++      struct tuntap_data *pri = data;
++      char *output, *buffer;
++      int err, fds[2], len, used;
++
++      err = tap_open_common(pri->dev, pri->gate_addr);
++      if(err) return(err);
++
++      if(pri->fixed_config){
++              if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){
++                      printk("Failed to open /dev/net/tun, errno = %d\n",
++                             errno);
++                      return(-errno);
++              }
++              memset(&ifr, 0, sizeof(ifr));
++              ifr.ifr_flags = IFF_TAP;
++              strncpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name) - 1);
++              if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
++                      printk("TUNSETIFF failed, errno = %d", errno);
++                      close(pri->fd);
++                      return(-errno);
++              }
++      }
++      else {
++              err = os_pipe(fds, 0, 0);
++              if(err){
++                      printk("tuntap_open : os_pipe failed - errno = %d\n",
++                             -err);
++                      return(err);
++              }
++
++              buffer = get_output_buffer(&len);
++              if(buffer != NULL) len--;
++              used = 0;
++
++              err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
++                                      fds[1], buffer, len, &used);
++
++              output = buffer;
++              if(err == 0){
++                      pri->dev_name = uml_strdup(buffer);
++                      output += IFNAMSIZ;
++                      printk(output);
++                      free_output_buffer(buffer);
++              }
++              else {
++                      printk(output);
++                      free_output_buffer(buffer);
++                      printk("tuntap_open_tramp failed - errno = %d\n", err);
++                      return(-err);
++              }
++              close(fds[0]);
++              iter_addresses(pri->dev, open_addr, pri->dev_name);
++      }
++
++      return(pri->fd);
++}
++
++static void tuntap_close(int fd, void *data)
++{
++      struct tuntap_data *pri = data;
++
++      if(!pri->fixed_config) 
++              iter_addresses(pri->dev, close_addr, pri->dev_name);
++      close(fd);
++      pri->fd = -1;
++}
++
++static int tuntap_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info tuntap_user_info = {
++      init:           tuntap_user_init,
++      open:           tuntap_open,
++      close:          tuntap_close,
++      remove:         NULL,
++      set_mtu:        tuntap_set_mtu,
++      add_address:    tuntap_add_addr,
++      delete_address: tuntap_del_addr,
++      max_packet:     MAX_PACKET
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/file.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,344 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/ioctl.h>
++#include <sys/mount.h>
++#include <sys/uio.h>
++#include "os.h"
++#include "user.h"
++#include "kern_util.h"
++
++int os_file_type(char *file)
++{
++      struct stat64 buf;
++
++      if(stat64(file, &buf) == -1)
++              return(-errno);
++
++      if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
++      else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
++      else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
++      else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
++      else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
++      else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
++      else return(OS_TYPE_FILE);
++}
++
++int os_file_mode(char *file, struct openflags *mode_out)
++{
++      *mode_out = OPENFLAGS();
++
++      if(!access(file, W_OK)) *mode_out = of_write(*mode_out);
++      else if(errno != EACCES) 
++              return(-errno);
++
++      if(!access(file, R_OK)) *mode_out = of_read(*mode_out);
++      else if(errno != EACCES) 
++              return(-errno);
++
++      return(0);
++}
++
++int os_open_file(char *file, struct openflags flags, int mode)
++{
++      int fd, f = 0;
++
++      if(flags.r && flags.w) f = O_RDWR;
++      else if(flags.r) f = O_RDONLY;
++      else if(flags.w) f = O_WRONLY;
++      else f = 0;
++
++      if(flags.s) f |= O_SYNC;
++      if(flags.c) f |= O_CREAT;
++      if(flags.t) f |= O_TRUNC;
++      if(flags.e) f |= O_EXCL;
++
++      fd = open64(file, f, mode);
++      if(fd < 0) return(-errno);
++      return(fd);
++}
++
++int os_connect_socket(char *name)
++{
++      struct sockaddr_un sock;
++      int fd, err;
++
++      sock.sun_family = AF_UNIX;
++      snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
++
++      fd = socket(AF_UNIX, SOCK_STREAM, 0);
++      if(fd < 0)
++              return(fd);
++
++      err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
++      if(err)
++              return(err);
++
++      return(fd);
++}
++
++void os_close_file(int fd)
++{
++      close(fd);
++}
++
++int os_seek_file(int fd, __u64 offset)
++{
++      __u64 actual;
++
++      actual = lseek64(fd, offset, SEEK_SET);
++      if(actual != offset) return(-errno);
++      return(0);
++}
++
++int os_read_file(int fd, char *buf, int len)
++{
++      int n;
++
++      /* Force buf into memory if it's not already. */
++
++      /* XXX This fails if buf is kernel memory */
++#ifdef notdef
++      if(copy_to_user_proc(buf, &c, sizeof(c)))
++              return(-EFAULT);
++#endif
++
++      n = read(fd, buf, len);
++      if(n < 0)
++              return(-errno);
++      return(n);
++}
++
++int os_write_file(int fd, char *buf, int count)
++{
++      int n;
++
++      /* Force buf into memory if it's not already. */
++      
++      /* XXX This fails if buf is kernel memory */
++#ifdef notdef
++      if(copy_to_user_proc(buf, buf, buf[0]))
++              return(-EFAULT);
++#endif
++
++      n = write(fd, buf, count);
++      if(n < 0)
++              return(-errno);
++      return(n);
++}
++
++int os_file_size(char *file, long long *size_out)
++{
++      struct stat64 buf;
++
++      if(stat64(file, &buf) == -1){
++              printk("Couldn't stat \"%s\" : errno = %d\n", file, errno);
++              return(-errno);
++      }
++      if(S_ISBLK(buf.st_mode)){
++              int fd, blocks;
++
++              if((fd = open64(file, O_RDONLY)) < 0){
++                      printk("Couldn't open \"%s\", errno = %d\n", file,
++                             errno);
++                      return(-errno);
++              }
++              if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
++                      printk("Couldn't get the block size of \"%s\", "
++                             "errno = %d\n", file, errno);
++                      close(fd);
++                      return(-errno);
++              }
++              *size_out = ((long long) blocks) * 512;
++              close(fd);
++              return(0);
++      }
++      *size_out = buf.st_size;
++      return(0);
++}
++
++int os_pipe(int *fds, int stream, int close_on_exec)
++{
++      int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
++
++      err = socketpair(AF_UNIX, type, 0, fds);
++      if(err) return(-errno);
++
++      if(!close_on_exec)
++              return(0);
++
++      if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0))
++              printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", 
++                     errno);
++
++      return(0);
++}
++
++int os_set_fd_async(int fd, int owner)
++{
++      if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
++              printk("os_set_fd_async : failed to set O_ASYNC and "
++                     "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
++              return(-errno);
++      }
++#ifdef notdef
++      if(fcntl(fd, F_SETFD, 1) < 0){
++              printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
++                     "errno = %d\n", errno);
++      }
++#endif
++
++      if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
++         (fcntl(fd, F_SETOWN, owner) < 0)){
++              printk("os_set_fd_async : Failed to fcntl F_SETOWN "
++                     "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, 
++                     owner, errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_set_fd_block(int fd, int blocking)
++{
++      int flags;
++
++      flags = fcntl(fd, F_GETFL);
++
++      if(blocking) flags &= ~O_NONBLOCK;
++      else flags |= O_NONBLOCK;
++
++      if(fcntl(fd, F_SETFL, flags) < 0){
++              printk("Failed to change blocking on fd # %d, errno = %d\n",
++                     fd, errno);
++              return(-errno);
++      }
++      return(0);
++}
++
++int os_accept_connection(int fd)
++{
++      int err;
++
++      err = accept(fd, NULL, 0);
++      if(err) 
++              return(-errno);
++      return(0);
++}
++
++#ifndef SHUT_RD
++#define SHUT_RD 0
++#endif
++
++#ifndef SHUT_WR
++#define SHUT_WR 1
++#endif
++
++#ifndef SHUT_RDWR
++#define SHUT_RDWR 2
++#endif
++
++int os_shutdown_socket(int fd, int r, int w)
++{
++      int what, err;
++
++      if(r && w) what = SHUT_RDWR;
++      else if(r) what = SHUT_RD;
++      else if(w) what = SHUT_WR;
++      else {
++              printk("os_shutdown_socket : neither r or w was set\n");
++              return(-EINVAL);
++      }
++      err = shutdown(fd, what);
++      if(err)
++              return(-errno);
++      return(0);
++}
++
++int os_rcv_fd(int fd, int *helper_pid_out)
++{
++      int new, n;
++      char buf[CMSG_SPACE(sizeof(new))];
++      struct msghdr msg;
++      struct cmsghdr *cmsg;
++      struct iovec iov;
++
++      msg.msg_name = NULL;
++      msg.msg_namelen = 0;
++      iov = ((struct iovec) { iov_base : helper_pid_out,
++                              iov_len :  sizeof(*helper_pid_out) });
++      msg.msg_iov = &iov;
++      msg.msg_iovlen = 1;
++      msg.msg_control = buf;
++      msg.msg_controllen = sizeof(buf);
++      msg.msg_flags = 0;
++
++      n = recvmsg(fd, &msg, 0);
++      if(n < 0){
++              printk("rcv_fd : recvmsg failed - errno = %d\n", errno);
++              return(-1);
++      }
++      else if(n != sizeof(iov.iov_len))
++              *helper_pid_out = -1;
++  
++      cmsg = CMSG_FIRSTHDR(&msg);
++      if(cmsg == NULL){
++              printk("rcv_fd didn't receive anything, error = %d\n", errno);
++              return(-1);
++      }
++      if((cmsg->cmsg_level != SOL_SOCKET) || 
++         (cmsg->cmsg_type != SCM_RIGHTS)){
++              printk("rcv_fd didn't receive a descriptor\n");
++              return(-1);
++      }
++
++      new = ((int *) CMSG_DATA(cmsg))[0];
++      return(new);
++}
++
++int create_unix_socket(char *file, int len)
++{
++      struct sockaddr_un addr;
++      int sock, err;
++
++      sock = socket(PF_UNIX, SOCK_DGRAM, 0);
++      if (sock < 0){
++              printk("create_unix_socket - socket failed, errno = %d\n",
++                     errno);
++              return(-errno);
++      }
++
++      addr.sun_family = AF_UNIX;
++
++      /* XXX Be more careful about overflow */
++      snprintf(addr.sun_path, len, "%s", file);
++
++      err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++      if (err < 0){
++              printk("create_listening_socket - bind failed, errno = %d\n",
++                     errno);
++              return(-errno);
++      }
++
++      return(sock);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/include/file.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __OS_FILE_H__
++#define __OS_FILE_H__
++
++#define DEV_NULL "/dev/null"
++
++#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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/Makefile    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,17 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = os.o
++
++obj-y = file.o process.o tty.o
++
++include $(TOPDIR)/Rules.make
++
++$(obj-y) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
++
++archmrproper:
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/process.c   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,102 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <signal.h>
++#include "os.h"
++#include "user.h"
++
++unsigned long os_process_pc(int pid)
++{
++      char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
++      unsigned long pc;
++      int fd;
++
++      sprintf(proc_stat, "/proc/%d/stat", pid);
++      fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("os_process_pc - couldn't open '%s', errno = %d\n", 
++                     proc_stat, errno);
++              return(-1);
++      }
++      if(read(fd, buf, sizeof(buf)) < 0){
++              printk("os_process_pc - couldn't read '%s', errno = %d\n", 
++                     proc_stat, errno);
++              close(fd);
++              return(-1);
++      }
++      close(fd);
++      pc = -1;
++      if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d "
++                "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
++                "%*d %*d %*d %*d %ld", &pc) != 1){
++              printk("os_process_pc - couldn't find pc in '%s'\n", buf);
++      }
++      return(pc);
++}
++
++int os_process_parent(int pid)
++{
++      char stat[sizeof("/proc/nnnnn/stat\0")];
++      char data[256];
++      int parent, n, fd;
++
++      if(pid == -1) return(-1);
++
++      snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
++      fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open '%s', errno = %d\n", stat, -fd);
++              return(-1);
++      }
++
++      n = read(fd, data, sizeof(data));
++      close(fd);
++
++      if(n < 0){
++              printk("Couldn't read '%s', errno = %d\n", stat);
++              return(-1);
++      }
++
++      parent = -1;
++      /* XXX This will break if there is a space in the command */
++      n = sscanf(data, "%*d %*s %*c %d", &parent);
++      if(n != 1) printk("Failed to scan '%s'\n", data);
++
++      return(parent);
++}
++
++void os_stop_process(int pid)
++{
++      kill(pid, SIGSTOP);
++}
++
++void os_kill_process(int pid)
++{
++      kill(pid, SIGKILL);
++}
++
++void os_usr1_process(int pid)
++{
++      kill(pid, SIGUSR1);
++}
++
++int os_getpid(void)
++{
++      return(getpid());
++}
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/os-Linux/tty.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include "os.h"
++#include "user.h"
++#include "kern_util.h"
++
++struct grantpt_info {
++      int fd;
++      int res;
++      int err;
++};
++
++static void grantpt_cb(void *arg)
++{
++      struct grantpt_info *info = arg;
++
++      info->res = grantpt(info->fd);
++      info->err = errno;
++}
++
++int get_pty(void)
++{
++      struct grantpt_info info;
++      int fd;
++
++      if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){
++              printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n",
++                     errno);
++              return(-1);
++      }
++
++      info.fd = fd;
++      tracing_cb(grantpt_cb, &info);
++
++      if(info.res < 0){
++              printk("get_pty : Couldn't grant pty - errno = %d\n", 
++                     info.err);
++              return(-1);
++      }
++      if(unlockpt(fd) < 0){
++              printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
++              return(-1);
++      }
++      return(fd);
++}
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/Makefile     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++LIB = ptproxy.a
++
++OBJS = proxy.o ptrace.o sysdep.o wait.o
++
++all: $(LIB)
++
++$(LIB): $(OBJS)
++      rm -f $@
++      ar cr $@ $^
++
++proxy.o: proxy.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++ptrace.o: ptrace.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++sysdep.o: sysdep.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++wait.o: wait.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++clean:
++      rm -f *.o core child ptproxy
++
++include $(TOPDIR)/Rules.make
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/proxy.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,371 @@
++/**********************************************************************
++proxy.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++
++Jeff Dike (jdike@karaya.com) : Modified for integration into uml
++**********************************************************************/
++
++/* XXX This file shouldn't refer to CONFIG_* */
++
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <signal.h>
++#include <string.h>
++#include <fcntl.h>
++#include <termios.h>
++#include <sys/wait.h>
++#include <sys/types.h>
++#include <sys/ptrace.h>
++#include <sys/ioctl.h>
++#include <asm/unistd.h>
++
++#include "ptproxy.h"
++#include "sysdep.h"
++#include "wait.h"
++
++#include "user_util.h"
++#include "user.h"
++#include "os.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);
++
++      case __NR_waitpid:
++      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);
++}
++
++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_waitpid) || (syscall == __NR_wait4)){
++              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);
++}
++
++#ifdef CONFIG_SMP
++#error need to make these arrays
++#endif
++
++static debugger_state debugger;
++static debugee_state debugee;
++
++void init_proxy (pid_t debugger_pid, int stopped, int status)
++{
++      debugger.pid = debugger_pid;
++      debugger.handle_trace = debugger_syscall;
++      debugger.debugee = &debugee;
++      debugger.waiting = 0;
++      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){
++              pid = waitpid(debugger.pid, &status, WUNTRACED);
++              if(pid != debugger.pid){
++                      printk("fake_child_exit - waitpid failed, "
++                             "errno = %d\n", errno);
++                      return;
++              }
++              debugger_proxy(status, debugger.pid);
++      }
++      pid = waitpid(debugger.pid, &status, WUNTRACED);
++      if(pid != debugger.pid){
++              printk("fake_child_exit - waitpid failed, "
++                     "errno = %d\n", errno);
++              return;
++      }
++      if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
++              printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
++                     errno);
++}
++
++char gdb_init_string[] = 
++"att 1
++b panic
++b stop
++handle SIGWINCH nostop noprint pass
++";
++
++int start_debugger(char *prog, int startup, int stop, int *fd_out)
++{
++      int slave, child;
++
++      slave = open_gdb_chan();
++      if((child = fork()) == 0){
++              char *tempname = NULL;
++              int fd;
++
++              if(setsid() < 0) perror("setsid");
++              if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || 
++                 (dup2(slave, 2) < 0)){
++                      printk("start_debugger : dup2 failed, errno = %d\n",
++                             errno);
++                      exit(1);
++              }
++              if(ioctl(0, TIOCSCTTY, 0) < 0){
++                      printk("start_debugger : TIOCSCTTY failed, "
++                             "errno = %d\n", errno);
++                      exit(1);
++              }
++              if(tcsetpgrp (1, os_getpid()) < 0){
++                      printk("start_debugger : tcsetpgrp failed, "
++                             "errno = %d\n", errno);
++#ifdef notdef
++                      exit(1);
++#endif
++              }
++              if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
++                      printk("start_debugger : make_tempfile failed, errno = %d\n",
++                             errno);
++                      exit(1);
++              }
++              write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
++              if(startup){
++                      if(stop){
++                              write(fd, "b start_kernel\n",
++                                    strlen("b start_kernel\n"));
++                      }
++                      write(fd, "c\n", strlen("c\n"));
++              }
++              if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++                      printk("start_debugger :  PTRACE_TRACEME failed, "
++                             "errno = %d\n", errno);
++                      exit(1);
++              }
++              execlp("gdb", "gdb", "--command", tempname, prog, NULL);
++              printk("start_debugger : exec of gdb failed, errno = %d\n",
++                     errno);
++      }
++      if(child < 0){
++              printk("start_debugger : fork for gdb failed, errno = %d\n",
++                     errno);
++              return(-1);
++      }
++      *fd_out = slave;
++      return(child);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/ptproxy.h    2003-09-09 16:15:18.000000000 +0400
+@@ -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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/ptrace.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,238 @@
++/**********************************************************************
++ptrace.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++
++Jeff Dike (jdike@karaya.com) : Modified for integration into uml
++**********************************************************************/
++
++#include <errno.h>
++#include <unistd.h>
++#include <signal.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/wait.h>
++#include <asm/ptrace.h>
++
++#include "ptproxy.h"
++#include "debug.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "ptrace_user.h"
++
++long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
++                long arg3, long arg4, pid_t child, int *ret)
++{
++      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_PEEKUSER:
++              /* The value being read out could be -1, so we have to 
++               * check errno to see if there's an error, and zero it
++               * beforehand so we're not faked out by an old error
++               */
++
++              errno = 0;
++              result = ptrace(arg1, child, arg3, 0);
++              if((result == -1) && (errno != 0)) return(-errno);
++
++              result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
++              if(result == -1) return(-errno);
++                      
++              return(result);
++
++      case PTRACE_POKEDATA:
++      case PTRACE_POKETEXT:
++      case PTRACE_POKEUSER:
++              result = ptrace(arg1, child, arg3, arg4);
++              if(result == -1) return(-errno);
++
++              if(arg1 == PTRACE_POKEUSER) 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/sysdep.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,71 @@
++/**********************************************************************
++sysdep.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++**********************************************************************/
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <sys/types.h>
++#include <sys/ptrace.h>
++#include <asm/ptrace.h>
++#include <linux/unistd.h>
++#include "ptrace_user.h"
++#include "user_util.h"
++#include "user.h"
++
++int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, 
++              long *arg5)
++{
++      *arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0);
++      *arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0);
++      *arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0);
++      *arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0);
++      *arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0);
++      return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0));
++}
++
++void syscall_cancel(pid_t pid, int result)
++{
++      if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
++                 __NR_getpid) < 0) ||
++         (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
++         (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
++         (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
++         (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
++              printk("ptproxy: couldn't cancel syscall: errno = %d\n", 
++                     errno);
++}
++
++void syscall_set_result(pid_t pid, long result)
++{
++      ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result);
++}
++
++void syscall_continue(pid_t pid)
++{
++      ptrace(PTRACE_SYSCALL, pid, 0, 0);
++}
++
++int syscall_pause(pid_t pid) 
++{
++      if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
++              printk("syscall_change - ptrace failed, errno = %d\n", errno);
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/sysdep.h     2003-09-09 16:15:18.000000000 +0400
+@@ -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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/wait.c       2003-09-09 16:15:18.000000000 +0400
+@@ -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 <sys/ptrace.h>
++#include <asm/ptrace.h>
++
++#include "ptproxy.h"
++#include "sysdep.h"
++#include "wait.h"
++#include "user_util.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/ptrace_user.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 err, pid;
++
++      pid = debugger->pid;
++      ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++      ip = IP_RESTART_SYSCALL(ip);
++      err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip);
++      if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
++              tracer_panic("real_wait_return : Failed to restart system "
++                           "call, errno = %d\n");
++      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");
++      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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/ptproxy/wait.h       2003-09-09 16:15:18.000000000 +0400
+@@ -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
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/bugs.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,156 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/signal.h>
++#include "kern_util.h"
++#include "user.h"
++#include "sysdep/ptrace.h"
++#include "task.h"
++
++#define MAXTOKEN 64
++
++int cpu_has_cmov = 1;
++int cpu_has_xmm = 0;
++
++static char token(int fd, char *buf, int len, char stop)
++{
++      int n;
++      char *ptr, *end, c;
++
++      ptr = buf;
++      end = &buf[len];
++      do {
++              n = read(fd, ptr, sizeof(*ptr));
++              c = *ptr++;
++              if(n == 0) return(0);
++              else if(n != sizeof(*ptr)){
++                      printk("Reading /proc/cpuinfo failed, "
++                             "errno = %d\n", errno);
++                      return(-errno);
++              }
++      } while((c != '\n') && (c != stop) && (ptr < end));
++
++      if(ptr == end){
++              printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
++              return(-1);
++      }
++      *(ptr - 1) = '\0';
++      return(c);
++}
++
++static int check_cpu_feature(char *feature, int *have_it)
++{
++      char buf[MAXTOKEN], c;
++      int fd, len = sizeof(buf)/sizeof(buf[0]), n;
++
++      printk("Checking for host processor %s support...", feature);
++      fd = open("/proc/cpuinfo", O_RDONLY);
++      if(fd < 0){
++              printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno);
++              return(0);
++      }
++
++      *have_it = 0;
++      buf[len - 1] = '\0';
++      while(1){
++              c = token(fd, buf, len - 1, ':');
++              if(c <= 0) goto out;
++              else if(c != ':'){
++                      printk("Failed to find ':' in /proc/cpuinfo\n");
++                      goto out;
++              }
++
++              if(!strncmp(buf, "flags", strlen("flags"))) break;
++
++              do {
++                      n = read(fd, &c, sizeof(c));
++                      if(n != sizeof(c)){
++                              printk("Failed to find newline in "
++                                     "/proc/cpuinfo, n = %d, errno = %d\n",
++                                     n, errno);
++                              goto out;
++                      }
++              } while(c != '\n');
++      }
++
++      c = token(fd, buf, len - 1, ' ');
++      if(c < 0) goto out;
++      else if(c != ' '){
++              printk("Failed to find ':' in /proc/cpuinfo\n");
++              goto out;
++      }
++
++      while(1){
++              c = token(fd, buf, len - 1, ' ');
++              if(c < 0) goto out;
++              else if(c == '\n') break;
++
++              if(!strcmp(buf, feature)){
++                      *have_it = 1;
++                      goto out;
++              }
++      }
++ out:
++      if(*have_it == 0) printk("No\n");
++      else if(*have_it == 1) printk("Yes\n");
++      close(fd);
++      return(1);
++}
++
++void arch_check_bugs(void)
++{
++      int have_it;
++
++      if(access("/proc/cpuinfo", R_OK)){
++              printk("/proc/cpuinfo not available - skipping CPU capability "
++                     "checks\n");
++              return;
++      }
++      if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
++      if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
++}
++
++int arch_handle_signal(int sig, struct uml_pt_regs *regs)
++{
++      unsigned long ip;
++
++      /* This is testing for a cmov (0x0f 0x4x) instruction causing a
++       * SIGILL in init.
++       */
++      if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
++
++      ip = UPT_IP(regs);
++      if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
++              return(0);
++
++      if(cpu_has_cmov == 0)
++              panic("SIGILL caused by cmov, which this processor doesn't "
++                    "implement, boot a filesystem compiled for older "
++                    "processors");
++      else if(cpu_has_cmov == 1)
++              panic("SIGILL caused by cmov, which this processor claims to "
++                    "implement");
++      else if(cpu_has_cmov == -1)
++              panic("SIGILL caused by cmov, couldn't tell if this processor "
++                    "implements it, boot a filesystem compiled for older "
++                    "processors");
++      else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/fault.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++
++extern unsigned long search_exception_table(unsigned long addr);
++
++int arch_fixup(unsigned long address, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      unsigned long fixup;
++
++      fixup = search_exception_table(address);
++      if(fixup != 0){
++              sc->eip = fixup;
++              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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/ksyms.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,16 @@
++#include "linux/module.h"
++#include "linux/in6.h"
++#include "linux/rwsem.h"
++#include "asm/byteorder.h"
++#include "asm/semaphore.h"
++#include "asm/uaccess.h"
++#include "asm/checksum.h"
++#include "asm/errno.h"
++
++EXPORT_SYMBOL(__down_failed);
++EXPORT_SYMBOL(__down_failed_interruptible);
++EXPORT_SYMBOL(__down_failed_trylock);
++EXPORT_SYMBOL(__up_wakeup);
++
++/* Networking helper routines. */
++EXPORT_SYMBOL(csum_partial_copy_generic);
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/ldt.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/uaccess.h"
++
++extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
++
++int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++{
++      if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
++      return(modify_ldt(func, ptr, bytecount));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/Makefile    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,42 @@
++O_TARGET = sys.o
++
++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o old-checksum.o \
++      ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
++export-objs = ksyms.o
++
++USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o
++
++SYMLINKS = semaphore.c old-checksum.c checksum.S extable.c
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++checksum.S old-checksum.c: 
++      -rm -f $@
++      -ln -s $(TOPDIR)/arch/i386/lib/$@ $@
++
++semaphore.c:
++      -rm -f $@
++      -ln -s $(TOPDIR)/arch/i386/kernel/$@ $@
++
++extable.c:
++      -rm -f $@
++      -ln -s $(TOPDIR)/arch/i386/mm/$@ $@
++
++clean:
++      $(MAKE) -C util clean
++
++fastdep:
++
++dep:
++
++archmrproper:
++      rm -f $(SYMLINKS)
++
++archclean:
++
++archdep:
++
++modules:
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/ptrace.c    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,326 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "asm/elf.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "ptrace_user.h"
++#include "sysdep/sigcontext.h"
++#include "sysdep/sc.h"
++
++void arch_switch(void)
++{
++      update_debugregs(current->thread.arch.debugregs_seq);
++}
++
++int is_syscall(unsigned long addr)
++{
++      unsigned short instr;
++      int n;
++
++      n = copy_from_user(&instr, (void *) addr, sizeof(instr));
++      if(n){
++              printk("is_syscall : failed to read instruction from 0x%lu\n", 
++                     addr);
++              return(0);
++      }
++      return(instr == 0x80cd);
++}
++
++/* determines which flags the user has access to. */
++/* 1 = access 0 = no access */
++#define FLAG_MASK 0x00044dd5
++
++int putreg(struct task_struct *child, int regno, unsigned long value)
++{
++      regno >>= 2;
++      switch (regno) {
++      case FS:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              PT_REGS_FS(&child->thread.regs) = value;
++              return 0;
++      case GS:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              PT_REGS_GS(&child->thread.regs) = value;
++              return 0;
++      case DS:
++      case ES:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              value &= 0xffff;
++              break;
++      case SS:
++      case CS:
++              if ((value & 3) != 3)
++                      return -EIO;
++              value &= 0xffff;
++              break;
++      case EFL:
++              value &= FLAG_MASK;
++              value |= PT_REGS_EFLAGS(&child->thread.regs);
++              break;
++      }
++      PT_REGS_SET(&child->thread.regs, regno, value);
++      return 0;
++}
++
++unsigned long getreg(struct task_struct *child, int regno)
++{
++      unsigned long retval = ~0UL;
++
++      regno >>= 2;
++      switch (regno) {
++      case FS:
++      case GS:
++      case DS:
++      case ES:
++      case SS:
++      case CS:
++              retval = 0xffff;
++              /* fall through */
++      default:
++              retval &= PT_REG(&child->thread.regs, regno);
++      }
++      return retval;
++}
++
++struct i387_fxsave_struct {
++      unsigned short  cwd;
++      unsigned short  swd;
++      unsigned short  twd;
++      unsigned short  fop;
++      long    fip;
++      long    fcs;
++      long    foo;
++      long    fos;
++      long    mxcsr;
++      long    reserved;
++      long    st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
++      long    xmm_space[32];  /* 8*16 bytes for each XMM-reg = 128 bytes */
++      long    padding[56];
++};
++
++/*
++ * FPU tag word conversions.
++ */
++
++static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
++{
++      unsigned int tmp; /* to avoid 16 bit prefixes in the code */
++ 
++      /* Transform each pair of bits into 01 (valid) or 00 (empty) */
++        tmp = ~twd;
++        tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
++        /* and move the valid bits to the lower byte. */
++        tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
++        tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
++        tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
++        return tmp;
++}
++
++static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
++{
++      struct _fpxreg *st = NULL;
++      unsigned long twd = (unsigned long) fxsave->twd;
++      unsigned long tag;
++      unsigned long ret = 0xffff0000;
++      int i;
++
++#define FPREG_ADDR(f, n)      ((char *)&(f)->st_space + (n) * 16);
++
++      for ( i = 0 ; i < 8 ; i++ ) {
++              if ( twd & 0x1 ) {
++                      st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
++
++                      switch ( st->exponent & 0x7fff ) {
++                      case 0x7fff:
++                              tag = 2;                /* Special */
++                              break;
++                      case 0x0000:
++                              if ( !st->significand[0] &&
++                                   !st->significand[1] &&
++                                   !st->significand[2] &&
++                                   !st->significand[3] ) {
++                                      tag = 1;        /* Zero */
++                              } else {
++                                      tag = 2;        /* Special */
++                              }
++                              break;
++                      default:
++                              if ( st->significand[3] & 0x8000 ) {
++                                      tag = 0;        /* Valid */
++                              } else {
++                                      tag = 2;        /* Special */
++                              }
++                              break;
++                      }
++              } else {
++                      tag = 3;                        /* Empty */
++              }
++              ret |= (tag << (2 * i));
++              twd = twd >> 1;
++      }
++      return ret;
++}
++
++/*
++b * FXSR floating point environment conversions.
++ */
++
++static inline int convert_fxsr_to_user(struct _fpstate *buf, 
++                                     struct pt_regs *regs)
++{
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned long env[7];
++      struct _fpreg *to;
++      struct _fpxreg *from;
++      int i;
++
++      env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
++      env[1] = (unsigned long)fxsave->swd | 0xffff0000;
++      env[2] = twd_fxsr_to_i387(fxsave);
++      env[3] = fxsave->fip;
++      env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
++      env[5] = fxsave->foo;
++      env[6] = fxsave->fos;
++
++      if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
++              return 1;
++
++      to = &buf->_st[0];
++      from = (struct _fpxreg *) &fxsave->st_space[0];
++      for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
++              if ( __copy_to_user( to, from, sizeof(*to) ) )
++                      return 1;
++      }
++      return 0;
++}
++
++static inline int convert_fxsr_from_user(struct pt_regs *regs,
++                                       struct _fpstate *buf)
++{
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned long env[7];
++      struct _fpxreg *to;
++      struct _fpreg *from;
++      int i;
++
++      if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
++              return 1;
++
++      fxsave->cwd = (unsigned short)(env[0] & 0xffff);
++      fxsave->swd = (unsigned short)(env[1] & 0xffff);
++      fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
++      fxsave->fip = env[3];
++      fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
++      fxsave->fcs = (env[4] & 0xffff);
++      fxsave->foo = env[5];
++      fxsave->fos = env[6];
++
++      to = (struct _fpxreg *) &fxsave->st_space[0];
++      from = &buf->_st[0];
++      for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
++              if ( __copy_from_user( to, from, sizeof(*from) ) )
++                      return 1;
++      }
++      return 0;
++}
++
++int get_fpregs(unsigned long buf, struct task_struct *child)
++{
++      int err;
++
++      err = convert_fxsr_to_user((struct _fpstate *) buf, 
++                                 &child->thread.regs);
++      if(err) return(-EFAULT);
++      else return(0);
++}
++
++int set_fpregs(unsigned long buf, struct task_struct *child)
++{
++      int err;
++
++      err = convert_fxsr_from_user(&child->thread.regs, 
++                                   (struct _fpstate *) buf);
++      if(err) return(-EFAULT);
++      else return(0);
++}
++
++int get_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++      struct pt_regs *regs = &tsk->thread.regs;
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      int err;
++
++      err = __copy_to_user((void *) buf, fxsave,
++                           sizeof(struct user_fxsr_struct));
++      if(err) return -EFAULT;
++      else return 0;
++}
++
++int set_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++      struct pt_regs *regs = &tsk->thread.regs;
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      int err;
++
++      err = __copy_from_user(fxsave, (void *) buf,
++                             sizeof(struct user_fxsr_struct) );
++      if(err) return -EFAULT;
++      else return 0;
++}
++
++#ifdef notdef
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
++{
++      fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
++                  (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
++      fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
++      fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
++      fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
++      fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
++      fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
++      fpu->fos = 0;
++      memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
++             sizeof(fpu->st_space));
++      return(1);
++}
++#endif
++static inline void copy_fpu_fxsave(struct pt_regs *regs,
++                                 struct user_i387_struct *buf)
++{
++      struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned short *to;
++      unsigned short *from;
++      int i;
++
++      memcpy( buf, fpu, 7 * sizeof(long) );
++
++      to = (unsigned short *) &buf->st_space[0];
++      from = (unsigned short *) &fpu->st_space[0];
++      for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
++              memcpy( to, from, 5 * sizeof(unsigned short) );
++      }
++}
++
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
++{
++      copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
++      return(1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/ptrace_user.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,116 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <errno.h>
++#include <unistd.h>
++#include <linux/stddef.h>
++#include <sys/ptrace.h>
++#include <asm/ptrace.h>
++#include <asm/user.h>
++#include "kern_util.h"
++#include "sysdep/thread.h"
++#include "user.h"
++#include "os.h"
++
++int ptrace_getregs(long pid, unsigned long *regs_out)
++{
++      return(ptrace(PTRACE_GETREGS, pid, 0, regs_out));
++}
++
++int ptrace_setregs(long pid, unsigned long *regs)
++{
++      return(ptrace(PTRACE_SETREGS, pid, 0, regs));
++}
++
++int ptrace_getfpregs(long pid, unsigned long *regs)
++{
++      return(ptrace(PTRACE_GETFPREGS, pid, 0, regs));
++}
++
++static void write_debugregs(int pid, unsigned long *regs)
++{
++      struct user *dummy;
++      int nregs, i;
++
++      dummy = NULL;
++      nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++      for(i = 0; i < nregs; i++){
++              if((i == 4) || (i == 5)) continue;
++              if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
++                        regs[i]) < 0)
++                      printk("write_debugregs - ptrace failed, "
++                             "errno = %d\n", errno);
++      }
++}
++
++static void read_debugregs(int pid, unsigned long *regs)
++{
++      struct user *dummy;
++      int nregs, i;
++
++      dummy = NULL;
++      nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++      for(i = 0; i < nregs; i++){
++              regs[i] = ptrace(PTRACE_PEEKUSR, pid, 
++                               &dummy->u_debugreg[i], 0);
++      }
++}
++
++static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
++static int debugregs_seq = 0;
++
++void arch_enter_kernel(void *task, int pid)
++{
++      read_debugregs(pid, TASK_DEBUGREGS(task));
++      write_debugregs(pid, kernel_debugregs);
++}
++
++void arch_leave_kernel(void *task, int pid)
++{
++      read_debugregs(pid, kernel_debugregs);
++      write_debugregs(pid, TASK_DEBUGREGS(task));
++}
++
++void ptrace_pokeuser(unsigned long addr, unsigned long data)
++{
++      if((addr < offsetof(struct user, u_debugreg[0])) ||
++         (addr > offsetof(struct user, u_debugreg[7])))
++              return;
++      addr -= offsetof(struct user, u_debugreg[0]);
++      addr = addr >> 2;
++      if(kernel_debugregs[addr] == data) return;
++
++      kernel_debugregs[addr] = data;
++      debugregs_seq++;
++}
++
++static void update_debugregs_cb(void *arg)
++{
++      int pid = *((int *) arg);
++
++      write_debugregs(pid, kernel_debugregs);
++}
++
++void update_debugregs(int seq)
++{
++      int me;
++
++      if(seq == debugregs_seq) return;
++
++      me = os_getpid();
++      tracing_cb(update_debugregs_cb, &me);
++}
++
++/*
++ * 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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/sigcontext.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,116 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <string.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "kern_util.h"
++#include "frame_user.h"
++
++int sc_size(void *data)
++{
++      struct arch_frame_data *arch = data;
++
++      return(sizeof(struct sigcontext) + arch->fpstate_size);
++}
++
++int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data)
++{
++      struct arch_frame_data *arch = data;
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      struct _fpstate *to_fp, *from_fp;
++      int err;
++
++      to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
++      from_fp = from->fpstate;
++      err = copy_to_user_proc(to, from, sizeof(*to));
++      if(from_fp != NULL){
++              err |= copy_to_user_proc(&to->fpstate, &to_fp,
++                                       sizeof(to->fpstate));
++              err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
++      }
++      return(err);
++}
++
++int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data)
++{
++      struct arch_frame_data *arch = data;
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      struct _fpstate *to_fp, *from_fp;
++      unsigned long sigs;
++      int err;
++
++      to_fp = to->fpstate;
++      from_fp = from->fpstate;
++      sigs = to->oldmask;
++      err = copy_from_user_proc(to, from, sizeof(*to));
++      to->oldmask = sigs;
++      if(to_fp != NULL)
++              err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
++      return(err);
++}
++
++void sc_to_sc(void *to_ptr, void *from_ptr)
++{
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      int size = sizeof(*to) + signal_frame_sc.arch.fpstate_size;
++
++      memcpy(to, from, size);
++      if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1);
++}
++
++unsigned long *sc_sigmask(void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++
++      return(&sc->oldmask);
++}
++
++int sc_get_fpregs(unsigned long buf, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
++      int err = 0;
++
++      if(from == NULL){
++              err |= clear_user_proc(&to->cw, sizeof(to->cw));
++              err |= clear_user_proc(&to->sw, sizeof(to->sw));
++              err |= clear_user_proc(&to->tag, sizeof(to->tag));
++              err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
++              err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
++              err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
++              err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
++              err |= clear_user_proc(&to->_st, sizeof(to->_st));
++      }
++      else {
++              err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
++              err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
++              err |= copy_to_user_proc(&to->tag, &from->tag, 
++                                       sizeof(to->tag));
++              err |= copy_to_user_proc(&to->ipoff, &from->ipoff, 
++                                       sizeof(to->ipoff));
++              err |= copy_to_user_proc(&to->cssel,& from->cssel, 
++                                       sizeof(to->cssel));
++              err |= copy_to_user_proc(&to->dataoff, &from->dataoff, 
++                                  sizeof(to->dataoff));
++              err |= copy_to_user_proc(&to->datasel, &from->datasel, 
++                                  sizeof(to->datasel));
++              err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
++      }
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/syscalls.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,68 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/mman.h"
++#include "asm/uaccess.h"
++#include "asm/unistd.h"
++
++/*
++ * Perform the select(nd, in, out, ex, tv) and mmap() system
++ * calls. Linux/i386 didn't use to be able to handle more than
++ * 4 system call parameters, so these system calls used a memory
++ * block for parameter passing..
++ */
++
++struct mmap_arg_struct {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++extern int old_mmap(unsigned long addr, unsigned long len,
++                  unsigned long prot, unsigned long flags,
++                  unsigned long fd, unsigned long offset);
++
++int old_mmap_i386(struct mmap_arg_struct *arg)
++{
++      struct mmap_arg_struct a;
++      int err = -EFAULT;
++
++      if (copy_from_user(&a, arg, sizeof(a)))
++              goto out;
++
++      err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
++ out:
++      return err;
++}
++
++struct sel_arg_struct {
++      unsigned long n;
++      fd_set *inp, *outp, *exp;
++      struct timeval *tvp;
++};
++
++int old_select(struct sel_arg_struct *arg)
++{
++      struct sel_arg_struct a;
++
++      if (copy_from_user(&a, arg, sizeof(a)))
++              return -EFAULT;
++      /* sys_select() does the appropriate kernel locking */
++      return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/sysrq.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,30 @@
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "linux/sched.h"
++#include "asm/ptrace.h"
++#include "sysrq.h"
++
++void show_regs(struct pt_regs *regs)
++{
++        printk("\n");
++        printk("EIP: %04lx:[<%08lx>] CPU: %d %s", 
++             0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
++             smp_processor_id(), print_tainted());
++        if (PT_REGS_CS(regs) & 3)
++                printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
++                     PT_REGS_SP(regs));
++        printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
++             print_tainted());
++        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
++                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
++             PT_REGS_ECX(regs), 
++             PT_REGS_EDX(regs));
++        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
++             PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
++             PT_REGS_EBP(regs));
++        printk(" DS: %04lx ES: %04lx\n",
++             0xffff & PT_REGS_DS(regs), 
++             0xffff & PT_REGS_ES(regs));
++
++        show_trace((unsigned long *) &regs);
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/util/Makefile       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,17 @@
++all : mk_sc mk_thread
++
++mk_sc : mk_sc.c
++
++mk_thread : mk_thread_user.o mk_thread_kern.o
++      $(CC) -o mk_thread mk_thread_user.o mk_thread_kern.o
++
++mk_thread_user.o : mk_thread_user.c
++      $(CC) -c $< 
++
++mk_thread_kern.o : mk_thread_kern.c
++      $(CC) $(CFLAGS) -c $< 
++
++clean :
++      $(RM) mk_sc mk_thread
++
++archmrproper : clean
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/util/mk_sc.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,51 @@
++#include <stdio.h>
++#include <signal.h>
++#include <linux/stddef.h>
++
++#define SC_OFFSET(name, field) \
++  printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
++       offsetof(struct sigcontext, field))
++
++#define SC_FP_OFFSET(name, field) \
++  printf("#define " name \
++       "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
++       offsetof(struct _fpstate, field))
++
++#define SC_FP_OFFSET_PTR(name, field, type) \
++  printf("#define " name \
++       "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
++       offsetof(struct _fpstate, field))
++
++int main(int argc, char **argv)
++{
++  SC_OFFSET("SC_IP", eip);
++  SC_OFFSET("SC_SP", esp);
++  SC_OFFSET("SC_FS", fs);
++  SC_OFFSET("SC_GS", gs);
++  SC_OFFSET("SC_DS", ds);
++  SC_OFFSET("SC_ES", es);
++  SC_OFFSET("SC_SS", ss);
++  SC_OFFSET("SC_CS", cs);
++  SC_OFFSET("SC_EFLAGS", eflags);
++  SC_OFFSET("SC_EAX", eax);
++  SC_OFFSET("SC_EBX", ebx);
++  SC_OFFSET("SC_ECX", ecx);
++  SC_OFFSET("SC_EDX", edx);
++  SC_OFFSET("SC_EDI", edi);
++  SC_OFFSET("SC_ESI", esi);
++  SC_OFFSET("SC_EBP", ebp);
++  SC_OFFSET("SC_TRAPNO", trapno);
++  SC_OFFSET("SC_ERR", err);
++  SC_OFFSET("SC_CR2", cr2);
++  SC_OFFSET("SC_FPSTATE", fpstate);
++  SC_FP_OFFSET("SC_FP_CW", cw);
++  SC_FP_OFFSET("SC_FP_SW", sw);
++  SC_FP_OFFSET("SC_FP_TAG", tag);
++  SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
++  SC_FP_OFFSET("SC_FP_CSSEL", cssel);
++  SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
++  SC_FP_OFFSET("SC_FP_DATASEL", datasel);
++  SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
++  SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
++  return(0);
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/util/mk_thread_kern.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,7 @@
++#include "linux/stddef.h"
++#include "linux/sched.h"
++
++int debugreg(void)
++{
++  return(offsetof(struct task_struct, thread.arch.debugregs));
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-i386/util/mk_thread_user.c       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,12 @@
++#include <stdio.h>
++#include <linux/stddef.h>
++#include <asm/user.h>
++
++extern int debugreg(void);
++
++int main(int argc, char **argv)
++{
++  printf("#define TASK_DEBUGREGS(task) ((unsigned long *) "
++       "&(((char *) (task))[%d]))\n", debugreg());
++  return(0);
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ia64/Makefile    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++OBJ = sys.o
++
++OBJS =
++
++all: $(OBJ)
++
++$(OBJ): $(OBJS)
++      rm -f $@
++      $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
++clean:
++      rm -f $(OBJS)
++
++fastdep:
++
++archmrproper:
++
++archclean:
++      rm -f link.ld
++      @$(MAKEBOOT) clean
++
++archdep:
++      @$(MAKEBOOT) dep
++
++modules:
++
++include $(TOPDIR)/Rules.make
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/Makefile     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,80 @@
++OBJ = sys.o
++
++.S.o:
++      $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++
++OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
++      ptrace_user.o sysrq.o
++
++EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel
++
++all: $(OBJ)
++
++$(OBJ): $(OBJS)
++      rm -f $@
++      $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
++
++ptrace_user.o: ptrace_user.c
++      $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++sigcontext.o: sigcontext.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++semaphore.c:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++checksum.S:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
++
++mk_defs.c:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++ppc_defs.head:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++ppc_defs.h: mk_defs.c ppc_defs.head \
++              $(TOPDIR)/include/asm-ppc/mmu.h \
++              $(TOPDIR)/include/asm-ppc/processor.h \
++              $(TOPDIR)/include/asm-ppc/pgtable.h \
++              $(TOPDIR)/include/asm-ppc/ptrace.h
++#     $(CC) $(CFLAGS) -S mk_defs.c
++      cp ppc_defs.head ppc_defs.h
++# for bk, this way we can write to the file even if it's not checked out
++      echo '#define THREAD 608' >> ppc_defs.h
++      echo '#define PT_REGS 8' >> ppc_defs.h
++      echo '#define CLONE_VM 256' >> ppc_defs.h
++#     chmod u+w ppc_defs.h
++#     grep '^#define' mk_defs.s >> ppc_defs.h
++#     rm mk_defs.s
++
++# the asm link is horrible, and breaks the other targets.  This is also
++# not going to work with parallel makes.
++
++checksum.o: checksum.S
++      rm -f asm
++      ln -s $(TOPDIR)/include/asm-ppc asm
++      $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++      rm -f asm
++
++misc.o: misc.S ppc_defs.h
++      rm -f asm
++      ln -s $(TOPDIR)/include/asm-ppc asm
++      $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++      rm -f asm
++
++clean:
++      rm -f $(OBJS)
++      rm -f ppc_defs.h
++      rm -f checksum.S semaphore.c mk_defs.c
++
++fastdep:
++
++dep:
++
++modules:
++
++include $(TOPDIR)/Rules.make
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/misc.S       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,116 @@
++/*
++ * This file contains miscellaneous low-level functions.
++ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
++ *
++ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
++ * and Paul Mackerras.
++ *
++ * A couple of functions stolen from arch/ppc/kernel/misc.S for UML
++ * by Chris Emerson.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ */
++
++#include <linux/config.h>
++#include <asm/processor.h>
++#include "ppc_asm.h"
++
++#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
++#define CACHE_LINE_SIZE               16
++#define LG_CACHE_LINE_SIZE    4
++#define MAX_COPY_PREFETCH     1
++#elif !defined(CONFIG_PPC64BRIDGE)
++#define CACHE_LINE_SIZE               32
++#define LG_CACHE_LINE_SIZE    5
++#define MAX_COPY_PREFETCH     4
++#else
++#define CACHE_LINE_SIZE               128
++#define LG_CACHE_LINE_SIZE    7
++#define MAX_COPY_PREFETCH     1
++#endif /* CONFIG_4xx || CONFIG_8xx */
++
++      .text
++
++/*
++ * Clear a page using the dcbz instruction, which doesn't cause any
++ * memory traffic (except to write out any cache lines which get
++ * displaced).  This only works on cacheable memory.
++ */
++_GLOBAL(clear_page)
++      li      r0,4096/CACHE_LINE_SIZE
++      mtctr   r0
++#ifdef CONFIG_8xx
++      li      r4, 0
++1:    stw     r4, 0(r3)
++      stw     r4, 4(r3)
++      stw     r4, 8(r3)
++      stw     r4, 12(r3)
++#else
++1:    dcbz    0,r3
++#endif
++      addi    r3,r3,CACHE_LINE_SIZE
++      bdnz    1b
++      blr
++
++/*
++ * Copy a whole page.  We use the dcbz instruction on the destination
++ * to reduce memory traffic (it eliminates the unnecessary reads of
++ * the destination into cache).  This requires that the destination
++ * is cacheable.
++ */
++#define COPY_16_BYTES         \
++      lwz     r6,4(r4);       \
++      lwz     r7,8(r4);       \
++      lwz     r8,12(r4);      \
++      lwzu    r9,16(r4);      \
++      stw     r6,4(r3);       \
++      stw     r7,8(r3);       \
++      stw     r8,12(r3);      \
++      stwu    r9,16(r3)
++
++_GLOBAL(copy_page)
++      addi    r3,r3,-4
++      addi    r4,r4,-4
++      li      r5,4
++
++#ifndef CONFIG_8xx
++#if MAX_COPY_PREFETCH > 1
++      li      r0,MAX_COPY_PREFETCH
++      li      r11,4
++      mtctr   r0
++11:   dcbt    r11,r4
++      addi    r11,r11,CACHE_LINE_SIZE
++      bdnz    11b
++#else /* MAX_COPY_PREFETCH == 1 */
++      dcbt    r5,r4
++      li      r11,CACHE_LINE_SIZE+4
++#endif /* MAX_COPY_PREFETCH */
++#endif /* CONFIG_8xx */
++
++      li      r0,4096/CACHE_LINE_SIZE
++      mtctr   r0
++1:
++#ifndef CONFIG_8xx
++      dcbt    r11,r4
++      dcbz    r5,r3
++#endif
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 32
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 64
++      COPY_16_BYTES
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 128
++      COPY_16_BYTES
++      COPY_16_BYTES
++      COPY_16_BYTES
++      COPY_16_BYTES
++#endif
++#endif
++#endif
++      bdnz    1b
++      blr
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/miscthings.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,56 @@
++#include "linux/threads.h"
++#include "linux/stddef.h"  // for NULL
++#include "linux/elf.h"  // for AT_NULL
++
++/* unsigned int local_bh_count[NR_CPUS]; */
++unsigned long isa_io_base = 0;
++
++/* The following function nicked from arch/ppc/kernel/process.c and
++ * adapted slightly */
++/*
++ * XXX ld.so expects the auxiliary table to start on
++ * a 16-byte boundary, so we have to find it and
++ * move it up. :-(
++ */
++void shove_aux_table(unsigned long sp)
++{
++      int argc;
++      char *p;
++      unsigned long e;
++      unsigned long aux_start, offset;
++
++      argc = *(int *)sp;
++      sp += sizeof(int) + (argc + 1) * sizeof(char *);
++      /* skip over the environment pointers */
++      do {
++              p = *(char **)sp;
++              sp += sizeof(char *);
++      } while (p != NULL);
++      aux_start = sp;
++      /* skip to the end of the auxiliary table */
++      do {
++              e = *(unsigned long *)sp;
++              sp += 2 * sizeof(unsigned long);
++      } while (e != AT_NULL);
++      offset = ((aux_start + 15) & ~15) - aux_start;
++      if (offset != 0) {
++              do {
++                      sp -= sizeof(unsigned long);
++                      e = *(unsigned long *)sp;
++                      *(unsigned long *)(sp + offset) = e;
++              } while (sp > aux_start);
++      }
++}
++/* END stuff taken from arch/ppc/kernel/process.c */
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/ptrace.c     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,28 @@
++#include "linux/sched.h"
++#include "asm/ptrace.h"
++
++int putreg(struct task_struct *child, unsigned long regno, 
++                unsigned long value)
++{
++      child->thread.process_regs.regs[regno >> 2] = value;
++      return 0;
++}
++
++unsigned long getreg(struct task_struct *child, unsigned long regno)
++{
++      unsigned long retval = ~0UL;
++
++      retval &= child->thread.process_regs.regs[regno >> 2];
++      return retval;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/ptrace_user.c        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,40 @@
++#include <sys/ptrace.h>
++#include <errno.h>
++#include <asm/ptrace.h>
++#include "sysdep/ptrace.h"
++
++int ptrace_getregs(long pid, unsigned long *regs_out)
++{
++    int i;
++    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
++      errno = 0;
++      regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0);
++      if (errno) {
++          return -errno;
++      }
++    }
++    return 0;
++}
++
++int ptrace_setregs(long pid, unsigned long *regs_in)
++{
++    int i;
++    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
++      if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
++          if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) {
++              return -errno;
++          }
++      }
++    }
++    return 0;
++}
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/sigcontext.c 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,15 @@
++#include "asm/ptrace.h"
++#include "asm/sigcontext.h"
++#include "sysdep/ptrace.h"
++#include "user_util.h"
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/sys-ppc/sysrq.c      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,43 @@
++/* 
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "asm/ptrace.h"
++#include "sysrq.h"
++
++void show_regs(struct pt_regs_subarch *regs)
++{
++      printk("\n");
++      printk("show_regs(): insert regs here.\n");
++#if 0
++        printk("\n");
++        printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip,
++             smp_processor_id());
++        if (regs->xcs & 3)
++                printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp);
++        printk(" EFLAGS: %08lx\n", regs->eflags);
++        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
++                regs->eax, regs->ebx, regs->ecx, regs->edx);
++        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
++                regs->esi, regs->edi, regs->ebp);
++        printk(" DS: %04x ES: %04x\n",
++                0xffff & regs->xds, 0xffff & regs->xes);
++#endif
++
++        show_trace(&regs->gpr[1]);
++}
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/util/Makefile        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,15 @@
++all : mk_task
++
++mk_task : mk_task_user.o mk_task_kern.o
++      $(CC) -o mk_task mk_task_user.o mk_task_kern.o
++
++mk_task_user.o : mk_task_user.c
++      $(CC) -c $< 
++
++mk_task_kern.o : mk_task_kern.c
++      $(CC) $(CFLAGS) -c $< 
++
++clean :
++      $(RM) mk_task *.o *~
++
++archmrproper : clean
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/util/mk_task_kern.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,17 @@
++#include "linux/sched.h"
++#include "linux/stddef.h"
++
++extern void print(char *name, char *type, int offset);
++extern void print_ptr(char *name, char *type, int offset);
++extern void print_head(void);
++extern void print_tail(void);
++
++int main(int argc, char **argv)
++{
++  print_head();
++  print_ptr("TASK_REGS", "struct uml_pt_regs", 
++          offsetof(struct task_struct, thread.regs));
++  print("TASK_PID", "int", offsetof(struct task_struct, pid));
++  print_tail();
++  return(0);
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/arch/um/util/mk_task_user.c  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,30 @@
++#include <stdio.h>
++
++void print(char *name, char *type, int offset)
++{
++  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
++       offset);
++}
++
++void print_ptr(char *name, char *type, int offset)
++{
++  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
++       offset);
++}
++
++void print_head(void)
++{
++  printf("/*\n");
++  printf(" * Generated by mk_task\n");
++  printf(" */\n");
++  printf("\n");
++  printf("#ifndef __TASK_H\n");
++  printf("#define __TASK_H\n");
++  printf("\n");
++}
++
++void print_tail(void)
++{
++  printf("\n");
++  printf("#endif\n");
++}
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/a.out.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,18 @@
++#ifndef __UM_A_OUT_H
++#define __UM_A_OUT_H
++
++#include "asm/arch/a.out.h"
++
++#undef STACK_TOP
++
++extern unsigned long stacksizelim;
++
++extern unsigned long host_task_size;
++
++extern int honeypot;
++
++#define STACK_ROOM (stacksizelim)
++
++#define STACK_TOP (honeypot ? host_task_size : task_size)
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/archparam-i386.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,80 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_ARCHPARAM_I386_H
++#define __UM_ARCHPARAM_I386_H
++
++/********* Bits for asm-um/elf.h ************/
++
++#include "user.h"
++
++#define ELF_PLATFORM "i586"
++
++#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
++
++typedef struct user_i387_struct elf_fpregset_t;
++typedef unsigned long elf_greg_t;
++
++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
++typedef elf_greg_t elf_gregset_t[ELF_NGREG];
++
++#define ELF_DATA        ELFDATA2LSB
++#define ELF_ARCH        EM_386
++
++#define ELF_PLAT_INIT(regs) do { \
++      PT_REGS_EBX(regs) = 0; \
++      PT_REGS_ECX(regs) = 0; \
++      PT_REGS_EDX(regs) = 0; \
++      PT_REGS_ESI(regs) = 0; \
++      PT_REGS_EDI(regs) = 0; \
++      PT_REGS_EBP(regs) = 0; \
++      PT_REGS_EAX(regs) = 0; \
++} while(0)
++
++/* Shamelessly stolen from include/asm-i386/elf.h */
++
++#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \
++      pr_reg[0] = PT_REGS_EBX(regs);          \
++      pr_reg[1] = PT_REGS_ECX(regs);          \
++      pr_reg[2] = PT_REGS_EDX(regs);          \
++      pr_reg[3] = PT_REGS_ESI(regs);          \
++      pr_reg[4] = PT_REGS_EDI(regs);          \
++      pr_reg[5] = PT_REGS_EBP(regs);          \
++      pr_reg[6] = PT_REGS_EAX(regs);          \
++      pr_reg[7] = PT_REGS_DS(regs);           \
++      pr_reg[8] = PT_REGS_ES(regs);           \
++      /* fake once used fs and gs selectors? */       \
++      pr_reg[9] = PT_REGS_DS(regs);           \
++      pr_reg[10] = PT_REGS_DS(regs);          \
++      pr_reg[11] = regs->regs.syscall;        \
++      pr_reg[12] = PT_REGS_IP(regs);          \
++      pr_reg[13] = PT_REGS_CS(regs);          \
++      pr_reg[14] = PT_REGS_EFLAGS(regs);      \
++      pr_reg[15] = PT_REGS_SP(regs);          \
++      pr_reg[16] = PT_REGS_SS(regs);          \
++} while(0);
++
++/********* Bits for asm-um/delay.h **********/
++
++typedef unsigned long um_udelay_t;
++
++/********* Nothing for asm-um/hardirq.h **********/
++
++/********* Nothing for asm-um/hw_irq.h **********/
++
++/********* Nothing for asm-um/string.h **********/
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/archparam-ppc.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,41 @@
++#ifndef __UM_ARCHPARAM_PPC_H
++#define __UM_ARCHPARAM_PPC_H
++
++/********* Bits for asm-um/elf.h ************/
++
++#define ELF_PLATFORM (0)
++
++#define ELF_ET_DYN_BASE (0x08000000)
++
++/* the following stolen from asm-ppc/elf.h */
++#define ELF_NGREG     48      /* includes nip, msr, lr, etc. */
++#define ELF_NFPREG    33      /* includes fpscr */
++/* General registers */
++typedef unsigned long elf_greg_t;
++typedef elf_greg_t elf_gregset_t[ELF_NGREG];
++
++/* Floating point registers */
++typedef double elf_fpreg_t;
++typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
++
++#define ELF_DATA        ELFDATA2MSB
++#define ELF_ARCH      EM_PPC
++
++/********* Bits for asm-um/delay.h **********/
++
++typedef unsigned int um_udelay_t;
++
++/********* Bits for asm-um/hw_irq.h **********/
++
++struct hw_interrupt_type;
++
++/********* Bits for asm-um/hardirq.h **********/
++
++#define irq_enter(cpu, irq) hardirq_enter(cpu)
++#define irq_exit(cpu, irq) hardirq_exit(cpu)
++
++/********* Bits for asm-um/string.h **********/
++
++#define __HAVE_ARCH_STRRCHR
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/arch-signal-i386.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,24 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_ARCH_SIGNAL_I386_H
++#define __UM_ARCH_SIGNAL_I386_H
++
++struct arch_signal_context {
++      unsigned long extrasigs[_NSIG_WORDS];
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/atomic.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_ATOMIC_H
++#define __UM_ATOMIC_H
++
++#include "asm/arch/atomic.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/bitops.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BITOPS_H
++#define __UM_BITOPS_H
++
++#include "asm/arch/bitops.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/boot.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BOOT_H
++#define __UM_BOOT_H
++
++#include "asm/arch/boot.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/bugs.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BUGS_H
++#define __UM_BUGS_H
++
++void check_bugs(void);
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/byteorder.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BYTEORDER_H
++#define __UM_BYTEORDER_H
++
++#include "asm/arch/byteorder.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/cache.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_CACHE_H
++#define __UM_CACHE_H
++
++#define        L1_CACHE_BYTES  32
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/checksum.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_CHECKSUM_H
++#define __UM_CHECKSUM_H
++
++#include "asm/arch/checksum.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/cobalt.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_COBALT_H
++#define __UM_COBALT_H
++
++#include "asm/arch/cobalt.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/current.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,33 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_CURRENT_H
++#define __UM_CURRENT_H
++
++#ifndef __ASSEMBLY__
++
++#include "linux/config.h"
++#include "asm/page.h"
++
++struct task_struct;
++
++#define CURRENT_TASK(dummy) (((unsigned long) &dummy) & (PAGE_MASK << 2))
++
++#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); })
++
++#endif /* __ASSEMBLY__ */
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/delay.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,7 @@
++#ifndef __UM_DELAY_H
++#define __UM_DELAY_H
++
++#include "asm/arch/delay.h"
++#include "asm/archparam.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/desc.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_DESC_H
++#define __UM_DESC_H
++
++#include "asm/arch/desc.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/div64.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef _UM_DIV64_H
++#define _UM_DIV64_H
++
++#include "asm/arch/div64.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/dma.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++#ifndef __UM_DMA_H
++#define __UM_DMA_H
++
++#include "asm/io.h"
++
++extern unsigned long uml_physmem;
++
++#define MAX_DMA_ADDRESS (uml_physmem)
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/elf.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,18 @@
++#ifndef __UM_ELF_H
++#define __UM_ELF_H
++
++#include "asm/archparam.h"
++
++#define ELF_HWCAP (0)
++
++#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
++
++#define ELF_EXEC_PAGESIZE 4096
++
++#define elf_check_arch(x) (1)
++
++#define ELF_CLASS ELFCLASS32
++
++#define USE_ELF_CORE_DUMP
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/errno.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_ERRNO_H
++#define __UM_ERRNO_H
++
++#include "asm/arch/errno.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/fcntl.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_FCNTL_H
++#define __UM_FCNTL_H
++
++#include "asm/arch/fcntl.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/floppy.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_FLOPPY_H
++#define __UM_FLOPPY_H
++
++#include "asm/arch/floppy.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/hardirq.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_HARDIRQ_H
++#define __UM_HARDIRQ_H
++
++#include "asm/arch/hardirq.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/hdreg.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_HDREG_H
++#define __UM_HDREG_H
++
++#include "asm/arch/hdreg.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/highmem.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_HIGHMEM_H
++#define __UM_HIGHMEM_H
++
++#include "asm/arch/highmem.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/hw_irq.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++#ifndef _ASM_UM_HW_IRQ_H
++#define _ASM_UM_HW_IRQ_H
++
++#include "asm/irq.h"
++#include "asm/archparam.h"
++
++static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
++{}
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ide.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IDE_H
++#define __UM_IDE_H
++
++#include "asm/arch/ide.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/init.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,11 @@
++#ifndef _UM_INIT_H
++#define _UM_INIT_H
++
++#ifdef notdef
++#define __init
++#define __initdata
++#define __initfunc(__arginit) __arginit
++#define __cacheline_aligned 
++#endif
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ioctl.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTL_H
++#define __UM_IOCTL_H
++
++#include "asm/arch/ioctl.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ioctls.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTLS_H
++#define __UM_IOCTLS_H
++
++#include "asm/arch/ioctls.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/io.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,25 @@
++#ifndef __UM_IO_H
++#define __UM_IO_H
++
++#include "asm/page.h"
++
++#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */
++
++static inline int inb(unsigned long i) { return(0); }
++static inline void outb(char c, unsigned long i) { }
++
++/*
++ * Change virtual addresses to physical addresses and vv.
++ * These are pretty trivial
++ */
++static inline unsigned long virt_to_phys(volatile void * address)
++{
++      return __pa((void *) address);
++}
++
++static inline void * phys_to_virt(unsigned long address)
++{
++      return __va(address);
++}
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ipcbuf.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPCBUF_H
++#define __UM_IPCBUF_H
++
++#include "asm/arch/ipcbuf.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ipc.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPC_H
++#define __UM_IPC_H
++
++#include "asm/arch/ipc.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/irq.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,35 @@
++#ifndef __UM_IRQ_H
++#define __UM_IRQ_H
++
++/* The i386 irq.h has a struct task_struct in a prototype without including
++ * sched.h.  This forward declaration kills the resulting warning.
++ */
++struct task_struct;
++
++#include "asm/arch/irq.h"
++#include "asm/ptrace.h"
++
++#undef NR_IRQS
++
++#define TIMER_IRQ             0
++#define UMN_IRQ                       1
++#define CONSOLE_IRQ           2
++#define CONSOLE_WRITE_IRQ     3
++#define UBD_IRQ                       4
++#define UM_ETH_IRQ            5
++#define SSL_IRQ                       6
++#define SSL_WRITE_IRQ         7
++#define ACCEPT_IRQ            8
++#define MCONSOLE_IRQ          9
++#define WINCH_IRQ             10
++#define SIGIO_WRITE_IRQ       11
++#define TELNETD_IRQ           12
++
++#define LAST_IRQ TELNETD_IRQ
++#define NR_IRQS (LAST_IRQ + 1)
++
++extern int um_request_irq(unsigned int irq, int fd, int type,
++                        void (*handler)(int, void *, struct pt_regs *),
++                        unsigned long irqflags,  const char * devname,
++                        void *dev_id);
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/keyboard.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_KEYBOARD_H
++#define __UM_KEYBOARD_H
++
++#include "asm/arch/keyboard.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/linux_logo.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_LINUX_LOGO_H
++#define __UM_LINUX_LOGO_H
++
++#include "asm/arch/linux_logo.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/locks.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_LOCKS_H
++#define __UM_LOCKS_H
++
++#include "asm/arch/locks.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/mca_dma.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef mca___UM_DMA_H
++#define mca___UM_DMA_H
++
++#include "asm/arch/mca_dma.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/mman.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MMAN_H
++#define __UM_MMAN_H
++
++#include "asm/arch/mman.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/mmu_context.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,25 @@
++#ifndef __UM_MMU_CONTEXT_H
++#define __UM_MMU_CONTEXT_H
++
++#include "linux/sched.h"
++
++#define init_new_context(task, mm) (0)
++#define get_mmu_context(task) do ; while(0)
++#define activate_context(tsk) do ; while(0)
++#define destroy_context(mm) do ; while(0)
++
++static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
++{
++}
++
++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
++                           struct task_struct *tsk, unsigned cpu)
++{
++}
++
++static inline void enter_lazy_tlb(struct mm_struct *mm, 
++                                struct task_struct *tsk, unsigned cpu)
++{
++}
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/mmu.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __MMU_H
++#define __MMU_H
++
++#include "asm/arch/mmu.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/module.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MODULE_H
++#define __UM_MODULE_H
++
++#include "asm/arch/module.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/msgbuf.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MSGBUF_H
++#define __UM_MSGBUF_H
++
++#include "asm/arch/msgbuf.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/mtrr.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MTRR_H
++#define __UM_MTRR_H
++
++#include "asm/arch/mtrr.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/namei.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_NAMEI_H
++#define __UM_NAMEI_H
++
++#include "asm/arch/namei.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/page.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,49 @@
++#ifndef __UM_PAGE_H
++#define __UM_PAGE_H
++
++struct page;
++
++#include "asm/arch/page.h"
++
++#undef BUG
++#undef PAGE_BUG
++#undef __pa
++#undef __va
++#undef virt_to_page
++#undef VALID_PAGE
++#undef PAGE_OFFSET
++#undef KERNELBASE
++
++#define PAGE_OFFSET (uml_physmem)
++#define KERNELBASE PAGE_OFFSET
++
++#ifndef __ASSEMBLY__
++
++extern void stop(void);
++
++#define BUG() do { \
++      panic("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
++} while (0)
++
++#define PAGE_BUG(page) do { \
++      BUG(); \
++} while (0)
++
++#endif /* __ASSEMBLY__ */
++
++#define __va_space (8*1024*1024)
++
++extern unsigned long region_pa(void *virt);
++extern void *region_va(unsigned long phys);
++
++#define __pa(virt) region_pa((void *) (virt))
++#define __va(phys) region_va((unsigned long) (phys))
++
++extern struct page *page_mem_map(struct page *page);
++
++#define VALID_PAGE(page) (page_mem_map(page) != NULL)
++
++extern struct page *arch_validate(struct page *page, int mask, int order);
++#define HAVE_ARCH_VALIDATE
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/page_offset.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1 @@
++#define PAGE_OFFSET_RAW (uml_physmem)
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/param.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,26 @@
++#ifndef _UM_PARAM_H
++#define _UM_PARAM_H
++
++#ifndef HZ
++#define HZ 52
++#endif
++
++#define EXEC_PAGESIZE   4096
++
++#ifndef NGROUPS
++#define NGROUPS         32
++#endif
++
++#ifndef NOGROUP
++#define NOGROUP         (-1)
++#endif
++
++#define MAXHOSTNAMELEN  64      /* max length of hostname */
++
++#ifdef __KERNEL__
++# define CLOCKS_PER_SEC 100    /* frequency at which times() counts */
++#endif
++
++#include <asm/arch/param.h>
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/pci.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_PCI_H
++#define __UM_PCI_H
++
++#define PCI_DMA_BUS_IS_PHYS     (1)
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/pgalloc.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,144 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PGALLOC_H
++#define __UM_PGALLOC_H
++
++#include "linux/mm.h"
++
++#define pgd_quicklist (current_cpu_data.pgd_quick)
++#define pmd_quicklist (current_cpu_data.pmd_quick)
++#define pte_quicklist (current_cpu_data.pte_quick)
++#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
++
++#define pmd_populate(mm, pmd, pte) \
++              set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) (pte)))
++
++/*
++ * Allocate and free page tables.
++ */
++
++static inline pgd_t *get_pgd_slow(void)
++{
++      pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
++
++      if (pgd) {
++              memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
++              memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
++      }
++      return pgd;
++}
++
++static inline pgd_t *get_pgd_fast(void)
++{
++      unsigned long *ret;
++
++      if ((ret = pgd_quicklist) != NULL) {
++              pgd_quicklist = (unsigned long *)(*ret);
++              ret[0] = 0;
++              pgtable_cache_size--;
++      } else
++              ret = (unsigned long *)get_pgd_slow();
++      return (pgd_t *)ret;
++}
++
++static inline void free_pgd_fast(pgd_t *pgd)
++{
++      *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
++      pgd_quicklist = (unsigned long *) pgd;
++      pgtable_cache_size++;
++}
++
++static inline void free_pgd_slow(pgd_t *pgd)
++{
++      free_page((unsigned long)pgd);
++}
++
++static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
++{
++      pte_t *pte;
++
++      pte = (pte_t *) __get_free_page(GFP_KERNEL);
++      if (pte)
++              clear_page(pte);
++      return pte;
++}
++
++static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
++{
++      unsigned long *ret;
++
++      if ((ret = (unsigned long *)pte_quicklist) != NULL) {
++              pte_quicklist = (unsigned long *)(*ret);
++              ret[0] = ret[1];
++              pgtable_cache_size--;
++      }
++      return (pte_t *)ret;
++}
++
++static inline void pte_free_pte_fast(pte_t *pte)
++{
++      *(unsigned long *)pte = (unsigned long) pte_quicklist;
++      pte_quicklist = (unsigned long *) pte;
++      pgtable_cache_size++;
++}
++
++static inline void pte_free_slow(pte_t *pte)
++{
++      free_page((unsigned long)pte);
++}
++
++#define pte_free(pte)           pte_free_slow(pte)
++#define pgd_free(pgd)           free_pgd_slow(pgd)
++#define pgd_alloc(mm)           get_pgd_fast()
++
++/*
++ * allocating and freeing a pmd is trivial: the 1-entry pmd is
++ * inside the pgd, so has no extra memory associated with it.
++ */
++
++#define pmd_alloc_one_fast(mm, addr)  ({ BUG(); ((pmd_t *)1); })
++#define pmd_alloc_one(mm, addr)               ({ BUG(); ((pmd_t *)2); })
++#define pmd_free_slow(x)              do { } while (0)
++#define pmd_free_fast(x)              do { } while (0)
++#define pmd_free(x)                   do { } while (0)
++#define pgd_populate(mm, pmd, pte)    BUG()
++
++/*
++ * TLB flushing:
++ *
++ *  - flush_tlb() flushes the current mm struct TLBs
++ *  - flush_tlb_all() flushes all processes TLBs
++ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
++ *  - flush_tlb_page(vma, vmaddr) flushes one page
++ *  - flush_tlb_kernel_vm() flushes the kernel vm area
++ *  - flush_tlb_range(mm, start, end) flushes a range of pages
++ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ */
++
++extern void flush_tlb_all(void);
++extern void flush_tlb_mm(struct mm_struct *mm);
++extern void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
++                          unsigned long end);
++extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
++extern void flush_tlb_kernel_vm(void);
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++                                    unsigned long start, unsigned long end)
++{
++}
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/pgtable.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,408 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Derived from include/asm-i386/pgtable.h
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PGTABLE_H
++#define __UM_PGTABLE_H
++
++#include "linux/sched.h"
++#include "asm/processor.h"
++#include "asm/page.h"
++
++extern pgd_t swapper_pg_dir[1024];
++
++#define flush_cache_all() do ; while (0)
++#define flush_cache_mm(mm) do ; while (0)
++#define flush_cache_range(vma, start, end) do ; while (0)
++#define flush_cache_page(vma, vmaddr) do ; while (0)
++#define flush_page_to_ram(page) do ; while (0)
++#define flush_dcache_page(page)       do ; while (0)
++#define flush_icache_range(from, to) do ; while (0)
++#define flush_icache_page(vma,pg) do ; while (0)
++
++extern void pte_free(pte_t *pte);
++
++extern void pgd_free(pgd_t *pgd);
++
++extern int do_check_pgt_cache(int, int);
++
++/* zero page used for uninitialized stuff */
++extern unsigned long *empty_zero_page;
++
++#define pgtable_cache_init() do ; while (0)
++
++/* PMD_SHIFT determines the size of the area a second-level page table can map */
++#define PMD_SHIFT     22
++#define PMD_SIZE      (1UL << PMD_SHIFT)
++#define PMD_MASK      (~(PMD_SIZE-1))
++
++/* PGDIR_SHIFT determines what a third-level page table entry can map */
++#define PGDIR_SHIFT   22
++#define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
++#define PGDIR_MASK    (~(PGDIR_SIZE-1))
++
++/*
++ * entries per page directory level: the i386 is two-level, so
++ * we don't really have any PMD directory physically.
++ */
++#define PTRS_PER_PTE  1024
++#define PTRS_PER_PMD  1
++#define PTRS_PER_PGD  1024
++#define USER_PTRS_PER_PGD     (TASK_SIZE/PGDIR_SIZE)
++#define FIRST_USER_PGD_NR       0
++
++#define pte_ERROR(e) \
++        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
++#define pmd_ERROR(e) \
++        printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
++#define pgd_ERROR(e) \
++        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
++/*
++ * pgd entries used up by user/kernel:
++ */
++
++#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
++#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
++
++#ifndef __ASSEMBLY__
++/* Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts.  That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++
++extern unsigned long high_physmem;
++extern unsigned long end_vm;
++
++#define VMALLOC_OFFSET        (__va_space)
++#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++#define VMALLOC_END   (end_vm)
++
++#define _PAGE_PRESENT 0x001
++#define _PAGE_NEWPAGE 0x002
++#define _PAGE_PROTNONE        0x004   /* If not present */
++#define _PAGE_RW      0x008
++#define _PAGE_USER    0x010
++#define _PAGE_ACCESSED        0x020
++#define _PAGE_DIRTY   0x040
++#define _PAGE_NEWPROT   0x080
++
++#define REGION_MASK   0xf0000000
++#define REGION_SHIFT  28
++
++#define _PAGE_TABLE   (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _PAGE_CHG_MASK        (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++#define PAGE_NONE     __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
++#define PAGE_SHARED   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_KERNEL   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
++#define PAGE_KERNEL_RO        __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
++
++/*
++ * The i386 can't do page protection for execute, and considers that the same are read.
++ * Also, write permissions imply read permissions. This is the closest we can get..
++ */
++#define __P000        PAGE_NONE
++#define __P001        PAGE_READONLY
++#define __P010        PAGE_COPY
++#define __P011        PAGE_COPY
++#define __P100        PAGE_READONLY
++#define __P101        PAGE_READONLY
++#define __P110        PAGE_COPY
++#define __P111        PAGE_COPY
++
++#define __S000        PAGE_NONE
++#define __S001        PAGE_READONLY
++#define __S010        PAGE_SHARED
++#define __S011        PAGE_SHARED
++#define __S100        PAGE_READONLY
++#define __S101        PAGE_READONLY
++#define __S110        PAGE_SHARED
++#define __S111        PAGE_SHARED
++
++/*
++ * Define this if things work differently on an i386 and an i486:
++ * it will (on an i486) warn about kernel memory accesses that are
++ * done without a 'verify_area(VERIFY_WRITE,..)'
++ */
++#undef TEST_VERIFY_AREA
++
++/* page table for 0-4MB for everybody */
++extern unsigned long pg0[1024];
++
++/*
++ * BAD_PAGETABLE is used when we need a bogus page-table, while
++ * BAD_PAGE is used for a bogus page.
++ *
++ * ZERO_PAGE is a global shared page that is always zero: used
++ * for zero-mapped memory areas etc..
++ */
++extern pte_t __bad_page(void);
++extern pte_t * __bad_pagetable(void);
++
++#define BAD_PAGETABLE __bad_pagetable()
++#define BAD_PAGE __bad_page()
++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
++
++/* number of bits that fit into a memory pointer */
++#define BITS_PER_PTR                  (8*sizeof(unsigned long))
++
++/* to align the pointer to a pointer address */
++#define PTR_MASK                      (~(sizeof(void*)-1))
++
++/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
++/* 64-bit machines, beware!  SRB. */
++#define SIZEOF_PTR_LOG2                       2
++
++/* to find an entry in a page-table */
++#define PAGE_PTR(address) \
++((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
++
++#define pte_none(x)   !(pte_val(x) & ~_PAGE_NEWPAGE)
++#define pte_present(x)        (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
++
++#define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
++
++#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT)
++#define pte_region_index(x) phys_region_index(pte_val(x))
++
++#define pmd_none(x)   (!(pmd_val(x) & ~_PAGE_NEWPAGE))
++#define       pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
++#define pmd_present(x)        (pmd_val(x) & _PAGE_PRESENT)
++#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
++
++#define pmd_newpage(x)  (pmd_val(x) & _PAGE_NEWPAGE)
++#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE)
++
++/*
++ * The "pgd_xxx()" functions here are trivial for a folded two-level
++ * setup: the pgd is never bad, and a pmd always exists (as it's folded
++ * into the pgd entry)
++ */
++static inline int pgd_none(pgd_t pgd)         { return 0; }
++static inline int pgd_bad(pgd_t pgd)          { return 0; }
++static inline int pgd_present(pgd_t pgd)      { return 1; }
++static inline void pgd_clear(pgd_t * pgdp)    { }
++
++
++/*
++ * Permanent address of a page. Obviously must never be
++ * called on a highmem page.
++ */
++
++/*
++ * this is defined in include/linux/mm.h for chaos kernels -bzzz
++#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
++ */
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++extern struct page *pte_mem_map(pte_t pte);
++extern struct page *phys_mem_map(unsigned long phys);
++
++#define pte_page(x) (pte_mem_map(x) + ((phys_addr(pte_val(x))) >> PAGE_SHIFT))
++#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
++#define mk_phys(a, r) ((a) + (r << REGION_SHIFT))
++#define phys_addr(p) ((p) & ~REGION_MASK)
++#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT))
++#define virt_to_page(kaddr) \
++      (phys_mem_map(__pa(kaddr)) + (phys_addr(__pa(kaddr)) >> PAGE_SHIFT))
++
++static inline pte_t pte_mknewprot(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_NEWPROT;
++      return(pte);
++}
++
++static inline pte_t pte_mknewpage(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_NEWPAGE;
++      return(pte);
++}
++
++static inline void set_pte(pte_t *pteptr, pte_t pteval)
++{
++      /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
++       * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
++       * mapped pages.
++       */
++      *pteptr = pte_mknewpage(pteval);
++      if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
++}
++
++/*
++ * (pmds are folded into pgds so this doesnt get actually called,
++ * but the define is needed for a generic inline function.)
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
++static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
++static inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
++static inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
++static inline int pte_write(pte_t pte)        { return pte_val(pte) & _PAGE_RW; }
++static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
++static inline int pte_newprot(pte_t pte)
++{ 
++      return(pte_present(pte) && (pte_val(pte) & _PAGE_NEWPROT)); 
++}
++
++static inline pte_t pte_rdprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_USER; 
++      return(pte_mknewprot(pte));
++}
++
++static inline pte_t pte_exprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_USER;
++      return(pte_mknewprot(pte));
++}
++
++static inline pte_t pte_mkclean(pte_t pte)
++{
++      pte_val(pte) &= ~_PAGE_DIRTY; 
++      return(pte);
++}
++
++static inline pte_t pte_mkold(pte_t pte)      
++{ 
++      pte_val(pte) &= ~_PAGE_ACCESSED; 
++      return(pte);
++}
++
++static inline pte_t pte_wrprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_RW; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkread(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_USER; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkexec(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_USER; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkdirty(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_DIRTY; 
++      return(pte);
++}
++
++static inline pte_t pte_mkyoung(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_ACCESSED; 
++      return(pte);
++}
++
++static inline pte_t pte_mkwrite(pte_t pte)    
++{
++      pte_val(pte) |= _PAGE_RW; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkuptodate(pte_t pte) 
++{
++      pte_val(pte) &= ~_PAGE_NEWPAGE;
++      if(pte_present(pte)) pte_val(pte) &= ~_PAGE_NEWPROT;
++      return(pte); 
++}
++
++extern unsigned long page_to_phys(struct page *page);
++
++/*
++ * Conversion functions: convert a page and protection to a page entry,
++ * and a page entry and page directory to the page they refer to.
++ */
++
++#define mk_pte(page, pgprot) \
++({                                    \
++      pte_t __pte;                    \
++                                        \
++      pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\
++      if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \
++      __pte;                          \
++})
++
++/* This takes a physical page address that is used by the remapping functions */
++#define mk_pte_phys(physpage, pgprot) \
++      pte_mknewpage(mk_pte(phys_page(physpage), pgprot))
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++      pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
++      if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte));
++      return pte; 
++}
++
++#define pmd_page(pmd) (pmd_val(pmd) & PAGE_MASK)
++
++/* to find an entry in a page-table-directory. */
++#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++
++/* to find an entry in a page-table-directory */
++#define pgd_offset(mm, address) \
++((mm)->pgd + ((address) >> PGDIR_SHIFT))
++
++/* to find an entry in a kernel page-table-directory */
++#define pgd_offset_k(address) pgd_offset(&init_mm, address)
++
++/* Find an entry in the second-level page table.. */
++static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
++{
++      return (pmd_t *) dir;
++}
++
++/* Find an entry in the third-level page table.. */ 
++#define pte_offset(pmd, address) \
++((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
++
++#define update_mmu_cache(vma,address,pte) do ; while (0)
++
++/* Encode and de-code a swap entry */
++#define SWP_TYPE(x)                   (((x).val >> 3) & 0x7f)
++#define SWP_OFFSET(x)                 ((x).val >> 10)
++
++#define SWP_ENTRY(type, offset) \
++      ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
++#define pte_to_swp_entry(pte) \
++      ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
++#define swp_entry_to_pte(x)           ((pte_t) { (x).val })
++
++#define PageSkip(x) (0)
++#define kern_addr_valid(addr) (1)
++
++#include <asm-generic/pgtable.h>
++
++#endif
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/poll.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_POLL_H
++#define __UM_POLL_H
++
++#include "asm/arch/poll.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/posix_types.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_POSIX_TYPES_H
++#define __UM_POSIX_TYPES_H
++
++#include "asm/arch/posix_types.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/processor-generic.h   2003-09-09 16:20:55.000000000 +0400
+@@ -0,0 +1,170 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PROCESSOR_GENERIC_H
++#define __UM_PROCESSOR_GENERIC_H
++
++struct pt_regs;
++
++struct task_struct;
++
++#include "linux/config.h"
++#include "linux/signal.h"
++#include "asm/segment.h"
++#include "asm/ptrace.h"
++#include "asm/siginfo.h"
++
++struct mm_struct;
++
++#define current_text_addr() ((void *) 0)
++
++#define cpu_relax()   do ; while (0)
++
++struct thread_struct {
++      int extern_pid;
++      int tracing;
++      int forking;
++      unsigned long kernel_stack;
++      int nsyscalls;
++      struct pt_regs regs;
++      unsigned long cr2;
++      int err;
++      void *fault_addr;
++      void *fault_catcher;
++      int vm_seq;
++      struct task_struct *prev_sched;
++      unsigned long temp_stack;
++      int switch_pipe[2];
++      void *jmp;
++      struct arch_thread arch;
++      int singlestep_syscall;
++      struct {
++              int op;
++              union {
++                      struct {
++                              int pid;
++                      } fork, exec;
++                      struct {
++                              int (*proc)(void *);
++                              void *arg;
++                      } thread;
++                      struct {
++                              void (*proc)(void *);
++                              void *arg;
++                      } cb;
++              } u;
++      } request;
++};
++
++#define INIT_THREAD \
++{ \
++      extern_pid:             -1, \
++      tracing:                0, \
++      forking:                0, \
++      kernel_stack:           0, \
++      nsyscalls:              0, \
++        regs:                 EMPTY_REGS, \
++      cr2:                    0, \
++      err:                    0, \
++      fault_addr:             NULL, \
++      vm_seq:                 0, \
++      prev_sched:             NULL, \
++      temp_stack:             0, \
++      switch_pipe:            { -1, -1 }, \
++      jmp:                    NULL, \
++      arch:                   INIT_ARCH_THREAD, \
++      singlestep_syscall:     0, \
++      request:                { 0 } \
++}
++
++#define THREAD_SIZE (2*PAGE_SIZE)
++
++typedef struct {
++      unsigned long seg;
++} mm_segment_t;
++
++extern struct task_struct *alloc_task_struct(void);
++extern void free_task_struct(struct task_struct *task);
++
++#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
++
++extern void release_thread(struct task_struct *);
++extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
++extern void dump_thread(struct pt_regs *regs, struct user *u);
++
++static inline void release_segments(struct mm_struct *mm)
++{
++}
++
++static inline void copy_segments(struct task_struct *p, 
++                               struct mm_struct *new_mm)
++{
++}
++
++#define forget_segments() do ; while(0)
++
++extern unsigned long thread_saved_pc(struct thread_struct *t);
++
++/*
++extern unsigned long init_task_ptr;
++
++#define init_task_u (*((union task_union *) init_task_ptr))
++*/
++#define init_task     (init_task_union.task)
++#define init_stack    (init_task_union.stack)
++
++/*
++ * User space process size: 3GB (default).
++ */
++extern unsigned long task_size;
++
++#define TASK_SIZE     (task_size)
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE    (0x40000000)
++
++extern void start_thread(struct pt_regs *regs, unsigned long entry, 
++                       unsigned long stack);
++extern long arch_kernel_thread(int (*fn)(void *), void *, unsigned long);
++
++struct cpuinfo_um {
++      unsigned long loops_per_jiffy;
++      unsigned long *pgd_quick;
++      unsigned long *pmd_quick;
++      unsigned long *pte_quick;
++      unsigned long pgtable_cache_sz;  
++      int ipi_pipe[2];
++};
++
++extern struct cpuinfo_um boot_cpu_data;
++
++#define my_cpu_data           cpu_data[smp_processor_id()]
++
++#ifdef CONFIG_SMP
++extern struct cpuinfo_um cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++#define KSTK_EIP(tsk) (PT_REGS_IP(&tsk->thread.regs))
++#define KSTK_ESP(tsk) (PT_REGS_SP(&tsk->thread.regs))
++#define get_wchan(p) (0)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/processor-i386.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,35 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PROCESSOR_I386_H
++#define __UM_PROCESSOR_I386_H
++
++extern int cpu_has_xmm;
++extern int cpu_has_cmov;
++
++struct arch_thread {
++      unsigned long debugregs[8];
++      int debugregs_seq;
++};
++
++#define INIT_ARCH_THREAD { debugregs :                { [ 0 ... 7 ] = 0 }, \
++                           debugregs_seq :    0 }
++
++#include "asm/arch/user.h"
++
++#include "asm/processor-generic.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/processor-ppc.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,15 @@
++#ifndef __UM_PROCESSOR_PPC_H
++#define __UM_PROCESSOR_PPC_H
++
++#if defined(__ASSEMBLY__)
++
++#define CONFIG_ALL_PPC
++#include "arch/processor.h"
++
++#else
++
++#include "asm/processor-generic.h"
++
++#endif
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ptrace-generic.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,71 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PTRACE_GENERIC_H
++#define __UM_PTRACE_GENERIC_H
++
++#ifndef __ASSEMBLY__
++
++#include "asm/current.h"
++
++#define pt_regs pt_regs_subarch
++#define show_regs show_regs_subarch
++
++#include "asm/arch/ptrace.h"
++
++#undef pt_regs
++#undef show_regs
++#undef user_mode
++#undef instruction_pointer
++
++#include "sysdep/ptrace.h"
++
++struct pt_regs {
++      struct uml_pt_regs regs;
++};
++
++#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
++
++#define PT_REGS_IP(r) UPT_IP(&(r)->regs)
++#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
++
++#define PT_REG(r, reg) UPT_REG(&(r)->regs, reg)
++#define PT_REGS_SET(r, reg, val) UPT_SET(&(r)->regs, reg, val)
++
++#define PT_REGS_SET_SYSCALL_RETURN(r, res) \
++      UPT_SET_SYSCALL_RETURN(&(r)->regs, res)
++#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs)
++
++#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs)
++
++#define PT_REGS_SC(r) UPT_SC(&(r)->regs)
++
++struct task_struct;
++
++extern unsigned long getreg(struct task_struct *child, int regno);
++extern int putreg(struct task_struct *child, int regno, unsigned long value);
++extern int get_fpregs(unsigned long buf, struct task_struct *child);
++extern int set_fpregs(unsigned long buf, struct task_struct *child);
++extern int get_fpxregs(unsigned long buf, struct task_struct *child);
++extern int set_fpxregs(unsigned long buf, struct task_struct *tsk);
++
++extern void show_regs(struct pt_regs *regs);
++
++#define INIT_TASK_SIZE (4 * PAGE_SIZE)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/ptrace-i386.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,45 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PTRACE_I386_H
++#define __UM_PTRACE_I386_H
++
++#include "asm/ptrace-generic.h"
++
++#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
++#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
++#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
++#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
++#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
++#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
++#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
++
++#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
++#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
++#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
++#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
++#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
++#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
++
++#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
++
++#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
++#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
++#define PT_FIX_EXEC_STACK(sp) do ; while(0)
++
++#define user_mode(r) ((r)->regs.is_user)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/resource.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_RESOURCE_H
++#define __UM_RESOURCE_H
++
++#include "asm/arch/resource.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/rwlock.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_RWLOCK_H
++#define __UM_RWLOCK_H
++
++#include "asm/arch/rwlock.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/rwsem.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++#ifndef __UM_RWSEM_H__
++#define __UM_RWSEM_H__
++
++#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
++#define __builtin_expect(exp,c) (exp)
++#endif
++
++#include "asm/arch/rwsem.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/scatterlist.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SCATTERLIST_H
++#define __UM_SCATTERLIST_H
++
++#include "asm/arch/scatterlist.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/segment.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,4 @@
++#ifndef __UM_SEGMENT_H
++#define __UM_SEGMENT_H
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/semaphore.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMAPHORE_H
++#define __UM_SEMAPHORE_H
++
++#include "asm/arch/semaphore.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/sembuf.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMBUF_H
++#define __UM_SEMBUF_H
++
++#include "asm/arch/sembuf.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/serial.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SERIAL_H
++#define __UM_SERIAL_H
++
++#include "asm/arch/serial.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/shmbuf.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMBUF_H
++#define __UM_SHMBUF_H
++
++#include "asm/arch/shmbuf.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/shmparam.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMPARAM_H
++#define __UM_SHMPARAM_H
++
++#include "asm/arch/shmparam.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/sigcontext-generic.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_GENERIC_H
++#define __UM_SIGCONTEXT_GENERIC_H
++
++#include "asm/arch/sigcontext.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/sigcontext-i386.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_I386_H
++#define __UM_SIGCONTEXT_I386_H
++
++#include "asm/sigcontext-generic.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/sigcontext-ppc.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++#ifndef __UM_SIGCONTEXT_PPC_H
++#define __UM_SIGCONTEXT_PPC_H
++
++#define pt_regs sys_pt_regs
++
++#include "asm/sigcontext-generic.h"
++
++#undef pt_regs
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/siginfo.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGINFO_H
++#define __UM_SIGINFO_H
++
++#include "asm/arch/siginfo.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/signal.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SIGNAL_H
++#define __UM_SIGNAL_H
++
++#include "asm/arch/signal.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/smp.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,19 @@
++#ifndef __UM_SMP_H
++#define __UM_SMP_H
++
++#ifdef CONFIG_SMP
++
++#include "linux/config.h"
++#include "asm/current.h"
++
++#define smp_processor_id() (current->processor)
++#define cpu_logical_map(n) (n)
++#define cpu_number_map(n) (n)
++#define PROC_CHANGE_PENALTY   15 /* Pick a number, any number */
++extern int hard_smp_processor_id(void);
++extern unsigned long cpu_online_map;
++#define NO_PROC_ID -1
++
++#endif
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/smplock.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SMPLOCK_H
++#define __UM_SMPLOCK_H
++
++#include "asm/arch/smplock.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/socket.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKET_H
++#define __UM_SOCKET_H
++
++#include "asm/arch/socket.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/sockios.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKIOS_H
++#define __UM_SOCKIOS_H
++
++#include "asm/arch/sockios.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/softirq.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,13 @@
++#ifndef __UM_SOFTIRQ_H
++#define __UM_SOFTIRQ_H
++
++#include "linux/smp.h"
++#include "asm/system.h"
++#include "asm/processor.h"
++
++/* A gratuitous name change */
++#define i386_bh_lock um_bh_lock
++#include "asm/arch/softirq.h"
++#undef i386_bh_lock
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/spinlock.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,10 @@
++#ifndef __UM_SPINLOCK_H
++#define __UM_SPINLOCK_H
++
++#include "linux/config.h"
++
++#ifdef CONFIG_SMP
++#include "asm/arch/spinlock.h"
++#endif
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/statfs.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef _UM_STATFS_H
++#define _UM_STATFS_H
++
++#include "asm/arch/statfs.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/stat.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_STAT_H
++#define __UM_STAT_H
++
++#include "asm/arch/stat.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/string.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,7 @@
++#ifndef __UM_STRING_H
++#define __UM_STRING_H
++
++#include "asm/arch/string.h"
++#include "asm/archparam.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/system-generic.h      2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,49 @@
++#ifndef __UM_SYSTEM_GENERIC_H
++#define __UM_SYSTEM_GENERIC_H
++
++#include "asm/arch/system.h"
++
++#undef prepare_to_switch
++#undef switch_to
++#undef __save_flags
++#undef save_flags
++#undef __restore_flags
++#undef restore_flags
++#undef __cli
++#undef __sti
++#undef cli
++#undef sti
++#undef local_irq_save
++#undef local_irq_restore
++#undef local_irq_disable
++#undef local_irq_enable
++
++#define prepare_to_switch() do ; while(0)
++
++void *_switch_to(void *prev, void *next);
++
++#define switch_to(prev, next, last) prev = _switch_to(prev, next)
++
++extern int set_signals(int enable);
++extern void block_signals(void);
++extern void unblock_signals(void);
++
++#define local_irq_save(flags) do { (flags) = set_signals(0); } while(0)
++
++#define local_irq_restore(flags) do { set_signals(flags); } while(0)
++
++#define local_irq_enable() unblock_signals()
++#define local_irq_disable() block_signals()
++
++#define __sti() unblock_signals()
++#define sti() unblock_signals()
++#define __cli() block_signals()
++#define cli() block_signals()
++
++#define __save_flags(x) local_irq_save(x)
++#define save_flags(x) __save_flags(x)
++
++#define __restore_flags(x) local_irq_restore(x)
++#define restore_flags(x) __restore_flags(x)
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/system-i386.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SYSTEM_I386_H
++#define __UM_SYSTEM_I386_H
++
++#include "asm/system-generic.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/system-ppc.h  2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,12 @@
++#ifndef __UM_SYSTEM_PPC_H
++#define __UM_SYSTEM_PPC_H
++
++#define _switch_to _ppc_switch_to
++
++#include "asm/arch/system.h"
++
++#undef _switch_to
++ 
++#include "asm/system-generic.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/termbits.h    2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMBITS_H
++#define __UM_TERMBITS_H
++
++#include "asm/arch/termbits.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/termios.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMIOS_H
++#define __UM_TERMIOS_H
++
++#include "asm/arch/termios.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/timex.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,15 @@
++#ifndef __UM_TIMEX_H
++#define __UM_TIMEX_H
++
++#include "linux/time.h"
++
++typedef unsigned long cycles_t;
++
++#define cacheflush_time (0)
++
++static inline cycles_t get_cycles (void)
++{
++      return 0;
++}
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/tlb.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1 @@
++#include <asm-generic/tlb.h>
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/types.h       2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_TYPES_H
++#define __UM_TYPES_H
++
++#include "asm/arch/types.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/uaccess.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,193 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_UACCESS_H
++#define __UM_UACCESS_H
++
++#include "linux/string.h"
++#include "linux/sched.h"
++#include "asm/processor.h"
++#include "asm/errno.h"
++#include "asm/current.h"
++#include "asm/a.out.h"
++
++#define VERIFY_READ 0
++#define VERIFY_WRITE 1
++
++/*
++ * The fs value determines whether argument validity checking should be
++ * performed or not.  If get_fs() == USER_DS, checking is performed, with
++ * get_fs() == KERNEL_DS, checking is bypassed.
++ *
++ * For historical reasons, these macros are grossly misnamed.
++ */
++
++#define MAKE_MM_SEG(s)        ((mm_segment_t) { (s) })
++
++#define ABOVE_KMEM (16 * 1024 * 1024)
++
++#define KERNEL_DS     MAKE_MM_SEG(0xFFFFFFFF)
++#define USER_DS               MAKE_MM_SEG(TASK_SIZE)
++
++#define get_ds()      (KERNEL_DS)
++#define get_fs()      (current->addr_limit)
++#define set_fs(x)     (current->addr_limit = (x))
++
++extern unsigned long end_vm;
++extern unsigned long uml_physmem;
++
++#define under_task_size(addr, size) \
++      (((unsigned long) (addr) < TASK_SIZE) && \
++         (((unsigned long) (addr) + (size)) < TASK_SIZE))
++
++#define is_stack(addr, size) \
++      (((unsigned long) (addr) < STACK_TOP) && \
++       ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
++       (((unsigned long) (addr) + (size)) <= STACK_TOP))
++
++#define segment_eq(a, b) ((a).seg == (b).seg)
++
++#define access_ok(type, addr, size) \
++      ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
++         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
++          (under_task_size(addr, size) || is_stack(addr, size))))
++
++static inline int verify_area(int type, const void * addr, unsigned long size)
++{
++      return(access_ok(type, addr, size) ? 0 : -EFAULT);
++}
++
++extern unsigned long get_fault_addr(void);
++
++extern int __do_copy_from_user(void *to, const void *from, int n,
++                                void **fault_addr, void **fault_catcher);
++
++static inline int copy_from_user(void *to, const void *from, int n)
++{
++      return(access_ok(VERIFY_READ, from, n) ?
++             __do_copy_from_user(to, from, n, 
++                                 &current->thread.fault_addr,
++                                 &current->thread.fault_catcher) : n);
++}
++
++#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
++
++extern int __do_copy_to_user(void *to, const void *from, int n,
++                                void **fault_addr, void **fault_catcher);
++
++static inline int copy_to_user(void *to, const void *from, int n)
++{
++      return(access_ok(VERIFY_WRITE, to, n) ?
++             __do_copy_from_user(to, from, n, 
++                                 &current->thread.fault_addr,
++                                 &current->thread.fault_catcher) : n);
++}
++
++#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
++
++#define __get_user(x, ptr) \
++({ \
++        const __typeof__(ptr) __private_ptr = ptr; \
++        __typeof__(*(__private_ptr)) __private_val; \
++        int __private_ret = -EFAULT; \
++        (x) = 0; \
++      if (__copy_from_user(&__private_val, (__private_ptr), \
++          sizeof(*(__private_ptr))) == 0) {\
++              (x) = (__typeof__(*(__private_ptr))) __private_val; \
++              __private_ret = 0; \
++      } \
++        __private_ret; \
++}) 
++
++#define get_user(x, ptr) \
++({ \
++        const __typeof__((*ptr)) *private_ptr = (ptr); \
++        (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
++       __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
++})
++
++#define __put_user(x, ptr) \
++({ \
++        __typeof__(ptr) __private_ptr = ptr; \
++        __typeof__(*(__private_ptr)) __private_val; \
++        int __private_ret = -EFAULT; \
++        __private_val = (__typeof__(*(__private_ptr))) (x); \
++        if (__copy_to_user((__private_ptr), &__private_val, \
++                         sizeof(*(__private_ptr))) == 0) { \
++              __private_ret = 0; \
++      } \
++        __private_ret; \
++})
++
++#define put_user(x, ptr) \
++({ \
++        __typeof__(*(ptr)) *private_ptr = (ptr); \
++        (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \
++       __put_user(x, private_ptr) : -EFAULT); \
++})
++
++extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
++                                void **fault_addr, void **fault_catcher);
++
++static inline int strncpy_from_user(char *dst, const char *src, int count)
++{
++      int n;
++
++      if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT);
++      n = __do_strncpy_from_user(dst, src, count, 
++                                 &current->thread.fault_addr,
++                                 &current->thread.fault_catcher);
++      if(n < 0) return(-EFAULT);
++      return(n);
++}
++
++extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
++                         void **fault_catcher);
++
++static inline int __clear_user(void *mem, int len)
++{
++      return(__do_clear_user(mem, len,
++                             &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
++}
++
++static inline int clear_user(void *mem, int len)
++{
++      return(access_ok(VERIFY_WRITE, mem, len) ? 
++             __do_clear_user(mem, len, 
++                             &current->thread.fault_addr,
++                             &current->thread.fault_catcher) : len);
++}
++
++extern int __do_strnlen_user(const char *str, unsigned long n,
++                           void **fault_addr, void **fault_catcher);
++
++static inline int strnlen_user(void *str, int len)
++{
++      return(__do_strnlen_user(str, len,
++                               &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
++}
++
++#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
++
++struct exception_table_entry
++{
++        unsigned long insn;
++      unsigned long fixup;
++};
++
++#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:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/unaligned.h   2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_UNALIGNED_H
++#define __UM_UNALIGNED_H
++
++#include "asm/arch/unaligned.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/unistd.h      2003-09-09 16:31:30.000000000 +0400
+@@ -0,0 +1,120 @@
++/* 
++ * Copyright (C) 2000, 2001  Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef _UM_UNISTD_H_
++#define _UM_UNISTD_H_
++
++#include "linux/resource.h"
++#include "asm/uaccess.h"
++
++extern int sys_chdir(const char *);
++extern int sys_chroot(const char *);
++extern long sys_open(const char *filename, int flags, int mode);
++extern long sys_dup(unsigned int fildes);
++extern long sys_close(unsigned int fd);
++extern int um_execve(const char *file, char *const argv[], char *const env[]);
++extern long sys_setsid(void);
++extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
++extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, 
++                    struct rusage *ru);
++extern long sys_mount(char *dev_name, char *dir_name, char *type, 
++                    unsigned long flags, void *data);
++extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, 
++                     struct timeval *tvp);
++extern long sys_lseek(unsigned int fildes, unsigned long offset, int whence);
++extern ssize_t sys_read(unsigned int fd, char * buf, size_t count);
++extern ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
++
++#ifdef __KERNEL_SYSCALLS__
++
++#define KERNEL_CALL(ret_t, sys, args...)      \
++      mm_segment_t fs = get_fs();             \
++      ret_t ret;                              \
++      set_fs(KERNEL_DS);                      \
++      ret = sys(args);                        \
++      set_fs(fs);                             \
++      return ret;
++
++static inline long open(const char *pathname, int flags, int mode) 
++{
++      KERNEL_CALL(int, sys_open, pathname, flags, mode)
++}
++
++static inline long dup(unsigned int fd)
++{
++      KERNEL_CALL(int, sys_dup, fd);
++}
++
++static inline long close(unsigned int fd)
++{
++      KERNEL_CALL(int, sys_close, fd);
++}
++
++static inline int execve(const char *filename, char *const argv[], 
++                       char *const envp[])
++{
++      KERNEL_CALL(int, um_execve, filename, argv, envp);
++}
++
++static inline long waitpid(pid_t pid, unsigned int *status, int options)
++{
++      KERNEL_CALL(pid_t, sys_wait4, pid, status, options, NULL)
++}
++
++static inline pid_t wait(int *status)
++{
++      KERNEL_CALL(pid_t, sys_wait4, -1, status, 0, NULL)
++}
++
++static inline pid_t setsid(void)
++{
++      KERNEL_CALL(pid_t, sys_setsid)
++}
++
++static inline long lseek(unsigned int fd, off_t offset, unsigned int whence)
++{
++      KERNEL_CALL(long, sys_lseek, fd, offset, whence)
++}
++
++static inline int read(unsigned int fd, char * buf, int len)
++{
++      KERNEL_CALL(int, sys_read, fd, buf, len)
++}
++
++static inline int write(unsigned int fd, char * buf, int len)
++{
++      KERNEL_CALL(int, sys_write, fd, buf, len)
++}
++
++#endif
++
++/* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying
++ * arch's unistd.h for the system call numbers, and restore the old 
++ * __KERNEL_SYSCALLS__.
++ */
++
++#ifdef __KERNEL_SYSCALLS__
++#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__
++#endif
++
++#undef __KERNEL_SYSCALLS__
++#include "asm/arch/unistd.h"
++
++#ifdef __KERNEL_SYSCALLS__
++#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/user.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_USER_H
++#define __UM_USER_H
++
++#include "asm/arch/user.h"
++
++#endif
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/vga.h 2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_VGA_H
++#define __UM_VGA_H
++
++#include "asm/arch/vga.h"
++
++#endif
+--- linux-2.4.18-chaos-uml/include/linux/raid/md_compatible.h~uml-patch-2.4.18-chaos-53        2001-11-22 22:48:07.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/linux/raid/md_compatible.h   2003-09-09 16:15:18.000000000 +0400
+@@ -34,7 +34,7 @@ static __inline__ int md_cpu_has_mmx(voi
+       return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
+ }
+ #else
+-#define md_cpu_has_mmx(x)     (0)
++#define md_cpu_has_mmx()      (0)
+ #endif
+ /* 002 */
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/suspend.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,4 @@
++#ifndef SUSPEND_H_
++#define SUSPEND_H_
++#endif
++
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/perfctr.h     2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,17 @@
++#ifndef PERFCTR_H_
++#define       PERFCTR_H_
++
++struct perfctr_cpu_state {
++      int a;
++};
++
++struct perfctr_cpu_control {
++      int a;
++};
++
++struct perfctr_sum_ctrs {
++      int a;
++};
++
++#endif
++
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/syscall.h     2003-09-09 16:36:17.000000000 +0400
+@@ -0,0 +1,11 @@
++#ifndef SYSCALL_H_
++#define SYSCALL_H_
++
++typedef long syscall_handler_t(struct pt_regs);
++
++extern int sys_chroot(const char *);
++extern int sys_chdir(const char *);
++extern syscall_handler_t sys_fcntl;
++
++#endif
++
+--- /dev/null  2003-01-30 13:24:37.000000000 +0300
++++ linux-2.4.18-chaos-uml-alexey/include/asm-um/rmap.h        2003-09-09 16:15:18.000000000 +0400
+@@ -0,0 +1,8 @@
++#ifndef _UM_RMAP_H
++#define _UM_RMAP_H
++
++/* nothing to see, move along */
++#include <asm-generic/rmap.h>
++
++#endif
++
+--- linux-2.4.18-chaos-uml/include/linux/fs.h~uml-patch-2.4.18-chaos-53        2003-07-28 17:52:17.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/include/linux/fs.h   2003-09-09 16:15:18.000000000 +0400
+@@ -658,13 +658,9 @@ extern struct list_head file_lock_list;
+ extern int fcntl_getlk(unsigned int, struct flock *);
+ extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+ extern asmlinkage long sys_dup(unsigned int fildes);
+-extern asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
+ extern asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
+ extern asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
+-extern asmlinkage long sys_chroot(const char * filename);
+-extern asmlinkage long sys_chdir(const char * filename);
+ extern int fcntl_getlk64(unsigned int, struct flock64 *);
+--- linux-2.4.18-chaos-uml/kernel/ksyms.c~uml-patch-2.4.18-chaos-53    2003-07-28 17:52:20.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/kernel/ksyms.c       2003-09-09 16:15:18.000000000 +0400
+@@ -50,7 +50,7 @@
+ #include <linux/seq_file.h>
+ #include <asm/checksum.h>
+ #include <linux/unistd.h>
+-
++#include <asm/syscall.h>
+ #if defined(CONFIG_PROC_FS)
+ #include <linux/proc_fs.h>
+--- linux-2.4.18-chaos-uml/include/linux/syscall.h~uml-patch-2.4.18-chaos-53   2003-07-28 17:52:19.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/include/linux/syscall.h      2003-09-09 16:15:18.000000000 +0400
+@@ -40,8 +40,6 @@ extern asmlinkage long sys_fdatasync(uns
+ /* fs/fcntl.c */
+ extern asmlinkage long sys_dup(unsigned int fildes);
+ extern asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
+-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd,
+-              unsigned long arg);
+ #if (BITS_PER_LONG == 32)
+ extern asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd,
+               unsigned long arg);
+@@ -69,9 +67,7 @@ extern asmlinkage long sys_pivot_root(co
+ /* fs/open.c */
+ extern asmlinkage long sys_access(const char * filename, int mode);            
+-extern asmlinkage long sys_chdir(const char * filename);
+ extern asmlinkage long sys_fchdir(unsigned int fd);
+-extern asmlinkage long sys_chroot(const char * filename);
+ extern asmlinkage long sys_chmod(const char * filename, mode_t mode);
+ extern asmlinkage long sys_fchmod(unsigned int fd, mode_t mode);
+ extern asmlinkage long sys_chown(const char * filename, uid_t user,
+@@ -160,7 +156,6 @@ extern asmlinkage long sys_sched_setpara
+ extern asmlinkage long sys_sched_getscheduler(pid_t pid);
+ extern asmlinkage long sys_sched_getparam(pid_t pid,
+               struct sched_param *param);
+-extern asmlinkage long sys_sched_yield(void);
+ extern asmlinkage long sys_sched_get_priority_max(int policy);
+ extern asmlinkage long sys_sched_get_priority_min(int policy);
+ extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
+--- linux-2.4.18-chaos-uml/kernel/ptrace.c~uml-patch-2.4.18-chaos-53   2003-07-28 17:52:20.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/kernel/ptrace.c      2003-09-09 16:15:18.000000000 +0400
+@@ -160,7 +160,9 @@ int access_process_vm(struct task_struct
+               if (write) {
+                       memcpy(maddr + offset, buf, bytes);
+                       flush_page_to_ram(page);
++                      /* the simple way to build uml kernel ;) -bzzz
+                       flush_icache_user_range(vma, page, addr, len);
++                      */
+               } else {
+                       memcpy(buf, maddr + offset, bytes);
+                       flush_page_to_ram(page);
+--- linux-2.4.18-chaos-uml/include/asm-i386/system.h~uml-patch-2.4.18-chaos-53 2003-09-09 13:30:55.000000000 +0400
++++ linux-2.4.18-chaos-uml-alexey/include/asm-i386/system.h    2003-09-09 16:15:18.000000000 +0400
+@@ -233,7 +233,6 @@ static inline unsigned long __xchg(unsig
+  * indicated by comparing RETURN with OLD.
+  */
+-#ifdef CONFIG_X86_CMPXCHG
+ #define __HAVE_ARCH_CMPXCHG 1
+ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+@@ -267,10 +266,6 @@ static inline unsigned long __cmpxchg(vo
+       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+                                       (unsigned long)(n),sizeof(*(ptr))))
+     
+-#else
+-/* Compiling for a 386 proper.        Is it worth implementing via cli/sti?  */
+-#endif
+-
+ /*
+  * Force strict CPU ordering.
+  * And yes, this is required on UP too when we're talking
+
+_
diff --git a/lustre/kernel_patches/pc/kmap_log_init-fix-2.4.18-chaos.pc b/lustre/kernel_patches/pc/kmap_log_init-fix-2.4.18-chaos.pc
new file mode 100644 (file)
index 0000000..1b72108
--- /dev/null
@@ -0,0 +1 @@
+init/main.c
diff --git a/lustre/kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc b/lustre/kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc
new file mode 100644 (file)
index 0000000..dd1256e
--- /dev/null
@@ -0,0 +1,311 @@
+arch/um/boot/Makefile
+arch/um/config_block.in
+arch/um/config_char.in
+arch/um/config.in
+arch/um/config_net.in
+arch/um/config.release
+arch/um/config_scsi.in
+arch/um/defconfig
+arch/um/drivers/chan_kern.c
+arch/um/drivers/chan_user.c
+arch/um/drivers/daemon.h
+arch/um/drivers/daemon_kern.c
+arch/um/drivers/daemon_kern.h
+arch/um/drivers/daemon_user.c
+arch/um/drivers/fd.c
+arch/um/drivers/harddog_kern.c
+arch/um/drivers/harddog_user.c
+arch/um/drivers/hostaudio_kern.c
+arch/um/drivers/hostaudio_user.c
+arch/um/drivers/line.c
+arch/um/drivers/Makefile
+arch/um/drivers/mcast.h
+arch/um/drivers/mcast_kern.c
+arch/um/drivers/mcast_kern.h
+arch/um/drivers/mcast_user.c
+arch/um/drivers/mconsole_kern.c
+arch/um/drivers/mconsole_user.c
+arch/um/drivers/mmapper_kern.c
+arch/um/drivers/net_kern.c
+arch/um/drivers/net_user.c
+arch/um/drivers/null.c
+arch/um/drivers/port.h
+arch/um/drivers/port_kern.c
+arch/um/drivers/port_user.c
+arch/um/drivers/pty.c
+arch/um/drivers/slip.h
+arch/um/drivers/slip_kern.c
+arch/um/drivers/slip_kern.h
+arch/um/drivers/slip_user.c
+arch/um/drivers/ssl.c
+arch/um/drivers/ssl.h
+arch/um/drivers/stdio_console.c
+arch/um/drivers/stdio_console.h
+arch/um/drivers/tty.c
+arch/um/drivers/ubd_kern.c
+arch/um/drivers/ubd_user.c
+arch/um/drivers/xterm.c
+arch/um/fs/hostfs/hostfs.h
+arch/um/fs/hostfs/hostfs_kern.c
+arch/um/fs/hostfs/hostfs_user.c
+arch/um/fs/hostfs/Makefile
+arch/um/fs/hppfs/hppfs_kern.c
+arch/um/fs/hppfs/Makefile
+arch/um/fs/Makefile
+arch/um/include/2_5compat.h
+arch/um/include/chan_kern.h
+arch/um/include/chan_user.h
+arch/um/include/debug.h
+arch/um/include/frame.h
+arch/um/include/frame_kern.h
+arch/um/include/frame_user.h
+arch/um/include/helper.h
+arch/um/include/hostaudio.h
+arch/um/include/init.h
+arch/um/include/initrd.h
+arch/um/include/irq_user.h
+arch/um/include/kern.h
+arch/um/include/kern_util.h
+arch/um/include/line.h
+arch/um/include/Makefile
+arch/um/include/mconsole.h
+arch/um/include/mconsole_kern.h
+arch/um/include/mem.h
+arch/um/include/mem_user.h
+arch/um/include/net_kern.h
+arch/um/include/net_user.h
+arch/um/include/os.h
+arch/um/include/process.h
+arch/um/include/ptrace_user.h
+arch/um/include/sigcontext.h
+arch/um/include/sigio.h
+arch/um/include/signal_kern.h
+arch/um/include/signal_user.h
+arch/um/include/syscall_user.h
+arch/um/include/sysdep-i386/frame.h
+arch/um/include/sysdep-i386/frame_kern.h
+arch/um/include/sysdep-i386/frame_user.h
+arch/um/include/sysdep-i386/ptrace.h
+arch/um/include/sysdep-i386/ptrace_user.h
+arch/um/include/sysdep-i386/sigcontext.h
+arch/um/include/sysdep-i386/syscalls.h
+arch/um/include/sysdep-ia64/ptrace.h
+arch/um/include/sysdep-ia64/sigcontext.h
+arch/um/include/sysdep-ia64/syscalls.h
+arch/um/include/sysdep-ppc/ptrace.h
+arch/um/include/sysdep-ppc/sigcontext.h
+arch/um/include/sysdep-ppc/syscalls.h
+arch/um/include/sysrq.h
+arch/um/include/tlb.h
+arch/um/include/ubd_user.h
+arch/um/include/umid.h
+arch/um/include/umn.h
+arch/um/include/user.h
+arch/um/include/user_util.h
+arch/um/kernel/config.c.in
+arch/um/kernel/exec_kern.c
+arch/um/kernel/exec_user.c
+arch/um/kernel/exitcode.c
+arch/um/kernel/frame.c
+arch/um/kernel/frame_kern.c
+arch/um/kernel/gmon_syms.c
+arch/um/kernel/gprof_syms.c
+arch/um/kernel/helper.c
+arch/um/kernel/initrd_kern.c
+arch/um/kernel/initrd_user.c
+arch/um/kernel/init_task.c
+arch/um/kernel/irq.c
+arch/um/kernel/irq_user.c
+arch/um/kernel/ksyms.c
+arch/um/kernel/Makefile
+arch/um/kernel/mem.c
+arch/um/kernel/mem_user.c
+arch/um/kernel/mprot.h
+arch/um/kernel/process.c
+arch/um/kernel/process_kern.c
+arch/um/kernel/ptrace.c
+arch/um/kernel/reboot.c
+arch/um/kernel/resource.c
+arch/um/kernel/setup.c
+arch/um/kernel/sigio_kern.c
+arch/um/kernel/sigio_user.c
+arch/um/kernel/signal_kern.c
+arch/um/kernel/signal_user.c
+arch/um/kernel/smp.c
+arch/um/kernel/syscall_kern.c
+arch/um/kernel/sys_call_table.c
+arch/um/kernel/syscall_user.c
+arch/um/kernel/sysrq.c
+arch/um/kernel/time.c
+arch/um/kernel/time_kern.c
+arch/um/kernel/tlb.c
+arch/um/kernel/trap_kern.c
+arch/um/kernel/trap_user.c
+arch/um/kernel/tty_log.c
+arch/um/kernel/uaccess_user.c
+arch/um/kernel/um_arch.c
+arch/um/kernel/umid.c
+arch/um/kernel/unmap.c
+arch/um/kernel/user_syms.c
+arch/um/kernel/user_util.c
+arch/um/link.ld.in
+arch/um/main.c
+arch/um/Makefile
+arch/um/Makefile-i386
+arch/um/Makefile-ia64
+arch/um/Makefile-os-Linux
+arch/um/Makefile-ppc
+arch/um/os-Linux/drivers/etap.h
+arch/um/os-Linux/drivers/etap_kern.h
+arch/um/os-Linux/drivers/ethertap_kern.c
+arch/um/os-Linux/drivers/ethertap_user.c
+arch/um/os-Linux/drivers/Makefile
+arch/um/os-Linux/drivers/tuntap.h
+arch/um/os-Linux/drivers/tuntap_kern.c
+arch/um/os-Linux/drivers/tuntap_kern.h
+arch/um/os-Linux/drivers/tuntap_user.c
+arch/um/os-Linux/file.c
+arch/um/os-Linux/include/file.h
+arch/um/os-Linux/Makefile
+arch/um/os-Linux/process.c
+arch/um/os-Linux/tty.c
+arch/um/ptproxy/Makefile
+arch/um/ptproxy/proxy.c
+arch/um/ptproxy/ptproxy.h
+arch/um/ptproxy/ptrace.c
+arch/um/ptproxy/sysdep.c
+arch/um/ptproxy/sysdep.h
+arch/um/ptproxy/wait.c
+arch/um/ptproxy/wait.h
+arch/um/sys-i386/bugs.c
+arch/um/sys-i386/fault.c
+arch/um/sys-i386/ksyms.c
+arch/um/sys-i386/ldt.c
+arch/um/sys-i386/Makefile
+arch/um/sys-i386/ptrace.c
+arch/um/sys-i386/ptrace_user.c
+arch/um/sys-i386/sigcontext.c
+arch/um/sys-i386/syscalls.c
+arch/um/sys-i386/sysrq.c
+arch/um/sys-i386/util/Makefile
+arch/um/sys-i386/util/mk_sc.c
+arch/um/sys-i386/util/mk_thread_kern.c
+arch/um/sys-i386/util/mk_thread_user.c
+arch/um/sys-ia64/Makefile
+arch/um/sys-ppc/Makefile
+arch/um/sys-ppc/misc.S
+arch/um/sys-ppc/miscthings.c
+arch/um/sys-ppc/ptrace.c
+arch/um/sys-ppc/ptrace_user.c
+arch/um/sys-ppc/sigcontext.c
+arch/um/sys-ppc/sysrq.c
+arch/um/util/Makefile
+arch/um/util/mk_task_kern.c
+arch/um/util/mk_task_user.c
+include/asm-um/a.out.h
+include/asm-um/archparam-i386.h
+include/asm-um/archparam-ppc.h
+include/asm-um/arch-signal-i386.h
+include/asm-um/atomic.h
+include/asm-um/bitops.h
+include/asm-um/boot.h
+include/asm-um/bugs.h
+include/asm-um/byteorder.h
+include/asm-um/cache.h
+include/asm-um/checksum.h
+include/asm-um/cobalt.h
+include/asm-um/current.h
+include/asm-um/delay.h
+include/asm-um/desc.h
+include/asm-um/div64.h
+include/asm-um/dma.h
+include/asm-um/elf.h
+include/asm-um/errno.h
+include/asm-um/fcntl.h
+include/asm-um/floppy.h
+include/asm-um/hardirq.h
+include/asm-um/hdreg.h
+include/asm-um/highmem.h
+include/asm-um/hw_irq.h
+include/asm-um/ide.h
+include/asm-um/init.h
+include/asm-um/ioctl.h
+include/asm-um/ioctls.h
+include/asm-um/io.h
+include/asm-um/ipcbuf.h
+include/asm-um/ipc.h
+include/asm-um/irq.h
+include/asm-um/keyboard.h
+include/asm-um/linux_logo.h
+include/asm-um/locks.h
+include/asm-um/mca_dma.h
+include/asm-um/mman.h
+include/asm-um/mmu_context.h
+include/asm-um/mmu.h
+include/asm-um/module.h
+include/asm-um/msgbuf.h
+include/asm-um/mtrr.h
+include/asm-um/namei.h
+include/asm-um/page.h
+include/asm-um/page_offset.h
+include/asm-um/param.h
+include/asm-um/pci.h
+include/asm-um/pgalloc.h
+include/asm-um/pgtable.h
+include/asm-um/poll.h
+include/asm-um/posix_types.h
+include/asm-um/processor-generic.h
+include/asm-um/processor-i386.h
+include/asm-um/processor-ppc.h
+include/asm-um/ptrace-generic.h
+include/asm-um/ptrace-i386.h
+include/asm-um/resource.h
+include/asm-um/rwlock.h
+include/asm-um/rwsem.h
+include/asm-um/scatterlist.h
+include/asm-um/segment.h
+include/asm-um/semaphore.h
+include/asm-um/sembuf.h
+include/asm-um/serial.h
+include/asm-um/shmbuf.h
+include/asm-um/shmparam.h
+include/asm-um/sigcontext-generic.h
+include/asm-um/sigcontext-i386.h
+include/asm-um/sigcontext-ppc.h
+include/asm-um/siginfo.h
+include/asm-um/signal.h
+include/asm-um/smp.h
+include/asm-um/smplock.h
+include/asm-um/socket.h
+include/asm-um/sockios.h
+include/asm-um/softirq.h
+include/asm-um/spinlock.h
+include/asm-um/statfs.h
+include/asm-um/stat.h
+include/asm-um/string.h
+include/asm-um/system-generic.h
+include/asm-um/system-i386.h
+include/asm-um/system-ppc.h
+include/asm-um/termbits.h
+include/asm-um/termios.h
+include/asm-um/timex.h
+include/asm-um/tlb.h
+include/asm-um/types.h
+include/asm-um/uaccess.h
+include/asm-um/unaligned.h
+include/asm-um/unistd.h
+include/asm-um/user.h
+include/asm-um/vga.h
+include/linux/raid/md_compatible.h
+include/asm-um/suspend.h
+include/asm-um/perfctr.h
+include/asm-um/syscall.h
+include/asm-um/rmap.h
+include/linux/fs.h
+include/linux/sched.h
+kernel/ksyms.c
+include/linux/syscall.h
+kernel/ptrace.c
+kernel/signal.c
+include/asm-i386/system.h
+init/do_mounts.c
diff --git a/lustre/kernel_patches/series/chaos-2.4.18-uml b/lustre/kernel_patches/series/chaos-2.4.18-uml
new file mode 100644 (file)
index 0000000..a1b5d77
--- /dev/null
@@ -0,0 +1,29 @@
+uml-patch-2.4.18-chaos-53.patch
+kmap_log_init-fix-2.4.18-chaos.patch
+dev_read_only.patch
+exports.patch
+lustre_version.patch
+vfs_intent-2.4.18-18-chaos65.patch
+invalidate_show.patch
+iod-rmap-exports.patch
+export-truncate.patch
+htree-ext3-2.4.18.patch
+linux-2.4.18ea-0.8.26.patch
+ext3-2.4-ino_t.patch
+ext3-2.4.18-ino_sb_macro.patch
+ext3-orphan_lock.patch
+ext3-delete_thread-2.4.18.patch
+extN-misc-fixup.patch
+extN-noread.patch
+extN-wantedi.patch
+ext3-san-2.4.20.patch
+extN-2.4.18-ino_sb_fixup.patch
+ext3-map_inode_page_2.4.18.patch
+ext3-error-export.patch
+iopen-2.4.18.patch
+jbd-dont-account-blocks-twice.patch
+jbd-commit-tricks.patch
+ext3-o_direct-1-2.4.18-chaos.patch
+ext3-no-write-super-chaos.patch
+ext3-extents-2.4.18-chaos.patch
+ext3-extents-oflag-2.4.18-chaos.patch