From 135d1bb663b8d9727fb7494156ed00333c0223ad Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 10 Sep 2003 06:06:40 +0000 Subject: [PATCH] - uml for 2.4.18-chaos and series file --- .../patches/kmap_log_init-fix-2.4.18-chaos.patch | 19 + .../patches/uml-patch-2.4.18-chaos-53.patch | 31159 +++++++++++++++++++ .../pc/kmap_log_init-fix-2.4.18-chaos.pc | 1 + .../kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc | 311 + lustre/kernel_patches/series/chaos-2.4.18-uml | 29 + 5 files changed, 31519 insertions(+) create mode 100644 lustre/kernel_patches/patches/kmap_log_init-fix-2.4.18-chaos.patch create mode 100644 lustre/kernel_patches/patches/uml-patch-2.4.18-chaos-53.patch create mode 100644 lustre/kernel_patches/pc/kmap_log_init-fix-2.4.18-chaos.pc create mode 100644 lustre/kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc create mode 100644 lustre/kernel_patches/series/chaos-2.4.18-uml 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 index 0000000..8ed8df7 --- /dev/null +++ b/lustre/kernel_patches/patches/kmap_log_init-fix-2.4.18-chaos.patch @@ -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 index 0000000..65ba399 --- /dev/null +++ b/lustre/kernel_patches/patches/uml-patch-2.4.18-chaos-53.patch @@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#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", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_NULL_CHAN ++ { "null", &null_ops }, ++#else ++ { "null", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_PORT_CHAN ++ { "port", &port_ops }, ++#else ++ { "port", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_PTY_CHAN ++ { "pty", &pty_ops }, ++ { "pts", &pts_ops }, ++#else ++ { "pty", ¬_configged_ops }, ++ { "pts", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_TTY_CHAN ++ { "tty", &tty_ops }, ++#else ++ { "tty", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_XTERM_CHAN ++ { "xterm", &xterm_ops }, ++#else ++ { "xterm", ¬_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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#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 , 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 ++ * ++ * Software only watchdog driver. Unlike its big brother the WDT501P ++ * driver this won't always recover a failed machine. ++ * ++ * 03/96: Angelo Haritsis : ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#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=\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=\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 ++#include ++#include ++#include ++#include ++#include ++#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 ++ * ++ * 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#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 = - Add a new device to UML; ++ same syntax as command line ++ remove - Remove a device from UML ++ sysrq - 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, ¤t->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:\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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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;irequest.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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 "); ++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, ð_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(ð->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, ð_cmd_line); ++ return(1); ++} ++ ++__setup("eth", eth_setup); ++__uml_help(eth_setup, ++"eth[0-9]+=,\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, ð_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(ð->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(¨_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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++#include ++#include ++#include ++#include ++#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" ++" 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;ifd); ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asm/types.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "ubd_user.h" ++#include "os.h" ++ ++#include ++#include ++#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, ++ §orsize, 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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=,,<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(®s), \ ++ UM_SYSCALL_ARG2(®s), \ ++ UM_SYSCALL_ARG3(®s), \ ++ UM_SYSCALL_ARG4(®s), \ ++ UM_SYSCALL_ARG5(®s), \ ++ UM_SYSCALL_ARG6(®s)) ++ ++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, ¤t->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) ≻ ++ 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), ++ ¤t->thread.fault_addr, ++ ¤t->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, ¤t->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(¤t->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 = ¤t_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 = ¤t_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 = ¤t->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(¤t->sigmask_lock); ++ sigorsets(¤t->blocked, ¤t->blocked, ++ &ka->sa.sa_mask); ++ sigaddset(¤t->blocked, signr); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->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 = ¤t->blocked; ++ ++ for (;;) { ++ unsigned long signr; ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ signr = dequeue_signal(¤t->blocked, &info); ++ spin_unlock_irq(¤t->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(¤t->blocked, signr)) { ++ send_sig_info(signr, &info, current); ++ continue; ++ } ++ } ++ ++ ka = ¤t->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, ¤t->thread.regs)) ++ exit_code |= 0x80; ++ /* FALLTHRU */ ++ ++ default: ++ sigaddset(¤t->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(¤t->thread.regs))) ++ current->thread.singlestep_syscall = 1; ++ return(0); ++} ++ ++int do_signal(int error) ++{ ++ return(kern_do_signal(¤t->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(¤t->sigmask_lock); ++ saveset = current->blocked; ++ siginitset(¤t->blocked, mask); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if(kern_do_signal(¤t->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(¤t->sigmask_lock); ++ saveset = current->blocked; ++ current->blocked = newset; ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if (kern_do_signal(¤t->thread.regs, &saveset, -EINTR)) ++ return(-EINTR); ++ } ++} ++ ++int sys_sigreturn(struct pt_regs regs) ++{ ++ void *sc = sp_to_sc(PT_REGS_SP(®s)); ++ void *mask = sp_to_mask(PT_REGS_SP(®s)); ++ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ copy_from_user(¤t->blocked.sig[0], sc_sigmask(sc), ++ sizeof(current->blocked.sig[0])); ++ copy_from_user(¤t->blocked.sig[1], mask, sig_size); ++ sigdelsetmask(¤t->blocked, ~_BLOCKABLE); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ copy_sc_from_user(current->thread.regs.regs.sc, sc, ++ &signal_frame_sc.arch); ++ return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); ++} ++ ++int sys_rt_sigreturn(struct pt_regs regs) ++{ ++ void *sc = sp_to_rt_sc(PT_REGS_SP(®s)); ++ void *mask = sp_to_rt_mask(PT_REGS_SP(®s)); ++ int sig_size = _NSIG_WORDS * sizeof(unsigned long); ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ copy_from_user(¤t->blocked, mask, sig_size); ++ sigdelsetmask(¤t->blocked, ~_BLOCKABLE); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ copy_sc_from_user(current->thread.regs.regs.sc, sc, ++ &signal_frame_sc.arch); ++ return(PT_REGS_SYSCALL_RET(¤t->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(¤t->mm->mmap_sem); ++ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); ++ up_write(¤t->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(¤t->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(®s); ++} ++ ++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', ¤t->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 = ðertap_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 = ðertap_user_info; ++ dev->kern = ðertap_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(ðertap_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 *) ®s); ++} +--- /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(®s->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, ++ ¤t->thread.fault_addr, ++ ¤t->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, ++ ¤t->thread.fault_addr, ++ ¤t->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, ++ ¤t->thread.fault_addr, ++ ¤t->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, ++ ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++static inline int clear_user(void *mem, int len) ++{ ++ return(access_ok(VERIFY_WRITE, mem, len) ? ++ __do_clear_user(mem, len, ++ ¤t->thread.fault_addr, ++ ¤t->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, ++ ¤t->thread.fault_addr, ++ ¤t->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 index 0000000..1b72108 --- /dev/null +++ b/lustre/kernel_patches/pc/kmap_log_init-fix-2.4.18-chaos.pc @@ -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 index 0000000..dd1256e --- /dev/null +++ b/lustre/kernel_patches/pc/uml-patch-2.4.18-chaos-53.pc @@ -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 index 0000000..a1b5d77 --- /dev/null +++ b/lustre/kernel_patches/series/chaos-2.4.18-uml @@ -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 -- 1.8.3.1