--- /dev/null
+diff -Naur -X ../exclude-files orig/arch/um/common.ld.in um/arch/um/common.ld.in
+--- orig/arch/um/common.ld.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/common.ld.in 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,53 @@
++ .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 = .;
++
++ .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) }
+diff -Naur -X ../exclude-files orig/arch/um/config_block.in um/arch/um/config_block.in
+--- orig/arch/um/config_block.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config_block.in 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,22 @@
++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
++bool 'COW device' CONFIG_COW
++
++if [ "$CONFIG_BLK_DEV_UBD" = "y" -o "$CONFIG_COW" = "y" ] ; then
++ define_bool CONFIG_COW_COMMON y
++fi
++
++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
+diff -Naur -X ../exclude-files orig/arch/um/config_char.in um/arch/um/config_char.in
+--- orig/arch/um/config_char.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config_char.in 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/config.in um/arch/um/config.in
+--- orig/arch/um/config.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config.in 2003-12-14 11:34:02.000000000 -0500
+@@ -0,0 +1,105 @@
++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 'Separate kernel address space support' CONFIG_MODE_SKAS
++
++# This is to ensure that at least one of the modes is enabled. When neither
++# is present in defconfig, they default to N, which is bad.
++if [ "$CONFIG_MODE_SKAS" != "y" ]; then
++ define_bool CONFIG_MODE_TT y
++fi
++
++bool 'Tracing thread support' CONFIG_MODE_TT
++if [ "$CONFIG_MODE_TT" != "y" ]; then
++ bool 'Statically linked binary when CONFIG_MODE_TT is disabled' CONFIG_STATIC_LINK
++fi
++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
++bool 'Highmem support' CONFIG_HIGHMEM
++bool '/proc/mm' CONFIG_PROC_MM
++int 'Kernel stack size order' CONFIG_KERNEL_STACK_ORDER 2
++bool 'Real-time Clock' CONFIG_UML_REAL_TIME_CLOCK
++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
++
++source lib/Config.in
++
++mainmenu_option next_comment
++comment 'Kernel hacking'
++bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
++bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM
++if [ "$CONFIG_XTERM_CHAN" = "y" ]; then
++ dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM
++else
++ define_bool CONFIG_PT_PROXY n
++fi
++dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM
++dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM
++endmenu
+diff -Naur -X ../exclude-files orig/arch/um/config_net.in um/arch/um/config_net.in
+--- orig/arch/um/config_net.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config_net.in 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,47 @@
++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 ' SLiRP transport' CONFIG_UML_NET_SLIRP $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
++dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $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
+diff -Naur -X ../exclude-files orig/arch/um/config.release um/arch/um/config.release
+--- orig/arch/um/config.release 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config.release 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,302 @@
++#
++# 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 is not set
++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=y
++
++#
++# Character Devices
++#
++CONFIG_STDIO_CONSOLE=y
++CONFIG_SSL=y
++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
++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_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=m
++CONFIG_EQUALIZER=m
++CONFIG_TUN=y
++CONFIG_PPP=m
++CONFIG_PPP_MULTILINK=y
++# 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
++
++#
++# 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
++
++#
++# Appletalk devices
++#
++# 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 testing
++#
++# CONFIG_NET_PKTGEN 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_CRAMFS=m
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++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_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_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_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
++
++#
++# 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=m
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD 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
+diff -Naur -X ../exclude-files orig/arch/um/config_scsi.in um/arch/um/config_scsi.in
+--- orig/arch/um/config_scsi.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/config_scsi.in 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/defconfig um/arch/um/defconfig
+--- orig/arch/um/defconfig 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/defconfig 2003-12-17 02:15:39.000000000 -0500
+@@ -0,0 +1,423 @@
++#
++# 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_MODE_SKAS=y
++CONFIG_MODE_TT=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_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
++# CONFIG_HIGHMEM is not set
++CONFIG_PROC_MM=y
++CONFIG_KERNEL_STACK_ORDER=2
++CONFIG_UML_REAL_TIME_CLOCK=y
++
++#
++# 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_COW is not set
++CONFIG_COW_COMMON=y
++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_SLIRP=y
++CONFIG_UML_NET_DAEMON=y
++CONFIG_UML_NET_MCAST=y
++# CONFIG_UML_NET_PCAP is not set
++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
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++CONFIG_IPV6_SCTP__=y
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK 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 testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# File systems
++#
++CONFIG_QUOTA=y
++# CONFIG_QFMT_V2 is not set
++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_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG 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=y
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS 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_NFS_DIRECTIO is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP 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
++
++#
++# 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_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_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_CFI_STAA 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
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA 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
++
++#
++# Library routines
++#
++# CONFIG_CRC32 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++
++#
++# Kernel hacking
++#
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_DEBUGSYM=y
++CONFIG_PT_PROXY=y
++# CONFIG_GPROF is not set
++# CONFIG_GCOV is not set
+diff -Naur -X ../exclude-files orig/arch/um/drivers/chan_kern.c um/arch/um/drivers/chan_kern.c
+--- orig/arch/um/drivers/chan_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/chan_kern.c 2003-11-07 07:25:34.000000000 -0500
+@@ -0,0 +1,519 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/string.h>
++#include <linux/tty_flip.h>
++#include <asm/irq.h>
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "sigio.h"
++#include "line.h"
++
++static void *not_configged_init(char *str, int device, struct chan_opts *opts)
++{
++ printk(KERN_ERR "Using a channel type which is configured out of "
++ "UML\n");
++ return(NULL);
++}
++
++static int not_configged_open(int input, int output, int primary, void *data,
++ char **dev_out)
++{
++ 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,
++ &chan->dev);
++ 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);
++ }
++}
++
++static int one_chan_config_string(struct chan *chan, char *str, int size,
++ char **error_out)
++{
++ int n = 0;
++
++ if(chan == NULL){
++ CONFIG_CHUNK(str, size, n, "none", 1);
++ return(n);
++ }
++
++ CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
++
++ if(chan->dev == NULL){
++ CONFIG_CHUNK(str, size, n, "", 1);
++ return(n);
++ }
++
++ CONFIG_CHUNK(str, size, n, ":", 0);
++ CONFIG_CHUNK(str, size, n, chan->dev, 0);
++
++ return(n);
++}
++
++static int chan_pair_config_string(struct chan *in, struct chan *out,
++ char *str, int size, char **error_out)
++{
++ int n;
++
++ n = one_chan_config_string(in, str, size, error_out);
++ str += n;
++ size -= n;
++
++ if(in == out){
++ CONFIG_CHUNK(str, size, n, "", 1);
++ return(n);
++ }
++
++ CONFIG_CHUNK(str, size, n, ",", 1);
++ n = one_chan_config_string(out, str, size, error_out);
++ str += n;
++ size -= n;
++ CONFIG_CHUNK(str, size, n, "", 1);
++
++ return(n);
++}
++
++int chan_config_string(struct list_head *chans, char *str, int size,
++ char **error_out)
++{
++ struct list_head *ele;
++ struct chan *chan, *in = NULL, *out = NULL;
++
++ list_for_each(ele, chans){
++ chan = list_entry(ele, struct chan, list);
++ if(!chan->primary)
++ continue;
++ if(chan->input)
++ in = chan;
++ if(chan->output)
++ out = chan;
++ }
++
++ return(chan_pair_config_string(in, out, str, size, error_out));
++}
++
++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);
++ }
++
++ out = strchr(str, ',');
++ if(out != 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/chan_user.c um/arch/um/drivers/chan_user.c
+--- orig/arch/um/drivers/chan_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/chan_user.c 2003-11-07 07:23:45.000000000 -0500
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <termios.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/ioctl.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "user_util.h"
++#include "chan_user.h"
++#include "user.h"
++#include "helper.h"
++#include "os.h"
++#include "choose-mode.h"
++#include "mode.h"
++
++void generic_close(int fd, void *unused)
++{
++ os_close_file(fd);
++}
++
++int generic_read(int fd, char *c_out, void *unused)
++{
++ int n;
++
++ n = os_read_file(fd, c_out, sizeof(*c_out));
++
++ if(n == -EAGAIN)
++ return(0);
++ else if(n == 0)
++ return(-EIO);
++ return(n);
++}
++
++/* XXX Trivial wrapper around os_write_file */
++
++int generic_write(int fd, const char *buf, int n, void *unused)
++{
++ return(os_write_file(fd, buf, n));
++}
++
++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)
++{
++ int rows, cols;
++ int ret;
++
++ ret = os_window_size(fd, &rows, &cols);
++ if(ret < 0)
++ return(ret);
++
++ ret = ((*rows_out != rows) || (*cols_out != cols));
++
++ *rows_out = rows;
++ *cols_out = cols;
++
++ 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;
++ int count, err;
++ char c = 1;
++
++ os_close_file(data->close_me);
++ pty_fd = data->pty_fd;
++ pipe_fd = data->pipe_fd;
++ count = os_write_file(pipe_fd, &c, sizeof(c));
++ if(count != sizeof(c))
++ printk("winch_thread : failed to write synchronization "
++ "byte, err = %d\n", -count);
++
++ 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);
++ }
++
++ err = os_new_tty_pgrp(pty_fd, os_getpid());
++ if(err < 0){
++ printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
++ exit(1);
++ }
++
++ count = os_read_file(pipe_fd, &c, sizeof(c));
++ if(count != sizeof(c))
++ printk("winch_thread : failed to read synchronization byte, "
++ "err = %d\n", -count);
++
++ while(1){
++ pause();
++
++ count = os_write_file(pipe_fd, &c, sizeof(c));
++ if(count != sizeof(c))
++ printk("winch_thread : write failed, err = %d\n",
++ -count);
++ }
++}
++
++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 < 0){
++ printk("winch_tramp : os_pipe failed, err = %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);
++ }
++
++ os_close_file(fds[1]);
++ *fd_out = fds[0];
++ n = os_read_file(fds[0], &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("winch_tramp : failed to read synchronization byte\n");
++ printk("read failed, err = %d\n", -n);
++ 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;
++ int count;
++ char c = 1;
++
++ if(!isatty(fd))
++ return;
++
++ pid = tcgetpgrp(fd);
++ if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
++ device_data) && (pid == -1)){
++ thread = winch_tramp(fd, device_data, &thread_fd);
++ if(fd != -1){
++ register_winch_irq(thread_fd, fd, thread, device_data);
++
++ count = os_write_file(thread_fd, &c, sizeof(c));
++ if(count != sizeof(c))
++ printk("register_winch : failed to write "
++ "synchronization byte, err = %d\n",
++ -count);
++ }
++ }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/cow.h um/arch/um/drivers/cow.h
+--- orig/arch/um/drivers/cow.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/cow.h 2004-01-16 03:45:20.000000000 -0500
+@@ -0,0 +1,41 @@
++#ifndef __COW_H__
++#define __COW_H__
++
++#include <asm/types.h>
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define ntohll(x) (x)
++# define htonll(x) (x)
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++# define ntohll(x) bswap_64(x)
++# define htonll(x) bswap_64(x)
++#else
++#error "__BYTE_ORDER not defined"
++#endif
++
++extern int init_cow_file(int fd, char *cow_file, char *backing_file,
++ int sectorsize, int alignment, int *bitmap_offset_out,
++ unsigned long *bitmap_len_out, int *data_offset_out);
++
++extern int file_reader(__u64 offset, char *buf, int len, void *arg);
++extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
++ void *arg, __u32 *version_out,
++ char **backing_file_out, time_t *mtime_out,
++ __u64 *size_out, int *sectorsize_out,
++ __u32 *align_out, int *bitmap_offset_out);
++
++extern int write_cow_header(char *cow_file, int fd, char *backing_file,
++ int sectorsize, int alignment, long long *size);
++
++extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
++ int bitmap_offset, unsigned long *bitmap_len_out,
++ int *data_offset_out);
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_kern.c um/arch/um/drivers/cow_kern.c
+--- orig/arch/um/drivers/cow_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/cow_kern.c 2004-01-10 05:55:04.000000000 -0500
+@@ -0,0 +1,630 @@
++#define COW_MAJOR 60
++#define MAJOR_NR COW_MAJOR
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/stat.h>
++#include <linux/vmalloc.h>
++#include <linux/blkdev.h>
++#include <linux/blk.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/devfs_fs.h>
++#include <asm/uaccess.h>
++#include "2_5compat.h"
++#include "cow.h"
++#include "ubd_user.h"
++
++#define COW_SHIFT 4
++
++struct cow {
++ int count;
++ char *cow_path;
++ dev_t cow_dev;
++ struct block_device *cow_bdev;
++ char *backing_path;
++ dev_t backing_dev;
++ struct block_device *backing_bdev;
++ int sectorsize;
++ unsigned long *bitmap;
++ unsigned long bitmap_len;
++ int bitmap_offset;
++ int data_offset;
++ devfs_handle_t devfs;
++ struct semaphore sem;
++ struct semaphore io_sem;
++ atomic_t working;
++ spinlock_t io_lock;
++ struct buffer_head *bh;
++ struct buffer_head *bhtail;
++ void *end_io;
++};
++
++#define DEFAULT_COW { \
++ .count = 0, \
++ .cow_path = NULL, \
++ .cow_dev = 0, \
++ .backing_path = NULL, \
++ .backing_dev = 0, \
++ .bitmap = NULL, \
++ .bitmap_len = 0, \
++ .bitmap_offset = 0, \
++ .data_offset = 0, \
++ .devfs = NULL, \
++ .working = ATOMIC_INIT(0), \
++ .io_lock = SPIN_LOCK_UNLOCKED, \
++}
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << COW_SHIFT)
++
++struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW };
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by cow_lock */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct hd_struct cow_part[MAX_MINOR] =
++ { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *cow_queue;
++
++static int cow_open(struct inode *inode, struct file *filp);
++static int cow_release(struct inode * inode, struct file * file);
++static int cow_ioctl(struct inode * inode, struct file * file,
++ unsigned int cmd, unsigned long arg);
++static int cow_revalidate(kdev_t rdev);
++
++static struct block_device_operations cow_blops = {
++ .open = cow_open,
++ .release = cow_release,
++ .ioctl = cow_ioctl,
++ .revalidate = cow_revalidate,
++};
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t cow_dir_handle;
++
++#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 spinlock_t cow_lock = SPIN_LOCK_UNLOCKED;
++
++static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part,
++ COW_SHIFT, sizes, MAX_DEV,
++ &cow_blops);
++
++static int cow_add(int n)
++{
++ struct cow *dev = &cow_dev[n];
++ char name[sizeof("nnnnnn\0")];
++ int err = -ENODEV;
++
++ if(dev->cow_path == NULL)
++ goto out;
++
++ sprintf(name, "%d", n);
++ dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE,
++ MAJOR_NR, n << COW_SHIFT, S_IFBLK |
++ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++ &cow_blops, NULL);
++
++ init_MUTEX_LOCKED(&dev->sem);
++ init_MUTEX(&dev->io_sem);
++
++ return(0);
++
++ out:
++ return(err);
++}
++
++/*
++ * Add buffer_head to back of pending list
++ */
++static void cow_add_bh(struct cow *cow, struct buffer_head *bh)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&cow->io_lock, flags);
++ if(cow->bhtail != NULL){
++ cow->bhtail->b_reqnext = bh;
++ cow->bhtail = bh;
++ }
++ else {
++ cow->bh = bh;
++ cow->bhtail = bh;
++ }
++ spin_unlock_irqrestore(&cow->io_lock, flags);
++}
++
++/*
++ * Grab first pending buffer
++ */
++static struct buffer_head *cow_get_bh(struct cow *cow)
++{
++ struct buffer_head *bh;
++
++ spin_lock_irq(&cow->io_lock);
++ bh = cow->bh;
++ if(bh != NULL){
++ if(bh == cow->bhtail)
++ cow->bhtail = NULL;
++ cow->bh = bh->b_reqnext;
++ bh->b_reqnext = NULL;
++ }
++ spin_unlock_irq(&cow->io_lock);
++
++ return(bh);
++}
++
++static void cow_handle_bh(struct cow *cow, struct buffer_head *bh,
++ struct buffer_head **cow_bh, int ncow_bh)
++{
++ int i;
++
++ if(ncow_bh > 0)
++ ll_rw_block(WRITE, ncow_bh, cow_bh);
++
++ for(i = 0; i < ncow_bh ; i++){
++ wait_on_buffer(cow_bh[i]);
++ brelse(cow_bh[i]);
++ }
++
++ ll_rw_block(WRITE, 1, &bh);
++ brelse(bh);
++}
++
++static struct buffer_head *cow_new_bh(struct cow *dev, int sector)
++{
++ struct buffer_head *bh;
++
++ sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize;
++ bh = getblk(dev->cow_dev, sector, dev->sectorsize);
++ memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])),
++ dev->sectorsize);
++ return(bh);
++}
++
++/* Copied from loop.c, needed to avoid deadlocking in make_request. */
++
++static int cow_thread(void *data)
++{
++ struct cow *dev = data;
++ struct buffer_head *bh;
++
++ daemonize();
++ exit_files(current);
++
++ sprintf(current->comm, "cow%d", dev - cow_dev);
++
++ spin_lock_irq(¤t->sigmask_lock);
++ sigfillset(¤t->blocked);
++ flush_signals(current);
++ spin_unlock_irq(¤t->sigmask_lock);
++
++ atomic_inc(&dev->working);
++
++ current->policy = SCHED_OTHER;
++ current->nice = -20;
++
++ current->flags |= PF_NOIO;
++
++ /*
++ * up sem, we are running
++ */
++ up(&dev->sem);
++
++ for(;;){
++ int start, len, nbh, i, update_bitmap = 0;
++ struct buffer_head *cow_bh[2];
++
++ down_interruptible(&dev->io_sem);
++ /*
++ * could be upped because of tear-down, not because of
++ * pending work
++ */
++ if(!atomic_read(&dev->working))
++ break;
++
++ bh = cow_get_bh(dev);
++ if(bh == NULL){
++ printk(KERN_ERR "cow: missing bh\n");
++ continue;
++ }
++
++ start = bh->b_blocknr * bh->b_size / dev->sectorsize;
++ len = bh->b_size / dev->sectorsize;
++ for(i = 0; i < len ; i++){
++ if(ubd_test_bit(start + i,
++ (unsigned char *) dev->bitmap))
++ continue;
++
++ update_bitmap = 1;
++ ubd_set_bit(start + i, (unsigned char *) dev->bitmap);
++ }
++
++ cow_bh[0] = NULL;
++ cow_bh[1] = NULL;
++ nbh = 0;
++ if(update_bitmap){
++ cow_bh[0] = cow_new_bh(dev, start);
++ nbh++;
++ if(start / dev->sectorsize !=
++ (start + len) / dev->sectorsize){
++ cow_bh[1] = cow_new_bh(dev, start + len);
++ nbh++;
++ }
++ }
++
++ bh->b_dev = dev->cow_dev;
++ bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++ cow_handle_bh(dev, bh, cow_bh, nbh);
++
++ /*
++ * upped both for pending work and tear-down, lo_pending
++ * will hit zero then
++ */
++ if(atomic_dec_and_test(&dev->working))
++ break;
++ }
++
++ up(&dev->sem);
++ return(0);
++}
++
++static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh)
++{
++ struct cow *dev;
++ int n, minor;
++
++ minor = MINOR(bh->b_rdev);
++ n = minor >> COW_SHIFT;
++ dev = &cow_dev[n];
++
++ dev->end_io = NULL;
++ if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){
++ bh->b_rdev = dev->cow_dev;
++ bh->b_rsector += dev->data_offset / dev->sectorsize;
++ }
++ else if(rw == WRITE){
++ bh->b_dev = dev->cow_dev;
++ bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++ cow_add_bh(dev, bh);
++ up(&dev->io_sem);
++ return(0);
++ }
++ else {
++ bh->b_rdev = dev->backing_dev;
++ }
++
++ return(1);
++}
++
++int cow_init(void)
++{
++ int i;
++
++ cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL);
++ if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) {
++ printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR);
++ return -1;
++ }
++ 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);
++
++ cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++ blk_init_queue(cow_queue, NULL);
++ INIT_ELV(cow_queue, &cow_queue->elevator);
++ blk_queue_make_request(cow_queue, cow_make_request);
++
++ add_gendisk(&cow_gendisk);
++
++ for(i=0;i<MAX_DEV;i++)
++ cow_add(i);
++
++ return(0);
++}
++
++__initcall(cow_init);
++
++static int reader(__u64 start, char *buf, int count, void *arg)
++{
++ dev_t dev = *((dev_t *) arg);
++ struct buffer_head *bh;
++ __u64 block;
++ int cur, offset, left, n, blocksize = get_hardsect_size(dev);
++
++ if(blocksize == 0)
++ panic("Zero blocksize");
++
++ block = start / blocksize;
++ offset = start % blocksize;
++ left = count;
++ cur = 0;
++ while(left > 0){
++ n = (left > blocksize) ? blocksize : left;
++
++ bh = bread(dev, block, (n < 512) ? 512 : n);
++ if(bh == NULL)
++ return(-EIO);
++
++ n -= offset;
++ memcpy(&buf[cur], bh->b_data + offset, n);
++ block++;
++ left -= n;
++ cur += n;
++ offset = 0;
++ brelse(bh);
++ }
++
++ return(count);
++}
++
++static int cow_open(struct inode *inode, struct file *filp)
++{
++ int (*dev_ioctl)(struct inode *, struct file *, unsigned int,
++ unsigned long);
++ mm_segment_t fs;
++ struct cow *dev;
++ __u64 size;
++ __u32 version, align;
++ time_t mtime;
++ char *backing_file;
++ int n, offset, err = 0;
++
++ n = DEVICE_NR(inode->i_rdev);
++ if(n >= MAX_DEV)
++ return(-ENODEV);
++ dev = &cow_dev[n];
++ offset = n << COW_SHIFT;
++
++ spin_lock(&cow_lock);
++
++ if(dev->count == 0){
++ dev->cow_dev = name_to_kdev_t(dev->cow_path);
++ if(dev->cow_dev == 0){
++ printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++ "failed\n", dev->cow_path);
++ err = -ENODEV;
++ }
++
++ dev->backing_dev = name_to_kdev_t(dev->backing_path);
++ if(dev->backing_dev == 0){
++ printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++ "failed\n", dev->backing_path);
++ err = -ENODEV;
++ }
++
++ if(err)
++ goto out;
++
++ dev->cow_bdev = bdget(dev->cow_dev);
++ if(dev->cow_bdev == NULL){
++ printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n",
++ dev->cow_path);
++ err = -ENOMEM;
++ }
++ dev->backing_bdev = bdget(dev->backing_dev);
++ if(dev->backing_bdev == NULL){
++ printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n",
++ dev->backing_path);
++ err = -ENOMEM;
++ }
++
++ if(err)
++ goto out;
++
++ err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0,
++ BDEV_RAW);
++ if(err){
++ printk("cow_open - blkdev_get of COW device failed, "
++ "error = %d\n", err);
++ goto out;
++ }
++
++ err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW);
++ if(err){
++ printk("cow_open - blkdev_get of backing device "
++ "failed, error = %d\n", err);
++ goto out;
++ }
++
++ err = read_cow_header(reader, &dev->cow_dev, &version,
++ &backing_file, &mtime, &size,
++ &dev->sectorsize, &align,
++ &dev->bitmap_offset);
++ if(err){
++ printk(KERN_ERR "cow_open - read_cow_header failed, "
++ "err = %d\n", err);
++ goto out;
++ }
++
++ cow_sizes(version, size, dev->sectorsize, align,
++ dev->bitmap_offset, &dev->bitmap_len,
++ &dev->data_offset);
++ dev->bitmap = (void *) vmalloc(dev->bitmap_len);
++ if(dev->bitmap == NULL){
++ err = -ENOMEM;
++ printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++ goto out;
++ }
++ flush_tlb_kernel_vm();
++
++ err = reader(dev->bitmap_offset, (char *) dev->bitmap,
++ dev->bitmap_len, &dev->cow_dev);
++ if(err < 0){
++ printk(KERN_ERR "Failed to read COW bitmap\n");
++ vfree(dev->bitmap);
++ goto out;
++ }
++
++ dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++ fs = get_fs();
++ set_fs(KERNEL_DS);
++ err = (*dev_ioctl)(inode, filp, BLKGETSIZE,
++ (unsigned long) &sizes[offset]);
++ set_fs(fs);
++ if(err){
++ printk(KERN_ERR "cow_open - BLKGETSIZE failed, "
++ "error = %d\n", err);
++ goto out;
++ }
++
++ kernel_thread(cow_thread, dev,
++ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++ down(&dev->sem);
++ }
++ dev->count++;
++ out:
++ spin_unlock(&cow_lock);
++ return(err);
++}
++
++static int cow_release(struct inode * inode, struct file * file)
++{
++ struct cow *dev;
++ int n, err;
++
++ n = DEVICE_NR(inode->i_rdev);
++ if(n >= MAX_DEV)
++ return(-ENODEV);
++ dev = &cow_dev[n];
++
++ spin_lock(&cow_lock);
++
++ if(--dev->count > 0)
++ goto out;
++
++ err = blkdev_put(dev->cow_bdev, BDEV_RAW);
++ if(err)
++ printk("cow_release - blkdev_put of cow device failed, "
++ "error = %d\n", err);
++ bdput(dev->cow_bdev);
++ dev->cow_bdev = 0;
++
++ err = blkdev_put(dev->backing_bdev, BDEV_RAW);
++ if(err)
++ printk("cow_release - blkdev_put of backing device failed, "
++ "error = %d\n", err);
++ bdput(dev->backing_bdev);
++ dev->backing_bdev = 0;
++
++ out:
++ spin_unlock(&cow_lock);
++ return(0);
++}
++
++static int cow_ioctl(struct inode * inode, struct file * file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct cow *dev;
++ int (*dev_ioctl)(struct inode *, struct file *, unsigned int,
++ unsigned long);
++ int n;
++
++ n = DEVICE_NR(inode->i_rdev);
++ if(n >= MAX_DEV)
++ return(-ENODEV);
++ dev = &cow_dev[n];
++
++ dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++ return((*dev_ioctl)(inode, file, cmd, arg));
++}
++
++static int cow_revalidate(kdev_t rdev)
++{
++ printk(KERN_ERR "Need to implement cow_revalidate\n");
++ return(0);
++}
++
++static int parse_unit(char **ptr)
++{
++ char *str = *ptr, *end;
++ int n = -1;
++
++ if(isdigit(*str)) {
++ n = simple_strtoul(str, &end, 0);
++ if(end == str)
++ return(-1);
++ *ptr = end;
++ }
++ else if (('a' <= *str) && (*str <= 'h')) {
++ n = *str - 'a';
++ str++;
++ *ptr = str;
++ }
++ return(n);
++}
++
++static int cow_setup(char *str)
++{
++ struct cow *dev;
++ char *cow_name, *backing_name;
++ int unit;
++
++ unit = parse_unit(&str);
++ if(unit < 0){
++ printk(KERN_ERR "cow_setup - Couldn't parse unit number\n");
++ return(1);
++ }
++
++ if(*str != '='){
++ printk(KERN_ERR "cow_setup - Missing '=' after unit "
++ "number\n");
++ return(1);
++ }
++ str++;
++
++ cow_name = str;
++ backing_name = strchr(str, ',');
++ if(backing_name == NULL){
++ printk(KERN_ERR "cow_setup - missing backing device name\n");
++ return(0);
++ }
++ *backing_name = '\0';
++ backing_name++;
++
++ spin_lock(&cow_lock);
++
++ dev = &cow_dev[unit];
++ dev->cow_path = cow_name;
++ dev->backing_path = backing_name;
++
++ spin_unlock(&cow_lock);
++ return(0);
++}
++
++__setup("cow", cow_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_sys.h um/arch/um/drivers/cow_sys.h
+--- orig/arch/um/drivers/cow_sys.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/cow_sys.h 2003-12-17 10:53:03.000000000 -0500
+@@ -0,0 +1,48 @@
++#ifndef __COW_SYS_H__
++#define __COW_SYS_H__
++
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "user.h"
++
++static inline void *cow_malloc(int size)
++{
++ return(um_kmalloc(size));
++}
++
++static inline void cow_free(void *ptr)
++{
++ kfree(ptr);
++}
++
++#define cow_printf printk
++
++static inline char *cow_strdup(char *str)
++{
++ return(uml_strdup(str));
++}
++
++static inline int cow_seek_file(int fd, __u64 offset)
++{
++ return(os_seek_file(fd, offset));
++}
++
++static inline int cow_file_size(char *file, __u64 *size_out)
++{
++ return(os_file_size(file, size_out));
++}
++
++static inline int cow_write_file(int fd, char *buf, int size)
++{
++ return(os_write_file(fd, buf, size));
++}
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_user.c um/arch/um/drivers/cow_user.c
+--- orig/arch/um/drivers/cow_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/cow_user.c 2004-01-10 05:56:22.000000000 -0500
+@@ -0,0 +1,375 @@
++#include <stddef.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <byteswap.h>
++#include <sys/time.h>
++#include <sys/param.h>
++#include <sys/user.h>
++#include <netinet/in.h>
++
++#include "os.h"
++
++#include "cow.h"
++#include "cow_sys.h"
++
++#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;
++};
++
++/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
++ * case other systems have different values for MAXPATHLEN
++ */
++#define PATH_LEN_V3 4096
++
++/* Changes from V2 -
++ * PATH_LEN_V3 as described above
++ * Explicitly specify field bit lengths for systems with different
++ * lengths for the usual C types. Not sure whether char or
++ * time_t should be changed, this can be changed later without
++ * breaking compatibility
++ * Add alignment field so that different alignments can be used for the
++ * bitmap and data
++ * Add cow_format field to allow for the possibility of different ways
++ * of specifying the COW blocks. For now, the only value is 0,
++ * for the traditional COW bitmap.
++ * Move the backing_file field to the end of the header. This allows
++ * for the possibility of expanding it into the padding required
++ * by the bitmap alignment.
++ * The bitmap and data portions of the file will be aligned as specified
++ * by the alignment field. This is to allow COW files to be
++ * put on devices with restrictions on access alignments, such as
++ * /dev/raw, with a 512 byte alignment restriction. This also
++ * allows the data to be more aligned more strictly than on
++ * sector boundaries. This is needed for ubd-mmap, which needs
++ * the data to be page aligned.
++ * Fixed (finally!) the rounding bug
++ */
++
++struct cow_header_v3 {
++ __u32 magic;
++ __u32 version;
++ time_t mtime;
++ __u64 size;
++ __u32 sectorsize;
++ __u32 alignment;
++ __u32 cow_format;
++ char backing_file[PATH_LEN_V3];
++};
++
++/* COW format definitions - for now, we have only the usual COW bitmap */
++#define COW_BITMAP 0
++
++union cow_header {
++ struct cow_header_v1 v1;
++ struct cow_header_v2 v2;
++ struct cow_header_v3 v3;
++};
++
++#define COW_MAGIC 0x4f4f4f4d /* MOOO */
++#define COW_VERSION 3
++
++#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
++#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
++
++void cow_sizes(int version, __u64 size, int sectorsize, int align,
++ int bitmap_offset, unsigned long *bitmap_len_out,
++ int *data_offset_out)
++{
++ if(version < 3){
++ *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;
++ }
++ else {
++ *bitmap_len_out = DIV_ROUND(size, sectorsize);
++ *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
++
++ *data_offset_out = bitmap_offset + *bitmap_len_out;
++ *data_offset_out = ROUND_UP(*data_offset_out, align);
++ }
++}
++
++static int absolutize(char *to, int size, char *from)
++{
++ char save_cwd[256], *slash;
++ int remaining;
++
++ if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
++ cow_printf("absolutize : unable to get cwd - errno = %d\n",
++ errno);
++ return(-1);
++ }
++ slash = strrchr(from, '/');
++ if(slash != NULL){
++ *slash = '\0';
++ if(chdir(from)){
++ *slash = '/';
++ cow_printf("absolutize : Can't cd to '%s' - "
++ "errno = %d\n", from, errno);
++ return(-1);
++ }
++ *slash = '/';
++ if(getcwd(to, size) == NULL){
++ cow_printf("absolutize : unable to get cwd of '%s' - "
++ "errno = %d\n", from, errno);
++ return(-1);
++ }
++ remaining = size - strlen(to);
++ if(strlen(slash) + 1 > remaining){
++ cow_printf("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){
++ cow_printf("absolutize : unable to fit '%s' into %d "
++ "chars\n", from, size);
++ return(-1);
++ }
++ strcpy(to, save_cwd);
++ strcat(to, "/");
++ strcat(to, from);
++ }
++ chdir(save_cwd);
++ return(0);
++}
++
++int write_cow_header(char *cow_file, int fd, char *backing_file,
++ int sectorsize, int alignment, long long *size)
++{
++ struct cow_header_v3 *header;
++ unsigned long modtime;
++ int err;
++
++ err = cow_seek_file(fd, 0);
++ if(err < 0){
++ cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
++ goto out;
++ }
++
++ err = -ENOMEM;
++ header = cow_malloc(sizeof(*header));
++ if(header == NULL){
++ cow_printf("Failed to allocate COW V3 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){
++ cow_printf("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 = os_file_modtime(header->backing_file, &modtime);
++ if(err < 0){
++ cow_printf("Backing file '%s' mtime request failed, "
++ "err = %d\n", header->backing_file, -err);
++ goto out_free;
++ }
++
++ err = cow_file_size(header->backing_file, size);
++ if(err < 0){
++ cow_printf("Couldn't get size of backing file '%s', "
++ "err = %d\n", header->backing_file, -err);
++ goto out_free;
++ }
++
++ header->mtime = htonl(modtime);
++ header->size = htonll(*size);
++ header->sectorsize = htonl(sectorsize);
++ header->alignment = htonl(alignment);
++ header->cow_format = COW_BITMAP;
++
++ err = os_write_file(fd, header, sizeof(*header));
++ if(err != sizeof(*header)){
++ cow_printf("Write of header to new COW file '%s' failed, "
++ "err = %d\n", cow_file, -err);
++ goto out_free;
++ }
++ err = 0;
++ out_free:
++ cow_free(header);
++ out:
++ return(err);
++}
++
++int file_reader(__u64 offset, char *buf, int len, void *arg)
++{
++ int fd = *((int *) arg);
++
++ return(pread(fd, buf, len, offset));
++}
++
++/* XXX Need to sanity-check the values read from the header */
++
++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
++ __u32 *version_out, char **backing_file_out,
++ time_t *mtime_out, __u64 *size_out,
++ int *sectorsize_out, __u32 *align_out,
++ int *bitmap_offset_out)
++{
++ union cow_header *header;
++ char *file;
++ int err, n;
++ unsigned long version, magic;
++
++ header = cow_malloc(sizeof(*header));
++ if(header == NULL){
++ cow_printf("read_cow_header - Failed to allocate header\n");
++ return(-ENOMEM);
++ }
++ err = -EINVAL;
++ n = (*reader)(0, (char *) header, sizeof(*header), arg);
++ if(n < offsetof(typeof(header->v1), backing_file)){
++ cow_printf("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);
++ }
++ /* No error printed because the non-COW case comes through here */
++ else goto out;
++
++ *version_out = version;
++
++ if(version == 1){
++ if(n < sizeof(header->v1)){
++ cow_printf("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);
++ *align_out = *sectorsize_out;
++ file = header->v1.backing_file;
++ }
++ else if(version == 2){
++ if(n < sizeof(header->v2)){
++ cow_printf("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);
++ *align_out = *sectorsize_out;
++ file = header->v2.backing_file;
++ }
++ else if(version == 3){
++ if(n < sizeof(header->v3)){
++ cow_printf("read_cow_header - failed to read V2 "
++ "header\n");
++ goto out;
++ }
++ *mtime_out = ntohl(header->v3.mtime);
++ *size_out = ntohll(header->v3.size);
++ *sectorsize_out = ntohl(header->v3.sectorsize);
++ *align_out = ntohl(header->v3.alignment);
++ *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
++ file = header->v3.backing_file;
++ }
++ else {
++ cow_printf("read_cow_header - invalid COW version\n");
++ goto out;
++ }
++ err = -ENOMEM;
++ *backing_file_out = cow_strdup(file);
++ if(*backing_file_out == NULL){
++ cow_printf("read_cow_header - failed to allocate backing "
++ "file\n");
++ goto out;
++ }
++ err = 0;
++ out:
++ cow_free(header);
++ return(err);
++}
++
++int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
++ int alignment, int *bitmap_offset_out,
++ unsigned long *bitmap_len_out, int *data_offset_out)
++{
++ __u64 size, offset;
++ char zero = 0;
++ int err;
++
++ err = write_cow_header(cow_file, fd, backing_file, sectorsize,
++ alignment, &size);
++ if(err)
++ goto out;
++
++ *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
++ cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
++ bitmap_len_out, data_offset_out);
++
++ offset = *data_offset_out + size - sizeof(zero);
++ err = cow_seek_file(fd, offset);
++ if(err < 0){
++ cow_printf("cow bitmap lseek failed : err = %d\n", -err);
++ goto out;
++ }
++
++ /* does not really matter how much we write it is just to set EOF
++ * this also sets the entire COW bitmap
++ * to zero without having to allocate it
++ */
++ err = cow_write_file(fd, &zero, sizeof(zero));
++ if(err != sizeof(zero)){
++ cow_printf("Write of bitmap to new COW file '%s' failed, "
++ "err = %d\n", cow_file, -err);
++ err = -EINVAL;
++ goto out;
++ }
++
++ return(0);
++
++ out:
++ return(err);
++}
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon.h um/arch/um/drivers/daemon.h
+--- orig/arch/um/drivers/daemon.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/daemon.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon_kern.c um/arch/um/drivers/daemon_kern.c
+--- orig/arch/um/drivers/daemon_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/daemon_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,113 @@
++/*
++ * 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"
++
++struct daemon_init {
++ char *sock_type;
++ char *ctl_sock;
++};
++
++void daemon_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *pri;
++ struct daemon_data *dpri;
++ struct daemon_init *init = data;
++
++ init_etherdev(dev, 0);
++ pri = dev->priv;
++ dpri = (struct daemon_data *) pri->user;
++ *dpri = ((struct daemon_data)
++ { .sock_type = init->sock_type,
++ .ctl_sock = init->ctl_sock,
++ .ctl_addr = NULL,
++ .data_addr = NULL,
++ .local_addr = NULL,
++ .fd = -1,
++ .control = -1,
++ .dev = dev });
++
++ printk("daemon backend (uml_switch version %d) - %s:%s",
++ SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
++ printk("\n");
++}
++
++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 = eth_protocol,
++ .read = daemon_read,
++ .write = daemon_write,
++};
++
++int daemon_setup(char *str, char **mac_out, void *data)
++{
++ struct daemon_init *init = data;
++ char *remain;
++
++ *init = ((struct daemon_init)
++ { .sock_type = "unix",
++ .ctl_sock = "/tmp/uml.ctl" });
++
++ remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
++ NULL);
++ if(remain != NULL)
++ printk(KERN_WARNING "daemon_setup : Ignoring data socket "
++ "specification\n");
++
++ return(1);
++}
++
++static struct transport daemon_transport = {
++ .list = LIST_HEAD_INIT(daemon_transport.list),
++ .name = "daemon",
++ .setup = daemon_setup,
++ .user = &daemon_user_info,
++ .kern = &daemon_kern_info,
++ .private_size = sizeof(struct daemon_data),
++ .setup_size = sizeof(struct daemon_init),
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon_user.c um/arch/um/drivers/daemon_user.c
+--- orig/arch/um/drivers/daemon_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/daemon_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,197 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include "net_user.h"
++#include "daemon.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++enum request_type { REQ_NEW_CONTROL };
++
++#define SWITCH_MAGIC 0xfeedface
++
++struct request_v3 {
++ uint32_t magic;
++ uint32_t 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;
++
++ pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
++ if(pri->control < 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;
++ }
++
++ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
++ if(fd < 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 = os_write_file(pri->control, &req, sizeof(req));
++ if(n != sizeof(req)){
++ printk("daemon_open : control setup request failed, err = %d\n",
++ -n);
++ err = -ENOTCONN;
++ goto out;
++ }
++
++ n = os_read_file(pri->control, sun, sizeof(*sun));
++ if(n != sizeof(*sun)){
++ printk("daemon_open : read of data socket failed, err = %d\n",
++ -n);
++ err = -ENOTCONN;
++ goto out_close;
++ }
++
++ pri->data_addr = sun;
++ return(fd);
++
++ out_close:
++ os_close_file(fd);
++ out:
++ os_close_file(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;
++
++ os_close_file(pri->fd);
++ os_close_file(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/fd.c um/arch/um/drivers/fd.c
+--- orig/arch/um/drivers/fd.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/fd.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,97 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <termios.h>
++#include "user.h"
++#include "user_util.h"
++#include "chan_user.h"
++
++struct fd_chan {
++ int fd;
++ int raw;
++ struct termios tt;
++ char str[sizeof("1234567890\0")];
++};
++
++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') || (end == str)){
++ printk("fd_init : couldn't parse file descriptor '%s'\n", str);
++ return(NULL);
++ }
++ data = um_kmalloc(sizeof(*data));
++ if(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, char **dev_out)
++{
++ struct fd_chan *data = d;
++
++ if(data->raw && isatty(data->fd)){
++ tcgetattr(data->fd, &data->tt);
++ raw(data->fd, 0);
++ }
++ sprintf(data->str, "%d", data->fd);
++ *dev_out = data->str;
++ 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 = {
++ .type = "fd",
++ .init = fd_init,
++ .open = fd_open,
++ .close = fd_close,
++ .read = generic_read,
++ .write = generic_write,
++ .console_write = fd_console_write,
++ .window_size = generic_window_size,
++ .free = generic_free,
++ .winch = 1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/harddog_kern.c um/arch/um/drivers/harddog_kern.c
+--- orig/arch/um/drivers/harddog_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/harddog_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,194 @@
++/* UML hardware watchdog, shamelessly stolen from:
++ *
++ * SoftDog 0.05: A Software Watchdog Device
++ *
++ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
++ * http://www.redhat.com
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
++ * warranty for any of this software. This material is provided
++ * "AS-IS" and at no charge.
++ *
++ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
++ *
++ * Software only watchdog driver. Unlike its big brother the WDT501P
++ * driver this won't always recover a failed machine.
++ *
++ * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
++ * Modularised.
++ * Added soft_margin; use upon insmod to change the timer delay.
++ * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
++ * minors.
++ *
++ * 19980911 Alan Cox
++ * Made SMP safe for 2.3.x
++ *
++ * 20011127 Joel Becker (jlbec@evilplan.org>
++ * Added soft_noboot; Allows testing the softdog trigger without
++ * requiring a recompile.
++ * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include "helper.h"
++#include "mconsole.h"
++
++MODULE_LICENSE("GPL");
++
++/* Locked by the BKL in harddog_open and harddog_release */
++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;
++
++ lock_kernel();
++ 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;
++ unlock_kernel();
++ 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/harddog_user.c um/arch/um/drivers/harddog_user.c
+--- orig/arch/um/drivers/harddog_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/harddog_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include "user_util.h"
++#include "user.h"
++#include "helper.h"
++#include "mconsole.h"
++#include "os.h"
++#include "choose-mode.h"
++#include "mode.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);
++ os_close_file(data->stdin);
++ os_close_file(data->stdout);
++ os_close_file(data->close_me[0]);
++ os_close_file(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 < 0){
++ printk("harddog_open - os_pipe failed, err = %d\n", -err);
++ goto out;
++ }
++
++ err = os_pipe(out_fds, 1, 0);
++ if(err < 0){
++ printk("harddog_open - os_pipe failed, err = %d\n", -err);
++ goto out_close_in;
++ }
++
++ 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 {
++ /* XXX The os_getpid() is not SMP correct */
++ sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid()));
++ args = pid_args;
++ }
++
++ pid = run_helper(pre_exec, &data, args, NULL);
++
++ os_close_file(out_fds[0]);
++ os_close_file(in_fds[1]);
++
++ if(pid < 0){
++ err = -pid;
++ printk("harddog_open - run_helper failed, errno = %d\n", -err);
++ goto out_close_out;
++ }
++
++ n = os_read_file(in_fds[0], &c, sizeof(c));
++ if(n == 0){
++ printk("harddog_open - EOF on watchdog pipe\n");
++ helper_wait(pid);
++ err = -EIO;
++ goto out_close_out;
++ }
++ else if(n < 0){
++ printk("harddog_open - read of watchdog pipe failed, "
++ "err = %d\n", -n);
++ helper_wait(pid);
++ err = n;
++ goto out_close_out;
++ }
++ *in_fd_ret = in_fds[0];
++ *out_fd_ret = out_fds[1];
++ return(0);
++
++ out_close_in:
++ os_close_file(in_fds[0]);
++ os_close_file(in_fds[1]);
++ out_close_out:
++ os_close_file(out_fds[0]);
++ os_close_file(out_fds[1]);
++ out:
++ return(err);
++}
++
++void stop_watchdog(int in_fd, int out_fd)
++{
++ os_close_file(in_fd);
++ os_close_file(out_fd);
++}
++
++int ping_watchdog(int fd)
++{
++ int n;
++ char c = '\n';
++
++ n = os_write_file(fd, &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("ping_watchdog - write failed, err = %d\n", -n);
++ if(n < 0)
++ return(n);
++ return(-EIO);
++ }
++ return 1;
++
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/hostaudio_kern.c um/arch/um/drivers/hostaudio_kern.c
+--- orig/arch/um/drivers/hostaudio_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/hostaudio_kern.c 2004-02-12 05:46:22.000000000 -0500
+@@ -0,0 +1,352 @@
++/*
++ * Copyright (C) 2002 Steve Schmidtke
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/slab.h"
++#include "linux/fs.h"
++#include "linux/sound.h"
++#include "linux/soundcard.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++#include "init.h"
++#include "os.h"
++
++struct hostaudio_state {
++ int fd;
++};
++
++struct hostmixer_state {
++ int fd;
++};
++
++#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
++#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
++
++/* Only changed from linux_main at boot time */
++char *dsp = HOSTAUDIO_DEV_DSP;
++char *mixer = HOSTAUDIO_DEV_MIXER;
++
++#define DSP_HELP \
++" This is used to specify the host dsp device to the hostaudio driver.\n" \
++" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
++
++#define MIXER_HELP \
++" This is used to specify the host mixer device to the hostaudio driver.\n" \
++" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
++
++#ifndef MODULE
++static int set_dsp(char *name, int *add)
++{
++ dsp = name;
++ return(0);
++}
++
++__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
++
++static int set_mixer(char *name, int *add)
++{
++ mixer = name;
++ return(0);
++}
++
++__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
++
++#else /*MODULE*/
++
++MODULE_PARM(dsp, "s");
++MODULE_PARM_DESC(dsp, DSP_HELP);
++
++MODULE_PARM(mixer, "s");
++MODULE_PARM_DESC(mixer, MIXER_HELP);
++
++#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;
++ void *kbuf;
++ int err;
++
++#ifdef DEBUG
++ printk("hostaudio: read called, count = %d\n", count);
++#endif
++
++ kbuf = kmalloc(count, GFP_KERNEL);
++ if(kbuf == NULL)
++ return(-ENOMEM);
++
++ err = os_read_file(state->fd, kbuf, count);
++ if(err < 0)
++ goto out;
++
++ if(copy_to_user(buffer, kbuf, err))
++ err = -EFAULT;
++
++ out:
++ kfree(kbuf);
++ return(err);
++}
++
++static ssize_t hostaudio_write(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct hostaudio_state *state = file->private_data;
++ void *kbuf;
++ int err;
++
++#ifdef DEBUG
++ printk("hostaudio: write called, count = %d\n", count);
++#endif
++
++ kbuf = kmalloc(count, GFP_KERNEL);
++ if(kbuf == NULL)
++ return(-ENOMEM);
++
++ err = -EFAULT;
++ if(copy_from_user(kbuf, buffer, count))
++ goto out;
++
++ err = os_write_file(state->fd, kbuf, count);
++ if(err < 0)
++ goto out;
++ *ppos += err;
++
++ out:
++ kfree(kbuf);
++ return(err);
++}
++
++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;
++ unsigned long data = 0;
++ int err;
++
++#ifdef DEBUG
++ printk("hostaudio: ioctl called, cmd = %u\n", cmd);
++#endif
++ switch(cmd){
++ case SNDCTL_DSP_SPEED:
++ case SNDCTL_DSP_STEREO:
++ case SNDCTL_DSP_GETBLKSIZE:
++ case SNDCTL_DSP_CHANNELS:
++ case SNDCTL_DSP_SUBDIVIDE:
++ case SNDCTL_DSP_SETFRAGMENT:
++ if(get_user(data, (int *) arg))
++ return(-EFAULT);
++ break;
++ default:
++ break;
++ }
++
++ err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
++
++ switch(cmd){
++ case SNDCTL_DSP_SPEED:
++ case SNDCTL_DSP_STEREO:
++ case SNDCTL_DSP_GETBLKSIZE:
++ case SNDCTL_DSP_CHANNELS:
++ case SNDCTL_DSP_SUBDIVIDE:
++ case SNDCTL_DSP_SETFRAGMENT:
++ if(put_user(data, (int *) arg))
++ return(-EFAULT);
++ break;
++ default:
++ break;
++ }
++
++ return(err);
++}
++
++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 = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
++ if(ret < 0){
++ kfree(state);
++ return(ret);
++ }
++
++ state->fd = ret;
++ file->private_data = state;
++ return(0);
++}
++
++static int hostaudio_release(struct inode *inode, struct file *file)
++{
++ struct hostaudio_state *state = file->private_data;
++
++#ifdef DEBUG
++ printk("hostaudio: release called\n");
++#endif
++
++ os_close_file(state->fd);
++ kfree(state);
++
++ return(0);
++}
++
++/* /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(os_ioctl_generic(state->fd, 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 = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
++
++ if(ret < 0){
++ printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
++ dsp, -ret);
++ 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;
++
++#ifdef DEBUG
++ printk("hostmixer: release called\n");
++#endif
++
++ os_close_file(state->fd);
++ kfree(state);
++
++ return(0);
++}
++
++
++/* 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 (host dsp = %s, host mixer = %s)\n",
++ dsp, mixer);
++
++ module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
++ if(module_data.dev_audio < 0){
++ printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
++ return -ENODEV;
++ }
++
++ module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
++ if(module_data.dev_mixer < 0){
++ printk(KERN_ERR "hostmixer: couldn't register mixer "
++ "device!\n");
++ unregister_sound_dsp(module_data.dev_audio);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static void __exit hostaudio_cleanup_module (void)
++{
++ unregister_sound_mixer(module_data.dev_mixer);
++ unregister_sound_dsp(module_data.dev_audio);
++}
++
++module_init(hostaudio_init_module);
++module_exit(hostaudio_cleanup_module);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/line.c um/arch/um/drivers/line.c
+--- orig/arch/um/drivers/line.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/line.c 2003-11-07 03:03:57.000000000 -0500
+@@ -0,0 +1,610 @@
++/*
++ * 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 "asm/uaccess.h"
++#include "chan_kern.h"
++#include "irq_user.h"
++#include "line.h"
++#include "kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "os.h"
++#include "irq_kern.h"
++
++#define LINE_BUFSIZE 4096
++
++static 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);
++}
++
++static void line_timer_cb(void *arg)
++{
++ struct line *dev = arg;
++
++ line_interrupt(dev->driver->read_irq, dev, NULL);
++}
++
++static int write_room(struct line *dev)
++{
++ 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);
++}
++
++static int buffer_data(struct line *line, const char *buf, int len)
++{
++ int end, room;
++
++ if(line->buffer == NULL){
++ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
++ if(line->buffer == NULL){
++ printk("buffer_data - atomic allocation failed\n");
++ return(0);
++ }
++ line->head = line->buffer;
++ line->tail = line->buffer;
++ }
++
++ room = write_room(line);
++ len = (len > room) ? room : len;
++
++ 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;
++ }
++
++ return(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, int from_user,
++ const char *buf, int len)
++{
++ struct line *line;
++ char *new;
++ unsigned long flags;
++ int n, err, i, ret = 0;
++
++ if(tty->stopped) return 0;
++
++ if(from_user){
++ new = kmalloc(len, GFP_KERNEL);
++ if(new == NULL)
++ return(0);
++ n = copy_from_user(new, buf, len);
++ buf = new;
++ if(n == len){
++ len = -EFAULT;
++ goto out_free;
++ }
++
++ len -= n;
++ }
++
++ i = minor(tty->device) - tty->driver.minor_start;
++ line = &lines[i];
++
++ down(&line->sem);
++ if(line->head != line->tail){
++ local_irq_save(flags);
++ ret += buffer_data(line, buf, len);
++ err = flush_buffer(line);
++ local_irq_restore(flags);
++ if(err <= 0)
++ goto out_up;
++ }
++ else {
++ n = write_chan(&line->chan_list, buf, len,
++ line->driver->write_irq);
++ if(n < 0){
++ ret = n;
++ goto out_up;
++ }
++
++ len -= n;
++ ret += n;
++ if(len > 0)
++ ret += buffer_data(line, buf + n, len);
++ }
++ out_up:
++ up(&line->sem);
++
++ out_free:
++ if(from_user)
++ kfree(buf);
++ return(ret);
++}
++
++static 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_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];
++
++ down(&line->sem);
++ 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);
++ up(&line->sem);
++}
++
++void close_lines(struct line *lines, int nlines)
++{
++ int i;
++
++ for(i = 0; i < nlines; i++)
++ close_chan(&lines[i].chan_list);
++}
++
++int line_setup(struct line *lines, int num, char *init, int all_allowed)
++{
++ 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(0);
++ }
++ init = end;
++ }
++ init++;
++ if((n >= 0) && (n >= num)){
++ printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
++ n, num);
++ return(0);
++ }
++ else if(n >= 0){
++ if(lines[n].count > 0){
++ printk("line_setup - device %d is open\n", n);
++ return(0);
++ }
++ 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;
++ }
++ }
++ }
++ else if(!all_allowed){
++ printk("line_setup - can't configure all devices from "
++ "mconsole\n");
++ return(0);
++ }
++ else {
++ 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;
++ }
++ }
++ }
++ }
++ return(1);
++}
++
++int line_config(struct line *lines, int num, char *str)
++{
++ char *new = uml_strdup(str);
++
++ if(new == NULL){
++ printk("line_config - uml_strdup failed\n");
++ return(-ENOMEM);
++ }
++ return(!line_setup(lines, num, new, 0));
++}
++
++int line_get_config(char *name, struct line *lines, int num, char *str,
++ int size, char **error_out)
++{
++ struct line *line;
++ char *end;
++ int dev, n = 0;
++
++ dev = simple_strtoul(name, &end, 0);
++ if((*end != '\0') || (end == name)){
++ *error_out = "line_get_config failed to parse device number";
++ return(0);
++ }
++
++ if((dev < 0) || (dev >= num)){
++ *error_out = "device number of of range";
++ return(0);
++ }
++
++ line = &lines[dev];
++
++ down(&line->sem);
++ if(!line->valid)
++ CONFIG_CHUNK(str, size, n, "none", 1);
++ else if(line->count == 0)
++ CONFIG_CHUNK(str, size, n, line->init_str, 1);
++ else n = chan_config_string(&line->chan_list, str, size, error_out);
++ up(&line->sem);
++
++ return(n);
++}
++
++int line_remove(struct line *lines, int num, char *str)
++{
++ char config[sizeof("conxxxx=none\0")];
++
++ sprintf(config, "%s=none", str);
++ return(!line_setup(lines, num, config, 0));
++}
++
++static int line_write_room(struct tty_struct *tty)
++{
++ struct line *dev = tty->driver_data;
++
++ return(write_room(dev));
++}
++
++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;
++
++ 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);
++ }
++
++ mconsole_register_dev(&line_driver->mc);
++}
++
++void lines_init(struct line *lines, int nlines)
++{
++ struct line *line;
++ int i;
++
++ for(i = 0; i < nlines; i++){
++ line = &lines[i];
++ INIT_LIST_HEAD(&line->chan_list);
++ sema_init(&line->sem, 1);
++ if(line->init_str != NULL){
++ line->init_str = uml_strdup(line->init_str);
++ if(line->init_str == NULL)
++ printk("lines_init - uml_strdup returned "
++ "NULL\n");
++ }
++ }
++}
++
++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;
++
++ if(winch->fd != -1){
++ 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);
++ 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:
++ if(winch->fd != -1)
++ reactivate_fd(winch->fd, WINCH_IRQ);
++}
++
++DECLARE_MUTEX(winch_handler_sem);
++LIST_HEAD(winch_handlers);
++
++void register_winch_irq(int fd, int tty_fd, int pid, void *line)
++{
++ struct winch *winch;
++
++ down(&winch_handler_sem);
++ winch = kmalloc(sizeof(*winch), GFP_KERNEL);
++ if(winch == NULL){
++ printk("register_winch_irq - kmalloc failed\n");
++ goto out;
++ }
++ *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");
++ out:
++ up(&winch_handler_sem);
++}
++
++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);
++ if(winch->fd != -1){
++ deactivate_fd(winch->fd, WINCH_IRQ);
++ os_close_file(winch->fd);
++ }
++ if(winch->pid != -1)
++ os_kill_process(winch->pid, 1);
++ }
++}
++
++__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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/Makefile um/arch/um/drivers/Makefile
+--- orig/arch/um/drivers/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/Makefile 2004-02-12 03:55:08.000000000 -0500
+@@ -0,0 +1,97 @@
++#
++# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := built-in.o
++
++CHAN_OBJS := chan_kern.o chan_user.o line.o
++
++list-multi := slip.o slirp.o daemon.o mcast.o mconsole.o net.o ubd.o \
++ hostaudio.o pcap.o port.o harddog.o
++
++slip-objs := slip_kern.o slip_user.o
++slirp-objs := slirp_kern.o slirp_user.o
++daemon-objs := daemon_kern.o daemon_user.o
++mcast-objs := mcast_kern.o mcast_user.o
++pcap-objs := pcap_kern.o pcap_user.o
++pcap-libs := -lpcap -L/usr/lib
++net-objs := net_kern.o net_user.o
++mconsole-objs := mconsole_kern.o mconsole_user.o
++hostaudio-objs := hostaudio_kern.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_SLIRP) += slirp.o
++obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
++obj-$(CONFIG_UML_NET_MCAST) += mcast.o
++obj-$(CONFIG_UML_NET_PCAP) += pcap.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 xterm_kern.o
++obj-$(CONFIG_UML_WATCHDOG) += harddog.o
++obj-$(CONFIG_COW) += cow_kern.o
++obj-$(CONFIG_COW_COMMON) += cow_user.o
++
++CFLAGS_pcap_user.o = -I/usr/include/pcap
++
++obj-y += stdio_console.o $(CHAN_OBJS)
++
++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
++
++USER_OBJS = $(filter %_user.o,$(obj-y) $(obj-m) $(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)
++
++slirp.o : $(slirp-objs)
++
++mcast.o : $(mcast-objs)
++
++pcap.o : $(pcap-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) -r -o $@ $($(patsubst %.o,%,$@)-objs) $($(patsubst %.o,%,$@)-libs)
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast.h um/arch/um/drivers/mcast.h
+--- orig/arch/um/drivers/mcast.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mcast.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * 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;
++ 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast_kern.c um/arch/um/drivers/mcast_kern.c
+--- orig/arch/um/drivers/mcast_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mcast_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,145 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ */
++
++#include "linux/kernel.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/in.h"
++#include "linux/inet.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "mcast.h"
++
++struct mcast_init {
++ char *addr;
++ int port;
++ int ttl;
++};
++
++void mcast_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *pri;
++ struct mcast_data *dpri;
++ struct mcast_init *init = data;
++
++ init_etherdev(dev, 0);
++ pri = dev->priv;
++ dpri = (struct mcast_data *) pri->user;
++ *dpri = ((struct mcast_data)
++ { .addr = init->addr,
++ .port = init->port,
++ .ttl = init->ttl,
++ .mcast_addr = NULL,
++ .dev = dev });
++ printk("mcast backend ");
++ printk("multicast adddress: %s:%u, TTL:%u ",
++ dpri->addr, dpri->port, dpri->ttl);
++
++ printk("\n");
++}
++
++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 = eth_protocol,
++ .read = mcast_read,
++ .write = mcast_write,
++};
++
++int mcast_setup(char *str, char **mac_out, void *data)
++{
++ struct mcast_init *init = data;
++ char *port_str = NULL, *ttl_str = NULL, *remain;
++ char *last;
++ int n;
++
++ *init = ((struct mcast_init)
++ { .addr = "239.192.168.1",
++ .port = 1102,
++ .ttl = 1 });
++
++ remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
++ NULL);
++ if(remain != NULL){
++ printk(KERN_ERR "mcast_setup - Extra garbage on "
++ "specification : '%s'\n", remain);
++ return(0);
++ }
++
++ if(port_str != NULL){
++ n = simple_strtoul(port_str, &last, 10);
++ if((*last != '\0') || (last == port_str)){
++ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
++ port_str);
++ return(0);
++ }
++ init->port = htons(n);
++ }
++
++ if(ttl_str != NULL){
++ init->ttl = simple_strtoul(ttl_str, &last, 10);
++ if((*last != '\0') || (last == ttl_str)){
++ printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
++ ttl_str);
++ return(0);
++ }
++ }
++
++ printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
++ init->port, init->ttl);
++
++ return(1);
++}
++
++static struct transport mcast_transport = {
++ .list = LIST_HEAD_INIT(mcast_transport.list),
++ .name = "mcast",
++ .setup = mcast_setup,
++ .user = &mcast_user_info,
++ .kern = &mcast_kern_info,
++ .private_size = sizeof(struct mcast_data),
++ .setup_size = sizeof(struct mcast_init),
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast_user.c um/arch/um/drivers/mcast_user.c
+--- orig/arch/um/drivers/mcast_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mcast_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,177 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ *
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <linux/inet.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include <netinet/in.h>
++#include "net_user.h"
++#include "mcast.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.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;
++ }
++
++ fd = socket(AF_INET, SOCK_DGRAM, 0);
++ if (fd < 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);
++ os_close_file(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);
++ os_close_file(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);
++ os_close_file(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);
++ os_close_file(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");
++ os_close_file(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);
++ }
++
++ os_close_file(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mconsole_kern.c um/arch/um/drivers/mconsole_kern.c
+--- orig/arch/um/drivers/mconsole_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mconsole_kern.c 2004-02-12 03:09:12.000000000 -0500
+@@ -0,0 +1,560 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.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/file.h"
++#include "linux/fs.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"
++#include "irq_kern.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,
++};
++
++/* Safe without explicit locking for now. Tasklets provide their own
++ * locking, and the interrupt handler is safe because it can't interrupt
++ * itself and it can only happen on CPU 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->context == MCONSOLE_INTR)
++ (*req.cmd->handler)(&req);
++ else {
++ new = kmalloc(sizeof(*new), 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);
++}
++
++void mconsole_log(struct mc_request *req)
++{
++ int len;
++ char *ptr = req->request.data;
++
++ ptr += strlen("log ");
++
++ len = req->len - (ptr - req->request.data);
++ printk("%.*s", len, ptr);
++ mconsole_reply(req, "", 0, 0);
++}
++
++void mconsole_proc(struct mc_request *req)
++{
++ struct nameidata nd;
++ struct file_system_type *proc;
++ struct super_block *super;
++ struct file *file;
++ int n, err;
++ char *ptr = req->request.data, *buf;
++
++ ptr += strlen("proc");
++ while(isspace(*ptr)) ptr++;
++
++ proc = get_fs_type("proc");
++ if(proc == NULL){
++ mconsole_reply(req, "procfs not registered", 1, 0);
++ goto out;
++ }
++
++ super = get_anon_super(proc, NULL, NULL);
++ if(super == NULL){
++ mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
++ goto out_put;
++ }
++
++ if(super->s_root == NULL){
++ super = (*proc->read_super)(super, NULL, 0);
++ if(super == NULL){
++ mconsole_reply(req, "Failed to read superblock", 1, 0);
++ goto out_put;
++ }
++ }
++ up_write(&super->s_umount);
++
++ nd.dentry = super->s_root;
++ nd.mnt = NULL;
++ nd.flags = O_RDONLY + 1;
++ nd.last_type = LAST_ROOT;
++
++ err = link_path_walk(ptr, &nd);
++ if(err){
++ mconsole_reply(req, "Failed to look up file", 1, 0);
++ goto out_kill;
++ }
++
++ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++ if(IS_ERR(file)){
++ mconsole_reply(req, "Failed to open file", 1, 0);
++ goto out_kill;
++ }
++
++ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++ if(buf == NULL){
++ mconsole_reply(req, "Failed to allocate buffer", 1, 0);
++ goto out_fput;
++ }
++
++ if((file->f_op != NULL) && (file->f_op->read != NULL)){
++ do {
++ n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
++ &file->f_pos);
++ if(n >= 0){
++ buf[n] = '\0';
++ mconsole_reply(req, buf, 0, (n > 0));
++ }
++ else {
++ mconsole_reply(req, "Read of file failed",
++ 1, 0);
++ goto out_free;
++ }
++ } while(n > 0);
++ }
++ else mconsole_reply(req, "", 0, 0);
++
++ out_free:
++ kfree(buf);
++ out_fput:
++ fput(file);
++ out_kill:
++ kill_super(super);
++ out_put:
++ /* put_filesystem(proc); */
++ out: ;
++}
++
++#define UML_MCONSOLE_HELPTEXT \
++"Commands: \n\
++ version - Get kernel version \n\
++ help - Print this message \n\
++ halt - Halt UML \n\
++ reboot - Reboot UML \n\
++ config <dev>=<config> - Add a new device to UML; \n\
++ same syntax as command line \n\
++ config <dev> - Query the configuration of a device \n\
++ remove <dev> - Remove a device from UML \n\
++ sysrq <letter> - Performs the SysRq action controlled by the letter \n\
++ cad - invoke the Ctl-Alt-Del handler \n\
++ stop - pause the UML; it will do nothing until it receives a 'go' \n\
++ go - continue the UML after a 'stop' \n\
++ log <string> - make UML enter <string> into the kernel log\n\
++ proc <file> - returns the contents of the UML's /proc/<file>\n\
++"
++
++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);
++}
++
++/* This list is populated by __initcall routines. */
++
++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);
++}
++
++#define CONFIG_BUF_SIZE 64
++
++static void mconsole_get_config(int (*get_config)(char *, char *, int,
++ char **),
++ struct mc_request *req, char *name)
++{
++ char default_buf[CONFIG_BUF_SIZE], *error, *buf;
++ int n, size;
++
++ if(get_config == NULL){
++ mconsole_reply(req, "No get_config routine defined", 1, 0);
++ return;
++ }
++
++ error = NULL;
++ size = sizeof(default_buf)/sizeof(default_buf[0]);
++ buf = default_buf;
++
++ while(1){
++ n = (*get_config)(name, buf, size, &error);
++ if(error != NULL){
++ mconsole_reply(req, error, 1, 0);
++ goto out;
++ }
++
++ if(n <= size){
++ mconsole_reply(req, buf, 0, 0);
++ goto out;
++ }
++
++ if(buf != default_buf)
++ kfree(buf);
++
++ size = n;
++ buf = kmalloc(size, GFP_KERNEL);
++ if(buf == NULL){
++ mconsole_reply(req, "Failed to allocate buffer", 1, 0);
++ return;
++ }
++ }
++ out:
++ if(buf != default_buf)
++ kfree(buf);
++
++}
++
++void mconsole_config(struct mc_request *req)
++{
++ struct mc_device *dev;
++ char *ptr = req->request.data, *name;
++ 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;
++ }
++
++ name = &ptr[strlen(dev->name)];
++ ptr = name;
++ while((*ptr != '=') && (*ptr != '\0'))
++ ptr++;
++
++ if(*ptr == '='){
++ err = (*dev->config)(name);
++ mconsole_reply(req, "", err, 0);
++ }
++ else mconsole_get_config(dev->get_config, req, name);
++}
++
++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++;
++
++ mconsole_reply(req, "", 0, 0);
++ handle_sysrq(*ptr, ¤t->thread.regs, NULL, NULL);
++}
++#else
++void mconsole_sysrq(struct mc_request *req)
++{
++ mconsole_reply(req, "Sysrq not compiled in", 1, 0);
++}
++#endif
++
++/* Changed by mconsole_setup, which is __setup, and called before SMP is
++ * active.
++ */
++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 = os_create_unix_socket(file, sizeof(file), 1);
++ 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)){
++ count = -EFAULT;
++ goto out;
++ }
++
++ buf[count] = '\0';
++
++ mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
++ out:
++ kfree(buf);
++ 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);
++}
++
++static spinlock_t notify_spinlock = SPIN_LOCK_UNLOCKED;
++
++void lock_notify(void)
++{
++ spin_lock(¬ify_spinlock);
++}
++
++void unlock_notify(void)
++{
++ spin_unlock(¬ify_spinlock);
++}
++
++__initcall(create_proc_mconsole);
++
++#define NOTIFY "=notify:"
++
++static int mconsole_setup(char *str)
++{
++ if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
++ str += strlen(NOTIFY);
++ notify_socket = str;
++ }
++ else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
++ return(1);
++}
++
++__setup("mconsole", mconsole_setup);
++
++__uml_help(mconsole_setup,
++"mconsole=notify:<socket>\n"
++" Requests that the mconsole driver send a message to the named Unix\n"
++" socket containing the name of the mconsole socket. This also serves\n"
++" to notify outside processes when UML has booted far enough to respond\n"
++" to mconsole requests.\n\n"
++);
++
++static int notify_panic(struct notifier_block *self, unsigned long unused1,
++ void *ptr)
++{
++ char *message = ptr;
++
++ if(notify_socket == NULL) return(0);
++
++ mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
++ strlen(message) + 1);
++ return(0);
++}
++
++static struct notifier_block panic_exit_notifier = {
++ .notifier_call = notify_panic,
++ .next = NULL,
++ .priority = 1
++};
++
++static int add_notifier(void)
++{
++ notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
++ return(0);
++}
++
++__initcall(add_notifier);
++
++char *mconsole_notify_socket(void)
++{
++ return(notify_socket);
++}
++
++EXPORT_SYMBOL(mconsole_notify_socket);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mconsole_user.c um/arch/um/drivers/mconsole_user.c
+--- orig/arch/um/drivers/mconsole_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mconsole_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,215 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <sys/un.h>
++#include <unistd.h>
++#include "user.h"
++#include "mconsole.h"
++#include "umid.h"
++
++static struct mconsole_command commands[] = {
++ { "version", mconsole_version, MCONSOLE_INTR },
++ { "halt", mconsole_halt, MCONSOLE_PROC },
++ { "reboot", mconsole_reboot, MCONSOLE_PROC },
++ { "config", mconsole_config, MCONSOLE_PROC },
++ { "remove", mconsole_remove, MCONSOLE_PROC },
++ { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
++ { "help", mconsole_help, MCONSOLE_INTR },
++ { "cad", mconsole_cad, MCONSOLE_INTR },
++ { "stop", mconsole_stop, MCONSOLE_PROC },
++ { "go", mconsole_go, MCONSOLE_INTR },
++ { "log", mconsole_log, MCONSOLE_INTR },
++ { "proc", mconsole_proc, MCONSOLE_PROC },
++};
++
++/* Initialized in mconsole_init, which is an initcall */
++char mconsole_socket_name[256];
++
++int mconsole_reply_v0(struct mc_request *req, char *reply)
++{
++ struct iovec iov;
++ struct msghdr msg;
++
++ iov.iov_base = reply;
++ iov.iov_len = strlen(reply);
++
++ msg.msg_name = &(req->origin);
++ msg.msg_namelen = req->originlen;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_flags = 0;
++
++ return sendmsg(req->originating_fd, &msg, 0);
++}
++
++static struct mconsole_command *mconsole_parse(struct mc_request *req)
++{
++ struct mconsole_command *cmd;
++ int i;
++
++ for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
++ cmd = &commands[i];
++ if(!strncmp(req->request.data, cmd->command,
++ strlen(cmd->command))){
++ return(cmd);
++ }
++ }
++ return(NULL);
++}
++
++#define MIN(a,b) ((a)<(b) ? (a):(b))
++
++#define STRINGX(x) #x
++#define STRING(x) STRINGX(x)
++
++int mconsole_get_request(int fd, struct mc_request *req)
++{
++ int len;
++
++ req->originlen = sizeof(req->origin);
++ req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
++ (struct sockaddr *) req->origin, &req->originlen);
++ if (req->len < 0)
++ return 0;
++
++ req->originating_fd = fd;
++
++ if(req->request.magic != MCONSOLE_MAGIC){
++ /* Unversioned request */
++ len = MIN(sizeof(req->request.data) - 1,
++ strlen((char *) &req->request));
++ memmove(req->request.data, &req->request, len);
++ req->request.data[len] = '\0';
++
++ req->request.magic = MCONSOLE_MAGIC;
++ req->request.version = 0;
++ req->request.len = len;
++
++ mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
++ "not supported by this driver");
++ return(0);
++ }
++
++ if(req->request.len >= MCONSOLE_MAX_DATA){
++ mconsole_reply(req, "Request too large", 1, 0);
++ return(0);
++ }
++ if(req->request.version != MCONSOLE_VERSION){
++ mconsole_reply(req, "This driver only supports version "
++ STRING(MCONSOLE_VERSION) " clients", 1, 0);
++ }
++
++ req->request.data[req->request.len] = '\0';
++ req->cmd = mconsole_parse(req);
++ if(req->cmd == NULL){
++ mconsole_reply(req, "Unknown command", 1, 0);
++ return(0);
++ }
++
++ return(1);
++}
++
++int mconsole_reply(struct mc_request *req, char *str, int err, int more)
++{
++ struct mconsole_reply reply;
++ int total, len, n;
++
++ total = strlen(str);
++ do {
++ reply.err = err;
++
++ /* err can only be true on the first packet */
++ err = 0;
++
++ len = MIN(total, MCONSOLE_MAX_DATA - 1);
++
++ if(len == total) reply.more = more;
++ else reply.more = 1;
++
++ memcpy(reply.data, str, len);
++ reply.data[len] = '\0';
++ total -= len;
++ str += 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 = 0;
++
++ lock_notify();
++ 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);
++ err = -errno;
++ }
++ }
++ unlock_notify();
++
++ if(err)
++ return(err);
++
++ 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/mmapper_kern.c um/arch/um/drivers/mmapper_kern.c
+--- orig/arch/um/drivers/mmapper_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/mmapper_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,151 @@
++/*
++ * arch/um/drivers/mmapper_kern.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ *
++ * Copyright (C) 2000 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ */
++#include <linux/kdev_t.h>
++#include <linux/time.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/smplock.h>
++#include <asm/pgtable.h>
++#include "mem_user.h"
++#include "user_util.h"
++
++/* These are set in mmapper_init, which is called at boot time */
++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){
++ printk(KERN_ERR "mmapper_init - find_iomem failed\n");
++ return(0);
++ }
++
++ p_buf = __pa(v_buf);
++
++ devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT,
++ 30, 0, S_IFCHR | S_IRUGO | S_IWUGO,
++ &mmapper_fops, NULL);
++ devfs_mk_symlink(NULL, "mmapper0", DEVFS_FL_DEFAULT, "mmapper",
++ NULL, NULL);
++ return(0);
++}
++
++static void mmapper_exit(void)
++{
++}
++
++module_init(mmapper_init);
++module_exit(mmapper_exit);
++
++MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
++MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/net_kern.c um/arch/um/drivers/net_kern.c
+--- orig/arch/um/drivers/net_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/net_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,872 @@
++/*
++ * 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/rtnetlink.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"
++#include "irq_kern.h"
++
++static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
++LIST_HEAD(opened);
++
++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. */
++ skb = dev_alloc_skb(dev->mtu);
++ if (skb == NULL) {
++ lp->stats.rx_dropped++;
++ return 0;
++ }
++
++ skb->dev = dev;
++ skb_put(skb, dev->mtu);
++ skb->mac.raw = skb->data;
++ pkt_len = (*lp->read)(lp->fd, &skb, lp);
++
++ 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))
++ return;
++
++ 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_close(dev);
++ goto out;
++ }
++ reactivate_fd(lp->fd, UM_ETH_IRQ);
++
++ out:
++ 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);
++
++ spin_lock(&opened_lock);
++ list_add(&lp->list, &opened);
++ spin_unlock(&opened_lock);
++ 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;
++ spin_lock(&opened_lock);
++ list_del(&lp->list);
++ spin_unlock(&opened_lock);
++
++ 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
++}
++
++/*
++ * default do nothing hard header packet routines for struct net_device init.
++ * real ethernet transports will overwrite with real routines.
++ */
++static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
++ unsigned short type, void *daddr, void *saddr, unsigned len)
++{
++ return(0); /* no change */
++}
++
++static int uml_net_rebuild_header(struct sk_buff *skb)
++{
++ return(0); /* ignore */
++}
++
++static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
++{
++ return(-1); /* fail */
++}
++
++static void uml_net_header_cache_update(struct hh_cache *hh,
++ struct net_device *dev, unsigned char * haddr)
++{
++ /* ignore */
++}
++
++static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
++{
++ return(0); /* nothing */
++}
++
++static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head devices = LIST_HEAD_INIT(devices);
++
++static int eth_configure(int n, void *init, char *mac,
++ struct transport *transport)
++{
++ struct uml_net *device;
++ struct net_device *dev;
++ struct uml_net_private *lp;
++ int save, err, size;
++
++ size = transport->private_size + sizeof(struct uml_net_private) +
++ sizeof(((struct uml_net_private *) 0)->user);
++
++ device = kmalloc(sizeof(*device), GFP_KERNEL);
++ if(device == NULL){
++ printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
++ return(1);
++ }
++
++ *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list),
++ .dev = NULL,
++ .index = n,
++ .mac = { [ 0 ... 5 ] = 0 },
++ .have_mac = 0 });
++
++ spin_lock(&devices_lock);
++ list_add(&device->list, &devices);
++ spin_unlock(&devices_lock);
++
++ if(setup_etheraddr(mac, device->mac))
++ device->have_mac = 1;
++
++ 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 = kmalloc(sizeof(*dev) + size, GFP_KERNEL);
++ if(dev == NULL){
++ printk(KERN_ERR "eth_configure: failed to allocate device\n");
++ return(1);
++ }
++ memset(dev, 0, sizeof(*dev) + size);
++
++ snprintf(dev->name, sizeof(dev->name), "eth%d", n);
++ dev->priv = (void *) &dev[1];
++ device->dev = dev;
++
++ dev->hard_header = uml_net_hard_header;
++ dev->rebuild_header = uml_net_rebuild_header;
++ dev->hard_header_cache = uml_net_header_cache;
++ dev->header_cache_update= uml_net_header_cache_update;
++ dev->hard_header_parse = uml_net_header_parse;
++
++ (*transport->kern->init)(dev, init);
++
++ dev->mtu = transport->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;
++
++ rtnl_lock();
++ err = register_netdevice(dev);
++ rtnl_unlock();
++ if(err)
++ return(1);
++ 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 = transport->kern->protocol,
++ .open = transport->user->open,
++ .close = transport->user->close,
++ .remove = transport->user->remove,
++ .read = transport->kern->read,
++ .write = transport->kern->write,
++ .add_address = transport->user->add_address,
++ .delete_address = transport->user->delete_address,
++ .set_mtu = transport->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(transport->user->init)
++ (*transport->user->init)(&lp->user, dev);
++
++ if(device->have_mac)
++ set_ether_mac(dev, device->mac);
++ return(0);
++}
++
++static struct uml_net *find_device(int n)
++{
++ struct uml_net *device;
++ struct list_head *ele;
++
++ spin_lock(&devices_lock);
++ list_for_each(ele, &devices){
++ device = list_entry(ele, struct uml_net, list);
++ if(device->index == n)
++ goto out;
++ }
++ device = NULL;
++ out:
++ spin_unlock(&devices_lock);
++ return(device);
++}
++
++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){
++ printk(KERN_ERR "eth_setup: device %d is negative\n", n);
++ return(1);
++ }
++ str = end;
++ if(*str != '='){
++ printk(KERN_ERR
++ "eth_setup: expected '=' after device number\n");
++ return(1);
++ }
++ str++;
++ if(find_device(n)){
++ 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;
++};
++
++/* Filled in at boot time. Will need locking if the transports become
++ * modular.
++ */
++struct list_head transports = LIST_HEAD_INIT(transports);
++
++/* Filled in during early boot */
++struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
++
++static int check_transport(struct transport *transport, char *eth, int n,
++ void **init_out, char **mac_out)
++{
++ int len;
++
++ len = strlen(transport->name);
++ if(strncmp(eth, transport->name, len))
++ return(0);
++
++ eth += len;
++ if(*eth == ',')
++ eth++;
++ else if(*eth != '\0')
++ return(0);
++
++ *init_out = kmalloc(transport->setup_size, GFP_KERNEL);
++ if(*init_out == NULL)
++ return(1);
++
++ if(!transport->setup(eth, mac_out, *init_out)){
++ kfree(*init_out);
++ *init_out = NULL;
++ }
++ return(1);
++}
++
++void register_transport(struct transport *new)
++{
++ struct list_head *ele, *next;
++ struct eth_init *eth;
++ void *init;
++ char *mac = NULL;
++ int match;
++
++ list_add(&new->list, &transports);
++
++ list_for_each_safe(ele, next, ð_cmd_line){
++ eth = list_entry(ele, struct eth_init, list);
++ match = check_transport(new, eth->init, eth->index, &init,
++ &mac);
++ if(!match)
++ continue;
++ else if(init != NULL){
++ eth_configure(eth->index, init, mac, new);
++ kfree(init);
++ }
++ list_del(ð->list);
++ }
++}
++
++static int eth_setup_common(char *str, int index)
++{
++ struct list_head *ele;
++ struct transport *transport;
++ void *init;
++ char *mac = NULL;
++
++ list_for_each(ele, &transports){
++ transport = list_entry(ele, struct transport, list);
++ if(!check_transport(transport, str, index, &init, &mac))
++ continue;
++ if(init != NULL){
++ eth_configure(index, init, mac, transport);
++ kfree(init);
++ }
++ return(1);
++ }
++ return(0);
++}
++
++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]+=<transport>,<options>\n"
++" Configure a network device.\n\n"
++);
++
++static int eth_init(void)
++{
++ struct list_head *ele, *next;
++ struct eth_init *eth;
++
++ list_for_each_safe(ele, next, ð_cmd_line){
++ eth = list_entry(ele, struct eth_init, list);
++
++ if(eth_setup_common(eth->init, eth->index))
++ list_del(ð->list);
++ }
++
++ return(1);
++}
++
++__initcall(eth_init);
++
++static int net_config(char *str)
++{
++ int n, err;
++
++ 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);
++}
++
++static int net_remove(char *str)
++{
++ struct uml_net *device;
++ struct net_device *dev;
++ struct uml_net_private *lp;
++ char *end;
++ int n;
++
++ n = simple_strtoul(str, &end, 0);
++ if((*end != '\0') || (end == str))
++ return(-1);
++
++ device = find_device(n);
++ if(device == NULL)
++ return(0);
++
++ dev = device->dev;
++ lp = dev->priv;
++ if(lp->fd > 0) return(-1);
++ if(lp->remove != NULL) (*lp->remove)(&lp->user);
++ unregister_netdev(dev);
++
++ list_del(&device->list);
++ kfree(device);
++ return(0);
++}
++
++static struct mc_device net_mc = {
++ .name = "eth",
++ .config = net_config,
++ .get_config = NULL,
++ .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;
++
++ if(str == NULL)
++ return(0);
++ 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(0);
++ }
++ str = end + 1;
++ }
++ if(addr[0] & 1){
++ printk(KERN_ERR
++ "Attempt to assign a broadcast ethernet address to a "
++ "device disallowed\n");
++ return(0);
++ }
++ return(1);
++}
++
++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;
++ }
++}
++
++int dev_netmask(void *d, void *m)
++{
++ struct net_device *dev = d;
++ struct in_device *ip = dev->ip_ptr;
++ struct in_ifaddr *in;
++ __u32 *mask_out = m;
++
++ if(ip == NULL)
++ return(1);
++
++ in = ip->ifa_list;
++ if(in == NULL)
++ return(1);
++
++ *mask_out = in->ifa_mask;
++ return(0);
++}
++
++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_out,
++ char **gate_addr)
++{
++ char *remain;
++
++ remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
++ if(remain != NULL){
++ printk("tap_setup_common - Extra garbage on specification : "
++ "'%s'\n", remain);
++ return(1);
++ }
++
++ return(0);
++}
++
++unsigned short eth_protocol(struct sk_buff *skb)
++{
++ return(eth_type_trans(skb, skb->dev));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/net_user.c um/arch/um/drivers/net_user.c
+--- orig/arch/um/drivers/net_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/net_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,252 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "net_user.h"
++#include "helper.h"
++#include "os.h"
++
++int tap_open_common(void *dev, char *gate_addr)
++{
++ int tap_addr[4];
++
++ if(gate_addr == NULL) return(0);
++ if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
++ &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
++ printk("Invalid tap IP address - '%s'\n", gate_addr);
++ return(-EINVAL);
++ }
++ return(0);
++}
++
++void tap_check_ips(char *gate_addr, char *eth_addr)
++{
++ int tap_addr[4];
++
++ if((gate_addr != NULL) &&
++ (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
++ &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
++ (eth_addr[0] == tap_addr[0]) &&
++ (eth_addr[1] == tap_addr[1]) &&
++ (eth_addr[2] == tap_addr[2]) &&
++ (eth_addr[3] == tap_addr[3])){
++ printk("The tap IP address and the UML eth IP address"
++ " must be different\n");
++ }
++}
++
++void read_output(int fd, char *output, int len)
++{
++ int remain, n, actual;
++ char c;
++
++ if(output == NULL){
++ output = &c;
++ len = sizeof(c);
++ }
++
++ *output = '\0';
++ n = os_read_file(fd, &remain, sizeof(remain));
++ if(n != sizeof(remain)){
++ printk("read_output - read of length failed, err = %d\n", -n);
++ return;
++ }
++
++ while(remain != 0){
++ n = (remain < len) ? remain : len;
++ actual = os_read_file(fd, output, n);
++ if(actual != n){
++ printk("read_output - read of data failed, "
++ "err = %d\n", -actual);
++ return;
++ }
++ remain -= actual;
++ }
++ return;
++}
++
++int net_read(int fd, void *buf, int len)
++{
++ int n;
++
++ n = os_read_file(fd, buf, len);
++
++ if(n == -EAGAIN)
++ return(0);
++ 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;
++
++ n = os_write_file(fd, buf, len);
++
++ if(n == -EAGAIN)
++ return(0);
++ 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;
++
++ os_close_file(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 < 0){
++ printk("change_tramp - pipe failed, err = %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);
++
++ os_close_file(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);
++}
++
++char *split_if_spec(char *str, ...)
++{
++ char **arg, *end;
++ va_list ap;
++
++ va_start(ap, str);
++ while((arg = va_arg(ap, char **)) != NULL){
++ if(*str == '\0')
++ return(NULL);
++ end = strchr(str, ',');
++ if(end != str)
++ *arg = str;
++ if(end == NULL)
++ return(NULL);
++ *end++ = '\0';
++ str = end;
++ }
++ va_end(ap);
++ return(str);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/null.c um/arch/um/drivers/null.c
+--- orig/arch/um/drivers/null.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/null.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include "chan_user.h"
++#include "os.h"
++
++static int null_chan;
++
++void *null_init(char *str, int device, struct chan_opts *opts)
++{
++ return(&null_chan);
++}
++
++int null_open(int input, int output, int primary, void *d, char **dev_out)
++{
++ *dev_out = NULL;
++ 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 = {
++ .type = "null",
++ .init = null_init,
++ .open = null_open,
++ .close = generic_close,
++ .read = null_read,
++ .write = generic_write,
++ .console_write = generic_console_write,
++ .window_size = generic_window_size,
++ .free = null_free,
++ .winch = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_kern.c um/arch/um/drivers/pcap_kern.c
+--- orig/arch/um/drivers/pcap_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/pcap_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
++ * Licensed under the GPL.
++ */
++
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "pcap_user.h"
++
++struct pcap_init {
++ char *host_if;
++ int promisc;
++ int optimize;
++ char *filter;
++};
++
++void pcap_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *pri;
++ struct pcap_data *ppri;
++ struct pcap_init *init = data;
++
++ init_etherdev(dev, 0);
++ pri = dev->priv;
++ ppri = (struct pcap_data *) pri->user;
++ *ppri = ((struct pcap_data)
++ { .host_if = init->host_if,
++ .promisc = init->promisc,
++ .optimize = init->optimize,
++ .filter = init->filter,
++ .compiled = NULL,
++ .pcap = NULL });
++}
++
++static int pcap_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(pcap_user_read(fd, (*skb)->mac.raw,
++ (*skb)->dev->mtu + ETH_HEADER_OTHER,
++ (struct pcap_data *) &lp->user));
++}
++
++static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++ return(-EPERM);
++}
++
++static struct net_kern_info pcap_kern_info = {
++ .init = pcap_init,
++ .protocol = eth_protocol,
++ .read = pcap_read,
++ .write = pcap_write,
++};
++
++int pcap_setup(char *str, char **mac_out, void *data)
++{
++ struct pcap_init *init = data;
++ char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
++ int i;
++
++ *init = ((struct pcap_init)
++ { .host_if = "eth0",
++ .promisc = 1,
++ .optimize = 0,
++ .filter = NULL });
++
++ remain = split_if_spec(str, &host_if, &init->filter,
++ &options[0], &options[1], NULL);
++ if(remain != NULL){
++ printk(KERN_ERR "pcap_setup - Extra garbage on "
++ "specification : '%s'\n", remain);
++ return(0);
++ }
++
++ if(host_if != NULL)
++ init->host_if = host_if;
++
++ for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
++ if(options[i] == NULL)
++ continue;
++ if(!strcmp(options[i], "promisc"))
++ init->promisc = 1;
++ else if(!strcmp(options[i], "nopromisc"))
++ init->promisc = 0;
++ else if(!strcmp(options[i], "optimize"))
++ init->optimize = 1;
++ else if(!strcmp(options[i], "nooptimize"))
++ init->optimize = 0;
++ else printk("pcap_setup : bad option - '%s'\n", options[i]);
++ }
++
++ return(1);
++}
++
++static struct transport pcap_transport = {
++ .list = LIST_HEAD_INIT(pcap_transport.list),
++ .name = "pcap",
++ .setup = pcap_setup,
++ .user = &pcap_user_info,
++ .kern = &pcap_kern_info,
++ .private_size = sizeof(struct pcap_data),
++ .setup_size = sizeof(struct pcap_init),
++};
++
++static int register_pcap(void)
++{
++ register_transport(&pcap_transport);
++ return(1);
++}
++
++__initcall(register_pcap);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_user.c um/arch/um/drivers/pcap_user.c
+--- orig/arch/um/drivers/pcap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/pcap_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
++ * Licensed under the GPL.
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <pcap.h>
++#include <asm/types.h>
++#include "net_user.h"
++#include "pcap_user.h"
++#include "user.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++#define PCAP_FD(p) (*(int *)(p))
++
++static void pcap_user_init(void *data, void *dev)
++{
++ struct pcap_data *pri = data;
++ pcap_t *p;
++ char errors[PCAP_ERRBUF_SIZE];
++
++ p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
++ if(p == NULL){
++ printk("pcap_user_init : pcap_open_live failed - '%s'\n",
++ errors);
++ return;
++ }
++
++ pri->dev = dev;
++ pri->pcap = p;
++}
++
++static int pcap_open(void *data)
++{
++ struct pcap_data *pri = data;
++ __u32 netmask;
++ int err;
++
++ if(pri->pcap == NULL)
++ return(-ENODEV);
++
++ if(pri->filter != NULL){
++ err = dev_netmask(pri->dev, &netmask);
++ if(err < 0){
++ printk("pcap_open : dev_netmask failed\n");
++ return(-EIO);
++ }
++
++ pri->compiled = um_kmalloc(sizeof(struct bpf_program));
++ if(pri->compiled == NULL){
++ printk("pcap_open : kmalloc failed\n");
++ return(-ENOMEM);
++ }
++
++ err = pcap_compile(pri->pcap,
++ (struct bpf_program *) pri->compiled,
++ pri->filter, pri->optimize, netmask);
++ if(err < 0){
++ printk("pcap_open : pcap_compile failed - '%s'\n",
++ pcap_geterr(pri->pcap));
++ return(-EIO);
++ }
++
++ err = pcap_setfilter(pri->pcap, pri->compiled);
++ if(err < 0){
++ printk("pcap_open : pcap_setfilter failed - '%s'\n",
++ pcap_geterr(pri->pcap));
++ return(-EIO);
++ }
++ }
++
++ return(PCAP_FD(pri->pcap));
++}
++
++static void pcap_remove(void *data)
++{
++ struct pcap_data *pri = data;
++
++ if(pri->compiled != NULL)
++ pcap_freecode(pri->compiled);
++
++ pcap_close(pri->pcap);
++}
++
++struct pcap_handler_data {
++ char *buffer;
++ int len;
++};
++
++static void handler(u_char *data, const struct pcap_pkthdr *header,
++ const u_char *packet)
++{
++ int len;
++
++ struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
++
++ len = hdata->len < header->caplen ? hdata->len : header->caplen;
++ memcpy(hdata->buffer, packet, len);
++ hdata->len = len;
++}
++
++int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
++{
++ struct pcap_handler_data hdata = ((struct pcap_handler_data)
++ { .buffer = buffer,
++ .len = len });
++ int n;
++
++ n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
++ if(n < 0){
++ printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
++ return(-EIO);
++ }
++ else if(n == 0)
++ return(0);
++ return(hdata.len);
++}
++
++struct net_user_info pcap_user_info = {
++ .init = pcap_user_init,
++ .open = pcap_open,
++ .close = NULL,
++ .remove = pcap_remove,
++ .set_mtu = NULL,
++ .add_address = NULL,
++ .delete_address = NULL,
++ .max_packet = MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_user.h um/arch/um/drivers/pcap_user.h
+--- orig/arch/um/drivers/pcap_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/pcap_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct pcap_data {
++ char *host_if;
++ int promisc;
++ int optimize;
++ char *filter;
++ void *compiled;
++ void *pcap;
++ void *dev;
++};
++
++extern struct net_user_info pcap_user_info;
++
++extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/port.h um/arch/um/drivers/port.h
+--- orig/arch/um/drivers/port.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/port.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/port_kern.c um/arch/um/drivers/port_kern.c
+--- orig/arch/um/drivers/port_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/port_kern.c 2004-01-10 06:18:49.000000000 -0500
+@@ -0,0 +1,303 @@
++/*
++ * 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 "irq_kern.h"
++#include "port.h"
++#include "init.h"
++#include "os.h"
++
++struct port_list {
++ struct list_head list;
++ int has_connection;
++ 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 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;
++
++ fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
++ if(fd < 0){
++ if(fd == -EAGAIN)
++ return;
++
++ printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
++ -fd);
++ os_close_file(conn->fd);
++ }
++
++ list_del(&conn->list);
++
++ conn->fd = fd;
++ list_add(&conn->list, &conn->port->connections);
++
++ up(&conn->port->sem);
++}
++
++static int port_accept(struct port_list *port)
++{
++ struct connection *conn;
++ int fd, socket[2], pid, ret = 0;
++
++ fd = port_connection(port->fd, socket, &pid);
++ if(fd < 0){
++ if(fd != -EAGAIN)
++ printk(KERN_ERR "port_accept : port_connection "
++ "returned %d\n", -fd);
++ goto out;
++ }
++
++ conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
++ if(conn == NULL){
++ printk(KERN_ERR "port_accept : 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 "port_accept : failed to get IRQ for "
++ "telnetd\n");
++ goto out_free;
++ }
++
++ list_add(&conn->list, &port->pending);
++ return(1);
++
++ out_free:
++ kfree(conn);
++ out_close:
++ os_close_file(fd);
++ if(pid != -1)
++ os_kill_process(pid, 1);
++ out:
++ return(ret);
++}
++
++DECLARE_MUTEX(ports_sem);
++struct list_head ports = LIST_HEAD_INIT(ports);
++
++void port_task_proc(void *unused)
++{
++ struct port_list *port;
++ struct list_head *ele;
++ unsigned long flags;
++
++ save_flags(flags);
++ list_for_each(ele, &ports){
++ port = list_entry(ele, struct port_list, list);
++ if(!port->has_connection)
++ continue;
++ reactivate_fd(port->fd, ACCEPT_IRQ);
++ while(port_accept(port)) ;
++ port->has_connection = 0;
++ }
++ restore_flags(flags);
++}
++
++struct tq_struct port_task = {
++ .routine = port_task_proc,
++ .data = NULL
++};
++
++static void port_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++ struct port_list *port = data;
++
++ port->has_connection = 1;
++ schedule_task(&port_task);
++}
++
++void *port_data(int port_num)
++{
++ struct list_head *ele;
++ struct port_list *port;
++ struct port_dev *dev = NULL;
++ int fd;
++
++ down(&ports_sem);
++ 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");
++ goto out;
++ }
++
++ 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),
++ .has_connection = 0,
++ .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");
++ goto out;
++ }
++
++ *dev = ((struct port_dev) { .port = port,
++ .helper_pid = -1,
++ .telnetd_pid = -1 });
++ goto out;
++
++ out_free:
++ kfree(port);
++ out_close:
++ os_close_file(fd);
++ out:
++ up(&ports_sem);
++ return(dev);
++}
++
++int port_wait(void *data)
++{
++ struct port_dev *dev = data;
++ struct connection *conn;
++ struct port_list *port = dev->port;
++ int fd;
++
++ 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);
++ }
++
++ fd = conn->fd;
++ dev->helper_pid = conn->helper_pid;
++ dev->telnetd_pid = conn->telnetd_pid;
++ kfree(conn);
++
++ return(fd);
++}
++
++void port_remove_dev(void *d)
++{
++ struct port_dev *dev = d;
++
++ if(dev->helper_pid != -1)
++ os_kill_process(dev->helper_pid, 0);
++ if(dev->telnetd_pid != -1)
++ os_kill_process(dev->telnetd_pid, 1);
++ dev->helper_pid = -1;
++ dev->telnetd_pid = -1;
++}
++
++void port_kern_free(void *d)
++{
++ struct port_dev *dev = d;
++
++ port_remove_dev(dev);
++ kfree(dev);
++}
++
++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_by_fd(port->fd);
++ os_close_file(port->fd);
++ }
++}
++
++__uml_exitcall(free_port);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/port_user.c um/arch/um/drivers/port_user.c
+--- orig/arch/um/drivers/port_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/port_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,213 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <termios.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netinet/in.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "chan_user.h"
++#include "port.h"
++#include "helper.h"
++#include "os.h"
++
++struct port_chan {
++ int raw;
++ struct termios tt;
++ void *kernel_data;
++ char dev[sizeof("32768\0")];
++};
++
++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') || (end == str)){
++ printk("port_init : couldn't parse port '%s'\n", str);
++ return(NULL);
++ }
++
++ kern_data = port_data(port);
++ if(kern_data == NULL)
++ return(NULL);
++
++ data = um_kmalloc(sizeof(*data));
++ if(data == NULL)
++ goto err;
++
++ *data = ((struct port_chan) { .raw = opts->raw,
++ .kernel_data = kern_data });
++ sprintf(data->dev, "%d", port);
++
++ return(data);
++ err:
++ port_kern_free(kern_data);
++ return(NULL);
++}
++
++void port_free(void *d)
++{
++ struct port_chan *data = d;
++
++ port_kern_free(data->kernel_data);
++ kfree(data);
++}
++
++int port_open(int input, int output, int primary, void *d, char **dev_out)
++{
++ 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);
++ }
++ *dev_out = data->dev;
++ return(fd);
++}
++
++void port_close(int fd, void *d)
++{
++ struct port_chan *data = d;
++
++ port_remove_dev(data->kernel_data);
++ os_close_file(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));
++}
++
++struct chan_ops port_ops = {
++ .type = "port",
++ .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;
++ }
++
++ err = os_set_fd_block(fd, 0);
++ if(err < 0)
++ 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);
++ os_close_file(data->sock_fd);
++ dup2(data->pipe_fd, 3);
++ os_shutdown_socket(3, 1, 0);
++ os_close_file(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;
++
++ new = os_accept_connection(fd);
++ if(new < 0)
++ return(new);
++
++ err = os_pipe(socket, 0, 0);
++ if(err < 0)
++ 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);
++ os_close_file(socket[0]);
++ os_shutdown_socket(socket[1], 1, 1);
++ os_close_file(socket[1]);
++ out_close:
++ os_close_file(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/pty.c um/arch/um/drivers/pty.c
+--- orig/arch/um/drivers/pty.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/pty.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <termios.h>
++#include "chan_user.h"
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "os.h"
++
++struct pty_chan {
++ void (*announce)(char *dev_name, int dev);
++ int dev;
++ int raw;
++ struct termios tt;
++ char dev_name[sizeof("/dev/pts/0123456\0")];
++};
++
++void *pty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++ struct pty_chan *data;
++
++ data = um_kmalloc(sizeof(*data));
++ if(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, char **dev_out)
++{
++ struct pty_chan *data = d;
++ char *dev;
++ int fd;
++
++ fd = get_pty();
++ if(fd < 0){
++ printk("open_pts : Failed to open pts\n");
++ return(-errno);
++ }
++ if(data->raw){
++ tcgetattr(fd, &data->tt);
++ raw(fd, 0);
++ }
++
++ dev = ptsname(fd);
++ sprintf(data->dev_name, "%s", dev);
++ *dev_out = data->dev_name;
++ if(data->announce) (*data->announce)(dev, data->dev);
++ return(fd);
++}
++
++int getmaster(char *line)
++{
++ char *pty, *bank, *cp;
++ int master, err;
++
++ pty = &line[strlen("/dev/ptyp")];
++ for (bank = "pqrs"; *bank; bank++) {
++ line[strlen("/dev/pty")] = *bank;
++ *pty = '0';
++ if (os_stat_file(line, NULL) < 0)
++ break;
++ for (cp = "0123456789abcdef"; *cp; cp++) {
++ *pty = *cp;
++ master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
++ if (master >= 0) {
++ char *tp = &line[strlen("/dev/")];
++
++ /* verify slave side is usable */
++ *tp = 't';
++ err = os_access(line, OS_ACC_RW_OK);
++ *tp = 'p';
++ if(err == 0) return(master);
++ (void) os_close_file(master);
++ }
++ }
++ }
++ return(-1);
++}
++
++int pty_open(int input, int output, int primary, void *d, char **dev_out)
++{
++ struct pty_chan *data = d;
++ int fd;
++ char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
++
++ fd = getmaster(dev);
++ if(fd < 0) return(-errno);
++
++ if(data->raw) raw(fd, 0);
++ if(data->announce) (*data->announce)(dev, data->dev);
++
++ sprintf(data->dev_name, "%s", dev);
++ *dev_out = data->dev_name;
++ 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 = {
++ .type = "pty",
++ .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 = {
++ .type = "pts",
++ .init = pty_chan_init,
++ .open = pts_open,
++ .close = generic_close,
++ .read = generic_read,
++ .write = generic_write,
++ .console_write = pty_console_write,
++ .window_size = generic_window_size,
++ .free = generic_free,
++ .winch = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slip.h um/arch/um/drivers/slip.h
+--- orig/arch/um/drivers/slip.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slip.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,39 @@
++#ifndef __UM_SLIP_H
++#define __UM_SLIP_H
++
++#define BUF_SIZE 1500
++ /* two bytes each for a (pathological) max packet of escaped chars + *
++ * terminating END char + initial END char */
++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
++
++struct slip_data {
++ void *dev;
++ char name[sizeof("slnnnnn\0")];
++ char *addr;
++ char *gate_addr;
++ int slave;
++ char ibuf[ENC_BUF_SIZE];
++ char obuf[ENC_BUF_SIZE];
++ int more; /* more data: do not read fd until ibuf has been drained */
++ int pos;
++ int esc;
++};
++
++extern struct net_user_info slip_user_info;
++
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
++extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_kern.c um/arch/um/drivers/slip_kern.c
+--- orig/arch/um/drivers/slip_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slip_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,109 @@
++#include "linux/config.h"
++#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"
++
++struct slip_init {
++ char *gate_addr;
++};
++
++void slip_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *private;
++ struct slip_data *spri;
++ struct slip_init *init = data;
++
++ private = dev->priv;
++ spri = (struct slip_data *) private->user;
++ *spri = ((struct slip_data)
++ { .name = { '\0' },
++ .addr = NULL,
++ .gate_addr = init->gate_addr,
++ .slave = -1,
++ .ibuf = { '\0' },
++ .obuf = { '\0' },
++ .pos = 0,
++ .esc = 0,
++ .dev = dev });
++
++ dev->init = NULL;
++ dev->hard_header_len = 0;
++ dev->addr_len = 4;
++ dev->type = ARPHRD_ETHER;
++ dev->tx_queue_len = 256;
++ dev->flags = IFF_NOARP;
++ printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
++}
++
++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_setup(char *str, char **mac_out, void *data)
++{
++ struct slip_init *init = data;
++
++ *init = ((struct slip_init)
++ { .gate_addr = NULL });
++
++ if(str[0] != '\0')
++ init->gate_addr = str;
++ return(1);
++}
++
++static struct transport slip_transport = {
++ .list = LIST_HEAD_INIT(slip_transport.list),
++ .name = "slip",
++ .setup = slip_setup,
++ .user = &slip_user_info,
++ .kern = &slip_kern_info,
++ .private_size = sizeof(struct slip_data),
++ .setup_size = sizeof(struct slip_init),
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_proto.h um/arch/um/drivers/slip_proto.h
+--- orig/arch/um/drivers/slip_proto.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slip_proto.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,93 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SLIP_PROTO_H__
++#define __UM_SLIP_PROTO_H__
++
++/* SLIP protocol characters. */
++#define SLIP_END 0300 /* indicates end of frame */
++#define SLIP_ESC 0333 /* indicates byte stuffing */
++#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
++#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
++
++static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
++{
++ int ret;
++
++ switch(c){
++ case SLIP_END:
++ *esc = 0;
++ ret=*pos;
++ *pos=0;
++ return(ret);
++ case SLIP_ESC:
++ *esc = 1;
++ return(0);
++ case SLIP_ESC_ESC:
++ if(*esc){
++ *esc = 0;
++ c = SLIP_ESC;
++ }
++ break;
++ case SLIP_ESC_END:
++ if(*esc){
++ *esc = 0;
++ c = SLIP_END;
++ }
++ break;
++ }
++ buf[(*pos)++] = c;
++ return(0);
++}
++
++static inline 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++ = SLIP_END;
++
++ /*
++ * For each byte in the packet, send the appropriate
++ * character sequence, according to the SLIP protocol.
++ */
++
++ while (len-- > 0) {
++ switch(c = *s++) {
++ case SLIP_END:
++ *ptr++ = SLIP_ESC;
++ *ptr++ = SLIP_ESC_END;
++ break;
++ case SLIP_ESC:
++ *ptr++ = SLIP_ESC;
++ *ptr++ = SLIP_ESC_ESC;
++ break;
++ default:
++ *ptr++ = c;
++ break;
++ }
++ }
++ *ptr++ = SLIP_END;
++ return (ptr - d);
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_user.c um/arch/um/drivers/slip_user.c
+--- orig/arch/um/drivers/slip_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slip_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,274 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <sched.h>
++#include <string.h>
++#include <sys/errno.h>
++#include <sys/termios.h>
++#include <sys/wait.h>
++#include <sys/signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "net_user.h"
++#include "slip.h"
++#include "slip_proto.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 >= 0) dup2(data->stdin, 0);
++ dup2(data->stdout, 1);
++ if(data->close_me >= 0) os_close_file(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 < 0){
++ printk("slip_tramp : pipe failed, err = %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");
++
++ os_close_file(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, err;
++
++ mfd = get_pty();
++ if(mfd < 0){
++ printk("umn : Failed to open pty, err = %d\n", -mfd);
++ return(mfd);
++ }
++ sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
++ if(sfd < 0){
++ printk("Couldn't open tty for slip line, err = %d\n", -sfd);
++ return(sfd);
++ }
++ 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 - err = %d\n", -err);
++ return(err);
++ }
++ err = os_get_ifname(pri->slave, pri->name);
++ if(err < 0){
++ printk("get_ifname failed, err = %d\n", -err);
++ return(err);
++ }
++ iter_addresses(pri->dev, open_addr, pri->name);
++ }
++ else {
++ err = os_set_slip(sfd);
++ if(err < 0){
++ printk("Failed to set slip discipline encapsulation - "
++ "err = %d\n", -err);
++ return(err);
++ }
++ }
++ 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);
++ os_close_file(fd);
++ os_close_file(pri->slave);
++ pri->slave = -1;
++}
++
++int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
++{
++ int i, n, size, start;
++
++ if(pri->more>0) {
++ i = 0;
++ while(i < pri->more) {
++ size = slip_unesc(pri->ibuf[i++],
++ pri->ibuf, &pri->pos, &pri->esc);
++ if(size){
++ memcpy(buf, pri->ibuf, size);
++ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
++ pri->more=pri->more-i;
++ return(size);
++ }
++ }
++ pri->more=0;
++ }
++
++ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
++ if(n <= 0) return(n);
++
++ start = pri->pos;
++ for(i = 0; i < n; i++){
++ size = slip_unesc(pri->ibuf[start + i],
++ pri->ibuf, &pri->pos, &pri->esc);
++ if(size){
++ memcpy(buf, pri->ibuf, size);
++ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
++ pri->more=n-(i+1);
++ return(size);
++ }
++ }
++ return(0);
++}
++
++int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
++{
++ int actual, n;
++
++ actual = slip_esc(buf, pri->obuf, len);
++ n = net_write(fd, pri->obuf, 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 < 0) 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 < 0) 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp.h um/arch/um/drivers/slirp.h
+--- orig/arch/um/drivers/slirp.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slirp.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,51 @@
++#ifndef __UM_SLIRP_H
++#define __UM_SLIRP_H
++
++#define BUF_SIZE 1500
++ /* two bytes each for a (pathological) max packet of escaped chars + *
++ * terminating END char + initial END char */
++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
++
++#define SLIRP_MAX_ARGS 100
++/*
++ * XXX this next definition is here because I don't understand why this
++ * initializer doesn't work in slirp_kern.c:
++ *
++ * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
++ *
++ * or why I can't typecast like this:
++ *
++ * argv : (char* [SLIRP_MAX_ARGS])(init->argv),
++ */
++struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
++
++struct slirp_data {
++ void *dev;
++ struct arg_list_dummy_wrapper argw;
++ int pid;
++ int slave;
++ char ibuf[ENC_BUF_SIZE];
++ char obuf[ENC_BUF_SIZE];
++ int more; /* more data: do not read fd until ibuf has been drained */
++ int pos;
++ int esc;
++};
++
++extern struct net_user_info slirp_user_info;
++
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
++extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp_kern.c um/arch/um/drivers/slirp_kern.c
+--- orig/arch/um/drivers/slirp_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slirp_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,132 @@
++#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 "slirp.h"
++
++struct slirp_init {
++ struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
++};
++
++void slirp_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *private;
++ struct slirp_data *spri;
++ struct slirp_init *init = data;
++ int i;
++
++ private = dev->priv;
++ spri = (struct slirp_data *) private->user;
++ *spri = ((struct slirp_data)
++ { .argw = init->argw,
++ .pid = -1,
++ .slave = -1,
++ .ibuf = { '\0' },
++ .obuf = { '\0' },
++ .pos = 0,
++ .esc = 0,
++ .dev = dev });
++
++ dev->init = NULL;
++ dev->hard_header_len = 0;
++ dev->addr_len = 4;
++ dev->type = ARPHRD_ETHER;
++ dev->tx_queue_len = 256;
++ dev->flags = IFF_NOARP;
++ printk("SLIRP backend - command line:");
++ for(i=0;spri->argw.argv[i]!=NULL;i++) {
++ printk(" '%s'",spri->argw.argv[i]);
++ }
++ printk("\n");
++}
++
++static unsigned short slirp_protocol(struct sk_buff *skbuff)
++{
++ return(htons(ETH_P_IP));
++}
++
++static int slirp_read(int fd, struct sk_buff **skb,
++ struct uml_net_private *lp)
++{
++ return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
++ (struct slirp_data *) &lp->user));
++}
++
++static int slirp_write(int fd, struct sk_buff **skb,
++ struct uml_net_private *lp)
++{
++ return(slirp_user_write(fd, (*skb)->data, (*skb)->len,
++ (struct slirp_data *) &lp->user));
++}
++
++struct net_kern_info slirp_kern_info = {
++ .init = slirp_init,
++ .protocol = slirp_protocol,
++ .read = slirp_read,
++ .write = slirp_write,
++};
++
++static int slirp_setup(char *str, char **mac_out, void *data)
++{
++ struct slirp_init *init = data;
++ int i=0;
++
++ *init = ((struct slirp_init)
++ { argw : { { "slirp", NULL } } });
++
++ str = split_if_spec(str, mac_out, NULL);
++
++ if(str == NULL) { /* no command line given after MAC addr */
++ return(1);
++ }
++
++ do {
++ if(i>=SLIRP_MAX_ARGS-1) {
++ printk("slirp_setup: truncating slirp arguments\n");
++ break;
++ }
++ init->argw.argv[i++] = str;
++ while(*str && *str!=',') {
++ if(*str=='_') *str=' ';
++ str++;
++ }
++ if(*str!=',')
++ break;
++ *str++='\0';
++ } while(1);
++ init->argw.argv[i]=NULL;
++ return(1);
++}
++
++static struct transport slirp_transport = {
++ .list = LIST_HEAD_INIT(slirp_transport.list),
++ .name = "slirp",
++ .setup = slirp_setup,
++ .user = &slirp_user_info,
++ .kern = &slirp_kern_info,
++ .private_size = sizeof(struct slirp_data),
++ .setup_size = sizeof(struct slirp_init),
++};
++
++static int register_slirp(void)
++{
++ register_transport(&slirp_transport);
++ return(1);
++}
++
++__initcall(register_slirp);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp_user.c um/arch/um/drivers/slirp_user.c
+--- orig/arch/um/drivers/slirp_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/slirp_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,201 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <sched.h>
++#include <string.h>
++#include <sys/errno.h>
++#include <sys/wait.h>
++#include <sys/signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "net_user.h"
++#include "slirp.h"
++#include "slip_proto.h"
++#include "helper.h"
++#include "os.h"
++
++void slirp_user_init(void *data, void *dev)
++{
++ struct slirp_data *pri = data;
++
++ pri->dev = dev;
++}
++
++struct slirp_pre_exec_data {
++ int stdin;
++ int stdout;
++};
++
++static void slirp_pre_exec(void *arg)
++{
++ struct slirp_pre_exec_data *data = arg;
++
++ if(data->stdin != -1) dup2(data->stdin, 0);
++ if(data->stdout != -1) dup2(data->stdout, 1);
++}
++
++static int slirp_tramp(char **argv, int fd)
++{
++ struct slirp_pre_exec_data pe_data;
++ int pid;
++
++ pe_data.stdin = fd;
++ pe_data.stdout = fd;
++ pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
++
++ return(pid);
++}
++
++/* XXX This is just a trivial wrapper around os_pipe */
++static int slirp_datachan(int *mfd, int *sfd)
++{
++ int fds[2], err;
++
++ err = os_pipe(fds, 1, 1);
++ if(err < 0){
++ printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
++ return(err);
++ }
++
++ *mfd = fds[0];
++ *sfd = fds[1];
++ return(0);
++}
++
++static int slirp_open(void *data)
++{
++ struct slirp_data *pri = data;
++ int sfd, mfd, pid, err;
++
++ err = slirp_datachan(&mfd, &sfd);
++ if(err)
++ return(err);
++
++ pid = slirp_tramp(pri->argw.argv, sfd);
++
++ if(pid < 0){
++ printk("slirp_tramp failed - errno = %d\n", -pid);
++ os_close_file(sfd);
++ os_close_file(mfd);
++ return(pid);
++ }
++
++ pri->slave = sfd;
++ pri->pos = 0;
++ pri->esc = 0;
++
++ pri->pid = pid;
++
++ return(mfd);
++}
++
++static void slirp_close(int fd, void *data)
++{
++ struct slirp_data *pri = data;
++ int status,err;
++
++ os_close_file(fd);
++ os_close_file(pri->slave);
++
++ pri->slave = -1;
++
++ if(pri->pid<1) {
++ printk("slirp_close: no child process to shut down\n");
++ return;
++ }
++
++#if 0
++ if(kill(pri->pid, SIGHUP)<0) {
++ printk("slirp_close: sending hangup to %d failed (%d)\n",
++ pri->pid, errno);
++ }
++#endif
++
++ err = waitpid(pri->pid, &status, WNOHANG);
++ if(err<0) {
++ printk("slirp_close: waitpid returned %d\n", errno);
++ return;
++ }
++
++ if(err==0) {
++ printk("slirp_close: process %d has not exited\n");
++ return;
++ }
++
++ pri->pid = -1;
++}
++
++int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
++{
++ int i, n, size, start;
++
++ if(pri->more>0) {
++ i = 0;
++ while(i < pri->more) {
++ size = slip_unesc(pri->ibuf[i++],
++ pri->ibuf,&pri->pos,&pri->esc);
++ if(size){
++ memcpy(buf, pri->ibuf, size);
++ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
++ pri->more=pri->more-i;
++ return(size);
++ }
++ }
++ pri->more=0;
++ }
++
++ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
++ if(n <= 0) return(n);
++
++ start = pri->pos;
++ for(i = 0; i < n; i++){
++ size = slip_unesc(pri->ibuf[start + i],
++ pri->ibuf,&pri->pos,&pri->esc);
++ if(size){
++ memcpy(buf, pri->ibuf, size);
++ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
++ pri->more=n-(i+1);
++ return(size);
++ }
++ }
++ return(0);
++}
++
++int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
++{
++ int actual, n;
++
++ actual = slip_esc(buf, pri->obuf, len);
++ n = net_write(fd, pri->obuf, actual);
++ if(n < 0) return(n);
++ else return(len);
++}
++
++static int slirp_set_mtu(int mtu, void *data)
++{
++ return(mtu);
++}
++
++struct net_user_info slirp_user_info = {
++ .init = slirp_user_init,
++ .open = slirp_open,
++ .close = slirp_close,
++ .remove = NULL,
++ .set_mtu = slirp_set_mtu,
++ .add_address = NULL,
++ .delete_address = NULL,
++ .max_packet = BUF_SIZE
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/ssl.c um/arch/um/drivers/ssl.c
+--- orig/arch/um/drivers/ssl.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/ssl.c 2004-01-10 06:20:17.000000000 -0500
+@@ -0,0 +1,300 @@
++/*
++ * 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 "linux/console.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 "mconsole_kern.h"
++#include "2_5compat.h"
++
++static int ssl_version = 1;
++
++/* Referenced only by tty_driver below - presumably it's locked correctly
++ * by the tty driver.
++ */
++static int ssl_refcount = 0;
++
++static struct tty_driver ssl_driver;
++
++#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,
++ .in_kernel = 1,
++};
++
++static int ssl_config(char *str);
++static int ssl_get_config(char *dev, char *str, int size, char **error_out);
++static int ssl_remove(char *str);
++
++static struct line_driver driver = {
++ .name = "UML serial line",
++ .devfs_name = "tts/%d",
++ .major = TTY_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",
++ .mc = {
++ .name = "ssl",
++ .config = ssl_config,
++ .get_config = ssl_get_config,
++ .remove = ssl_remove,
++ },
++};
++
++/* The array is initialized by line_init, which is an initcall. The
++ * individual elements are protected by individual semaphores.
++ */
++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);
++
++static int ssl_config(char *str)
++{
++ return(line_config(serial_lines,
++ sizeof(serial_lines)/sizeof(serial_lines[0]), str));
++}
++
++static int ssl_get_config(char *dev, char *str, int size, char **error_out)
++{
++ return(line_get_config(dev, serial_lines,
++ sizeof(serial_lines)/sizeof(serial_lines[0]),
++ str, size, error_out));
++}
++
++static int ssl_remove(char *str)
++{
++ return(line_remove(serial_lines,
++ sizeof(serial_lines)/sizeof(serial_lines[0]), str));
++}
++
++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, from_user, buf, count));
++}
++
++static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
++{
++ line_write(serial_lines, tty, 0, &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:
++ case TCSBRK:
++ case TCSBRKP:
++ case TIOCMSET:
++ 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 struct tty_driver ssl_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
++};
++
++/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
++ * by being an initcall and exitcall, respectively.
++ */
++static int ssl_init_done = 0;
++
++static void ssl_console_write(struct console *c, const char *string,
++ unsigned len)
++{
++ struct line *line = &serial_lines[c->index];
++ if(ssl_init_done)
++ down(&line->sem);
++ console_write_chan(&line->chan_list, string, len);
++ if(ssl_init_done)
++ up(&line->sem);
++}
++
++static kdev_t ssl_console_device(struct console *c)
++{
++ return mk_kdev(TTY_MAJOR, c->index);
++}
++
++static int ssl_console_setup(struct console *co, char *options)
++{
++ return(0);
++}
++
++static struct console ssl_cons = {
++ name: "ttyS",
++ write: ssl_console_write,
++ device: ssl_console_device,
++ setup: ssl_console_setup,
++ flags: CON_PRINTBUFFER,
++ index: -1,
++};
++
++int ssl_init(void)
++{
++ char *new_title;
++
++ printk(KERN_INFO "Initializing software serial port version %d\n",
++ ssl_version);
++
++ 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;
++
++ register_console(&ssl_cons);
++ ssl_init_done = 1;
++ return(0);
++}
++
++__initcall(ssl_init);
++
++static int ssl_chan_setup(char *str)
++{
++ return(line_setup(serial_lines,
++ sizeof(serial_lines)/sizeof(serial_lines[0]),
++ str, 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/ssl.h um/arch/um/drivers/ssl.h
+--- orig/arch/um/drivers/ssl.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/ssl.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/stdio_console.c um/arch/um/drivers/stdio_console.c
+--- orig/arch/um/drivers/stdio_console.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/stdio_console.c 2003-11-07 03:03:03.000000000 -0500
+@@ -0,0 +1,258 @@
++/*
++ * 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 "mconsole_kern.h"
++#include "init.h"
++#include "2_5compat.h"
++
++#define MAX_TTYS (8)
++
++/* Referenced only by tty_driver below - presumably it's locked correctly
++ * by the tty driver.
++ */
++
++static struct tty_driver console_driver;
++
++static int console_refcount = 0;
++
++static struct chan_ops init_console_ops = {
++ .type = "you shouldn't see this",
++ .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,
++ .in_kernel = 1,
++};
++
++static int con_config(char *str);
++static int con_get_config(char *dev, char *str, int size, char **error_out);
++static int con_remove(char *str);
++
++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",
++ .mc = {
++ .name = "con",
++ .config = con_config,
++ .get_config = con_get_config,
++ .remove = con_remove,
++ },
++};
++
++static struct lines console_lines = LINES_INIT(MAX_TTYS);
++
++/* The array is initialized by line_init, which is an initcall. The
++ * individual elements are protected by individual semaphores.
++ */
++struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
++ [ 1 ... MAX_TTYS - 1 ] =
++ LINE_INIT(CONFIG_CON_CHAN, &driver) };
++
++static int con_config(char *str)
++{
++ return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
++}
++
++static int con_get_config(char *dev, char *str, int size, char **error_out)
++{
++ return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
++ size, error_out));
++}
++
++static int con_remove(char *str)
++{
++ return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
++}
++
++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, from_user, 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");
++
++ 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)
++{
++ struct line *line = &vts[console->index];
++
++ if(con_init_done)
++ down(&line->sem);
++ console_write_chan(&line->chan_list, string, len);
++ if(con_init_done)
++ up(&line->sem);
++}
++
++static struct tty_driver console_driver = {
++ .refcount = &console_refcount,
++ .open = con_open,
++ .close = con_close,
++ .write = con_write,
++ .chars_in_buffer = chars_in_buffer,
++ .set_termios = set_termios
++};
++
++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 = {
++ name: "tty",
++ write: console_write,
++ device: console_device,
++ setup: console_setup,
++ flags: CON_PRINTBUFFER,
++ index: -1,
++};
++
++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)
++{
++ return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
++}
++
++__setup("con", console_chan_setup);
++__channel_help(console_chan_setup, "con");
++
++static void console_exit(void)
++{
++ if(!con_init_done) return;
++ 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/stdio_console.h um/arch/um/drivers/stdio_console.h
+--- orig/arch/um/drivers/stdio_console.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/stdio_console.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/tty.c um/arch/um/drivers/tty.c
+--- orig/arch/um/drivers/tty.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/tty.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <termios.h>
++#include <errno.h>
++#include <unistd.h>
++#include "chan_user.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++struct tty_chan {
++ char *dev;
++ int raw;
++ struct termios tt;
++};
++
++void *tty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++ struct tty_chan *data;
++
++ if(*str != ':'){
++ printk("tty_init : channel type 'tty' must specify "
++ "a device\n");
++ return(NULL);
++ }
++ str++;
++
++ data = um_kmalloc(sizeof(*data));
++ if(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, char **dev_out)
++{
++ 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);
++ }
++
++ *dev_out = data->dev;
++ 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 = {
++ .type = "tty",
++ .init = tty_chan_init,
++ .open = tty_open,
++ .close = generic_close,
++ .read = generic_read,
++ .write = generic_write,
++ .console_write = tty_console_write,
++ .window_size = generic_window_size,
++ .free = generic_free,
++ .winch = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/ubd_kern.c um/arch/um/drivers/ubd_kern.c
+--- orig/arch/um/drivers/ubd_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/ubd_kern.c 2004-01-21 01:28:43.000000000 -0500
+@@ -0,0 +1,1396 @@
++/*
++ * 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 "linux/spinlock.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 "irq_kern.h"
++#include "ubd_user.h"
++#include "2_5compat.h"
++#include "os.h"
++#include "mem.h"
++#include "mem_kern.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);
++static int ubd_revalidate1(kdev_t rdev);
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << UBD_SHIFT)
++
++/* Changed in early boot */
++static int ubd_do_mmap = 0;
++#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by ubd_lock */
++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,
++};
++
++/* Protected by ubd_lock, except in prepare_request and ubd_ioctl because
++ * the block layer should ensure that the device is idle before closing it.
++ */
++static struct hd_struct ubd_part[MAX_MINOR] =
++ { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *ubd_queue;
++
++/* Protected by ubd_lock */
++static int fake_major = MAJOR_NR;
++
++static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
++
++#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, \
++ .cl = 1 })
++#else
++#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
++ .cl = 1 })
++#endif
++
++/* Not protected - changed only in ubd_setup_common and then only to
++ * to enable O_SYNC.
++ */
++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 count;
++ int fd;
++ __u64 size;
++ struct openflags boot_openflags;
++ struct openflags openflags;
++ devfs_handle_t devfs;
++ int no_cow;
++ struct cow cow;
++
++ int map_writes;
++ int map_reads;
++ int nomap_writes;
++ int nomap_reads;
++ int write_maps;
++};
++
++#define DEFAULT_COW { \
++ .file = NULL, \
++ .fd = -1, \
++ .bitmap = NULL, \
++ .bitmap_offset = 0, \
++ .data_offset = 0, \
++}
++
++#define DEFAULT_UBD { \
++ .file = NULL, \
++ .count = 0, \
++ .fd = -1, \
++ .size = -1, \
++ .boot_openflags = OPEN_FLAGS, \
++ .openflags = OPEN_FLAGS, \
++ .devfs = NULL, \
++ .no_cow = 0, \
++ .cow = DEFAULT_COW, \
++ .map_writes = 0, \
++ .map_reads = 0, \
++ .nomap_writes = 0, \
++ .nomap_reads = 0, \
++ .write_maps = 0, \
++}
++
++struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
++
++static int ubd0_init(void)
++{
++ struct ubd *dev = &ubd_dev[0];
++
++ if(dev->file == NULL)
++ dev->file = "root_fs";
++ return(0);
++}
++
++__initcall(ubd0_init);
++
++/* Only changed by fake_ide_setup which is a setup */
++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;
++
++ /* Without locking this could race if a UML was booted with no
++ * disks and then two mconsole requests which add disks came in
++ * at the same time.
++ */
++ spin_lock(&ubd_lock);
++ if(proc_ide_root == NULL) make_proc_ide();
++ spin_unlock(&ubd_lock);
++
++ dir = proc_mkdir(dev_name, proc_ide);
++ if(!dir) return;
++
++ 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 parse_unit(char **ptr)
++{
++ char *str = *ptr, *end;
++ int n = -1;
++
++ if(isdigit(*str)) {
++ n = simple_strtoul(str, &end, 0);
++ if(end == str)
++ return(-1);
++ *ptr = end;
++ }
++ else if (('a' <= *str) && (*str <= 'h')) {
++ n = *str - 'a';
++ str++;
++ *ptr = str;
++ }
++ return(n);
++}
++
++static int ubd_setup_common(char *str, int *index_out)
++{
++ struct openflags flags = global_openflags;
++ struct ubd *dev;
++ char *backing_file;
++ int n, err;
++
++ if(index_out) *index_out = -1;
++ n = *str;
++ if(n == '='){
++ char *end;
++ int major;
++
++ str++;
++ if(!strcmp(str, "mmap")){
++ CHOOSE_MODE(printk("mmap not supported by the ubd "
++ "driver in tt mode\n"),
++ ubd_do_mmap = 1);
++ return(0);
++ }
++
++ if(!strcmp(str, "sync")){
++ global_openflags.s = 1;
++ return(0);
++ }
++ major = simple_strtoul(str, &end, 0);
++ if((*end != '\0') || (end == str)){
++ printk(KERN_ERR
++ "ubd_setup : didn't parse major number\n");
++ return(1);
++ }
++
++ err = 1;
++ spin_lock(&ubd_lock);
++ if(fake_major != MAJOR_NR){
++ printk(KERN_ERR "Can't assign a fake major twice\n");
++ goto out1;
++ }
++
++ fake_gendisk.major = major;
++ fake_major = major;
++
++ printk(KERN_INFO "Setting extra ubd major number to %d\n",
++ major);
++ err = 0;
++ out1:
++ spin_unlock(&ubd_lock);
++ return(err);
++ }
++
++ n = parse_unit(&str);
++ if(n < 0){
++ printk(KERN_ERR "ubd_setup : couldn't parse unit number "
++ "'%s'\n", str);
++ return(1);
++ }
++
++ if(n >= MAX_DEV){
++ printk(KERN_ERR "ubd_setup : index %d out of range "
++ "(%d devices)\n", n, MAX_DEV);
++ return(1);
++ }
++
++ err = 1;
++ spin_lock(&ubd_lock);
++
++ dev = &ubd_dev[n];
++ if(dev->file != NULL){
++ printk(KERN_ERR "ubd_setup : device already configured\n");
++ goto out2;
++ }
++
++ if(index_out) *index_out = n;
++
++ if(*str == 'r'){
++ flags.w = 0;
++ str++;
++ }
++ if(*str == 's'){
++ flags.s = 1;
++ str++;
++ }
++ if(*str == 'd'){
++ dev->no_cow = 1;
++ str++;
++ }
++
++ if(*str++ != '='){
++ printk(KERN_ERR "ubd_setup : Expected '='\n");
++ goto out2;
++ }
++
++ err = 0;
++ backing_file = strchr(str, ',');
++ if(backing_file){
++ if(dev->no_cow)
++ printk(KERN_ERR "Can't specify both 'd' and a "
++ "cow file\n");
++ else {
++ *backing_file = '\0';
++ backing_file++;
++ }
++ }
++ dev->file = str;
++ dev->cow.file = backing_file;
++ dev->boot_openflags = flags;
++ out2:
++ spin_unlock(&ubd_lock);
++ return(err);
++}
++
++static int ubd_setup(char *str)
++{
++ ubd_setup_common(str, NULL);
++ return(1);
++}
++
++__setup("ubd", ubd_setup);
++__uml_help(ubd_setup,
++"ubd<n>=<filename>\n"
++" This is used to associate a device with a file in the underlying\n"
++" filesystem. Usually, there is a filesystem in the file, but \n"
++" that's not required. Swap devices containing swap files can be\n"
++" specified like this. Also, a file which doesn't contain a\n"
++" filesystem can have its contents read in the virtual \n"
++" machine by running dd on the device. n must be in the range\n"
++" 0 to 7. Appending an 'r' to the number will cause that device\n"
++" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
++" an 's' (has to be _after_ 'r', if there is one) will cause data\n"
++" to be written to disk on the host immediately.\n\n"
++);
++
++static int fakehd(char *str)
++{
++ printk(KERN_INFO
++ "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
++ ubd_gendisk.major_name = "hd";
++ return(1);
++}
++
++__setup("fakehd", fakehd);
++__uml_help(fakehd,
++"fakehd\n"
++" Change the ubd device name to \"hd\".\n\n"
++);
++
++static void do_ubd_request(request_queue_t * q);
++
++/* Only changed by ubd_init, which is an initcall. */
++int thread_fd = -1;
++
++/* Changed by ubd_handler, which is serialized because interrupts only
++ * happen on CPU 0.
++ */
++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, err;
++
++ 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, "
++ "err = %d\n", os_getpid(), -n);
++ spin_lock(&io_request_lock);
++ end_request(0);
++ spin_unlock(&io_request_lock);
++ return;
++ }
++
++ if((req.op != UBD_MMAP) &&
++ ((req.offset != ((__u64) (CURRENT->sector)) << 9) ||
++ (req.length != (CURRENT->current_nr_sectors) << 9)))
++ panic("I/O op mismatch");
++
++ if(req.map_fd != -1){
++ err = physmem_subst_mapping(req.buffer, req.map_fd,
++ req.map_offset, 1);
++ if(err)
++ printk("ubd_handler - physmem_subst_mapping failed, "
++ "err = %d\n", -err);
++ }
++
++ spin_lock(&io_request_lock);
++ ubd_finish(req.error);
++ reactivate_fd(thread_fd, UBD_IRQ);
++ do_ubd_request(ubd_queue);
++ spin_unlock(&io_request_lock);
++}
++
++static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
++{
++ ubd_handler();
++}
++
++/* Only changed by ubd_init, which is an initcall. */
++static int io_pid = -1;
++
++void kill_io_thread(void)
++{
++ if(io_pid != -1)
++ os_kill_process(io_pid, 1);
++}
++
++__uml_exitcall(kill_io_thread);
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t ubd_dir_handle;
++
++static int ubd_add(int n)
++{
++ struct ubd *dev = &ubd_dev[n];
++ char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
++ int err = -EISDIR;
++
++ if(dev->file == NULL)
++ goto out;
++
++ err = ubd_revalidate1(MKDEV(MAJOR_NR, n << UBD_SHIFT));
++ if(err)
++ goto out;
++
++ if(dev->cow.file == NULL)
++ blk_sizes[n] = UBD_MMAP_BLOCK_SIZE;
++
++ sprintf(name, "%d", n);
++ dev->devfs = 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 0 /* 2.5 ... */
++ sprintf(disk->disk_name, "ubd%c", 'a' + unit);
++#endif
++
++ sprintf(dev_name, "%s%c", ubd_gendisk.major_name,
++ n + 'a');
++
++ make_ide_entries(dev_name);
++ return(0);
++
++ out:
++ return(err);
++}
++
++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);
++
++ spin_lock(&ubd_lock);
++ err = ubd_add(n);
++ if(err)
++ ubd_dev[n].file = NULL;
++ spin_unlock(&ubd_lock);
++
++ return(err);
++}
++
++static int ubd_get_config(char *name, char *str, int size, char **error_out)
++{
++ struct ubd *dev;
++ char *end;
++ int n, len = 0;
++
++ n = simple_strtoul(name, &end, 0);
++ if((*end != '\0') || (end == name)){
++ *error_out = "ubd_get_config : didn't parse device number";
++ return(-1);
++ }
++
++ if((n >= MAX_DEV) || (n < 0)){
++ *error_out = "ubd_get_config : device number out of range";
++ return(-1);
++ }
++
++ dev = &ubd_dev[n];
++ spin_lock(&ubd_lock);
++
++ if(dev->file == NULL){
++ CONFIG_CHUNK(str, size, len, "", 1);
++ goto out;
++ }
++
++ CONFIG_CHUNK(str, size, len, dev->file, 0);
++
++ if(dev->cow.file != NULL){
++ CONFIG_CHUNK(str, size, len, ",", 0);
++ CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
++ }
++ else CONFIG_CHUNK(str, size, len, "", 1);
++
++ out:
++ spin_unlock(&ubd_lock);
++ return(len);
++}
++
++static int ubd_remove(char *str)
++{
++ struct ubd *dev;
++ int n, err = -ENODEV;
++
++ if(isdigit(*str)){
++ char *end;
++ n = simple_strtoul(str, &end, 0);
++ if ((*end != '\0') || (end == str))
++ return(err);
++ }
++ else if (('a' <= *str) && (*str <= 'h'))
++ n = *str - 'a';
++ else
++ return(err); /* it should be a number 0-7/a-h */
++
++ if((n < 0) || (n >= MAX_DEV))
++ return(err);
++
++ dev = &ubd_dev[n];
++
++ spin_lock(&ubd_lock);
++ err = 0;
++ if(dev->file == NULL)
++ goto out;
++ err = -1;
++ if(dev->count > 0)
++ goto out;
++ if(dev->devfs != NULL)
++ devfs_unregister(dev->devfs);
++
++ *dev = ((struct ubd) DEFAULT_UBD);
++ err = 0;
++ out:
++ spin_unlock(&ubd_lock);
++ return(err);
++}
++
++static struct mc_device ubd_mc = {
++ .name = "ubd",
++ .config = ubd_config,
++ .get_config = ubd_get_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;
++ }
++ 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);
++
++ ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++ blk_init_queue(ubd_queue, DEVICE_REQUEST);
++ INIT_ELV(ubd_queue, &ubd_queue->elevator);
++
++ add_gendisk(&ubd_gendisk);
++ if (fake_major != MAJOR_NR){
++ /* major number 0 is used to auto select */
++ err = devfs_register_blkdev(fake_major, "fake", &ubd_blops);
++ if(fake_major == 0){
++ /* auto device number case */
++ fake_major = err;
++ if(err == 0)
++ return(-ENODEV);
++ }
++ else if (err){
++ /* not auto so normal error */
++ printk(KERN_ERR "ubd: error %d getting major %d\n",
++ -err, fake_major);
++ return(-ENODEV);
++ }
++
++ blk_dev[fake_major].queue = ubd_get_queue;
++ read_ahead[fake_major] = 8; /* 8 sector (4kB) read-ahead */
++ blksize_size[fake_major] = blk_sizes;
++ blk_size[fake_major] = sizes;
++ INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
++ add_gendisk(&fake_gendisk);
++ }
++
++ for(i=0;i<MAX_DEV;i++)
++ ubd_add(i);
++
++ if(global_openflags.s){
++ printk(KERN_INFO "ubd : Synchronous mode\n");
++ return(0);
++ }
++ stack = alloc_stack(0, 0);
++ io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
++ &thread_fd);
++ if(io_pid < 0){
++ io_pid = -1;
++ printk(KERN_ERR
++ "ubd : Failed to start I/O thread (errno = %d) - "
++ "falling back to synchronous I/O\n", -io_pid);
++ return(0);
++ }
++ err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
++ SA_INTERRUPT, "ubd", ubd_dev);
++ if(err != 0)
++ printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
++ return(err);
++}
++
++__initcall(ubd_init);
++
++static void ubd_close(struct ubd *dev)
++{
++ if(ubd_do_mmap)
++ physmem_forget_descriptor(dev->fd);
++ os_close_file(dev->fd);
++ if(dev->cow.file != NULL)
++ return;
++
++ if(ubd_do_mmap)
++ physmem_forget_descriptor(dev->cow.fd);
++ os_close_file(dev->cow.fd);
++ vfree(dev->cow.bitmap);
++ dev->cow.bitmap = NULL;
++}
++
++static int ubd_open_dev(struct ubd *dev)
++{
++ struct openflags flags;
++ char **back_ptr;
++ int err, create_cow, *create_ptr;
++
++ dev->openflags = dev->boot_openflags;
++ create_cow = 0;
++ create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
++ back_ptr = dev->no_cow ? NULL : &dev->cow.file;
++ dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
++ &dev->cow.bitmap_offset, &dev->cow.bitmap_len,
++ &dev->cow.data_offset, create_ptr);
++
++ if((dev->fd == -ENOENT) && create_cow){
++ dev->fd = create_cow_file(dev->file, dev->cow.file,
++ dev->openflags, 1 << 9, PAGE_SIZE,
++ &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){
++ printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++ 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 < 0)
++ 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:
++ os_close_file(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 = 0;
++
++ n = DEVICE_NR(inode->i_rdev);
++ dev = &ubd_dev[n];
++ if(n >= MAX_DEV)
++ return -ENODEV;
++
++ spin_lock(&ubd_lock);
++ offset = n << UBD_SHIFT;
++
++ if(dev->count == 0){
++ err = ubd_open_dev(dev);
++ if(err){
++ printk(KERN_ERR "ubd%d: Can't open \"%s\": "
++ "errno = %d\n", n, dev->file, -err);
++ goto out;
++ }
++ err = ubd_file_size(dev, &dev->size);
++ if(err < 0)
++ goto out;
++ 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);
++ err = -EROFS;
++ }
++ out:
++ spin_unlock(&ubd_lock);
++ return(err);
++}
++
++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;
++
++ spin_lock(&ubd_lock);
++ if(--ubd_dev[n].count == 0)
++ ubd_close(&ubd_dev[n]);
++ spin_unlock(&ubd_lock);
++
++ return(0);
++}
++
++static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
++ __u64 *cow_offset, unsigned long *bitmap,
++ __u64 bitmap_offset, unsigned long *bitmap_words,
++ __u64 bitmap_len)
++{
++ __u64 sector = io_offset >> 9;
++ int i, update_bitmap = 0;
++
++ for(i = 0; i < length >> 9; i++){
++ if(cow_mask != NULL)
++ ubd_set_bit(i, (unsigned char *) cow_mask);
++ if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
++ continue;
++
++ update_bitmap = 1;
++ ubd_set_bit(sector + i, (unsigned char *) bitmap);
++ }
++
++ if(!update_bitmap)
++ return;
++
++ *cow_offset = sector / (sizeof(unsigned long) * 8);
++
++ /* This takes care of the case where we're exactly at the end of the
++ * device, and *cow_offset + 1 is off the end. So, just back it up
++ * by one word. Thanks to Lynn Kerby for the fix and James McMechan
++ * for the original diagnosis.
++ */
++ if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
++ sizeof(unsigned long) - 1))
++ (*cow_offset)--;
++
++ bitmap_words[0] = bitmap[*cow_offset];
++ bitmap_words[1] = bitmap[*cow_offset + 1];
++
++ *cow_offset *= sizeof(unsigned long);
++ *cow_offset += bitmap_offset;
++}
++
++static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
++ __u64 bitmap_offset, __u64 bitmap_len)
++{
++ __u64 sector = req->offset >> 9;
++ int i;
++
++ 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 *) bitmap)){
++ ubd_set_bit(i, (unsigned char *)
++ &req->sector_mask);
++ }
++ }
++ }
++ else cowify_bitmap(req->offset, req->length, &req->sector_mask,
++ &req->cow_offset, bitmap, bitmap_offset,
++ req->bitmap_words, bitmap_len);
++}
++
++static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
++{
++ __u64 sector;
++ unsigned char *bitmap;
++ int bit, i;
++
++ /* mmap must have been requested on the command line */
++ if(!ubd_do_mmap)
++ return(-1);
++
++ /* The buffer must be page aligned */
++ if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
++ return(-1);
++
++ /* The request must be a page long */
++ if((req->current_nr_sectors << 9) != PAGE_SIZE)
++ return(-1);
++
++ if(dev->cow.file == NULL)
++ return(dev->fd);
++
++ sector = offset >> 9;
++ bitmap = (unsigned char *) dev->cow.bitmap;
++ bit = ubd_test_bit(sector, bitmap);
++
++ for(i = 1; i < req->current_nr_sectors; i++){
++ if(ubd_test_bit(sector + i, bitmap) != bit)
++ return(-1);
++ }
++
++ if(bit || (req->cmd == WRITE))
++ offset += dev->cow.data_offset;
++
++ /* The data on disk must be page aligned */
++ if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
++ return(-1);
++
++ return(bit ? dev->fd : dev->cow.fd);
++}
++
++static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
++ struct request *req,
++ struct io_thread_req *io_req)
++{
++ int err;
++
++ if(req->cmd == WRITE){
++ /* Writes are almost no-ops since the new data is already in the
++ * host page cache
++ */
++ dev->map_writes++;
++ if(dev->cow.file != NULL)
++ cowify_bitmap(io_req->offset, io_req->length,
++ &io_req->sector_mask, &io_req->cow_offset,
++ dev->cow.bitmap, dev->cow.bitmap_offset,
++ io_req->bitmap_words,
++ dev->cow.bitmap_len);
++ }
++ else {
++ int w;
++
++ if((dev->cow.file != NULL) && (fd == dev->cow.fd))
++ w = 0;
++ else w = dev->openflags.w;
++
++ if((dev->cow.file != NULL) && (fd == dev->fd))
++ offset += dev->cow.data_offset;
++
++ err = physmem_subst_mapping(req->buffer, fd, offset, w);
++ if(err){
++ printk("physmem_subst_mapping failed, err = %d\n",
++ -err);
++ return(1);
++ }
++ dev->map_reads++;
++ }
++ io_req->op = UBD_MMAP;
++ io_req->buffer = req->buffer;
++ return(0);
++}
++
++static int prepare_request(struct request *req, struct io_thread_req *io_req)
++{
++ struct ubd *dev;
++ __u64 offset;
++ int minor, n, len, fd;
++
++ if(req->rq_status == RQ_INACTIVE) return(1);
++
++ minor = MINOR(req->rq_dev);
++ n = minor >> UBD_SHIFT;
++ dev = &ubd_dev[n];
++
++ 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;
++ offset = ((__u64) req->sector) << 9;
++ len = req->current_nr_sectors << 9;
++
++ io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
++ io_req->fds[1] = dev->fd;
++ io_req->map_fd = -1;
++ io_req->cow_offset = -1;
++ io_req->offset = offset;
++ io_req->length = len;
++ io_req->error = 0;
++ io_req->sector_mask = 0;
++
++ fd = mmap_fd(req, dev, io_req->offset);
++ if(fd > 0){
++ /* If mmapping is otherwise OK, but the first access to the
++ * page is a write, then it's not mapped in yet. So we have
++ * to write the data to disk first, then we can map the disk
++ * page in and continue normally from there.
++ */
++ if((req->cmd == WRITE) && !is_remapped(req->buffer)){
++ io_req->map_fd = dev->fd;
++ io_req->map_offset = io_req->offset +
++ dev->cow.data_offset;
++ dev->write_maps++;
++ }
++ else return(prepare_mmap_request(dev, fd, io_req->offset, req,
++ io_req));
++ }
++
++ if(req->cmd == READ)
++ dev->nomap_reads++;
++ else dev->nomap_writes++;
++
++ io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE;
++ io_req->offsets[0] = 0;
++ io_req->offsets[1] = dev->cow.data_offset;
++ io_req->buffer = req->buffer;
++ io_req->sectorsize = 1 << 9;
++
++ if(dev->cow.file != NULL)
++ cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
++ dev->cow.bitmap_len);
++ 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;
++ struct hd_driveid ubd_id = {
++ .cyls = 0,
++ .heads = 128,
++ .sectors = 32,
++ };
++
++ 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 = ubd_part[minor].start_sect;
++ 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_revalidate1(kdev_t rdev)
++{
++ int i, n, offset, err = 0, 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);
++ goto out;
++ }
++
++ /* have to recompute sizes since we opened it */
++ err = ubd_file_size(dev, &dev->size);
++ if(err < 0) {
++ ubd_close(dev);
++ goto out;
++ }
++ 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 err = -ENODEV;
++ out:
++ return(err);
++}
++
++static int ubd_revalidate(kdev_t rdev)
++{
++ int err;
++
++ spin_lock(&ubd_lock);
++ err = ubd_revalidate1(rdev);
++ spin_unlock(&ubd_lock);
++ return(err);
++}
++
++static int ubd_check_remapped(int fd, unsigned long address, int is_write,
++ __u64 offset)
++{
++ __u64 bitmap_offset;
++ unsigned long new_bitmap[2];
++ int i, err, n;
++
++ /* If it's not a write access, we can't do anything about it */
++ if(!is_write)
++ return(0);
++
++ /* We have a write */
++ for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
++ struct ubd *dev = &ubd_dev[i];
++
++ if((dev->fd != fd) && (dev->cow.fd != fd))
++ continue;
++
++ /* It's a write to a ubd device */
++
++ if(!dev->openflags.w){
++ /* It's a write access on a read-only device - probably
++ * shouldn't happen. If the kernel is trying to change
++ * something with no intention of writing it back out,
++ * then this message will clue us in that this needs
++ * fixing
++ */
++ printk("Write access to mapped page from readonly ubd "
++ "device %d\n", i);
++ return(0);
++ }
++
++ /* It's a write to a writeable ubd device - it must be COWed
++ * because, otherwise, the page would have been mapped in
++ * writeable
++ */
++
++ if(!dev->cow.file)
++ panic("Write fault on writeable non-COW ubd device %d",
++ i);
++
++ /* It should also be an access to the backing file since the
++ * COW pages should be mapped in read-write
++ */
++
++ if(fd == dev->fd)
++ panic("Write fault on a backing page of ubd "
++ "device %d\n", i);
++
++ /* So, we do the write, copying the backing data to the COW
++ * file...
++ */
++
++ err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
++ if(err < 0)
++ panic("Couldn't seek to %lld in COW file of ubd "
++ "device %d, err = %d",
++ offset + dev->cow.data_offset, i, -err);
++
++ n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
++ if(n != PAGE_SIZE)
++ panic("Couldn't copy data to COW file of ubd "
++ "device %d, err = %d", i, -n);
++
++ /* ... updating the COW bitmap... */
++
++ cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,
++ dev->cow.bitmap, dev->cow.bitmap_offset,
++ new_bitmap, dev->cow.bitmap_len);
++
++ err = os_seek_file(dev->fd, bitmap_offset);
++ if(err < 0)
++ panic("Couldn't seek to %lld in COW file of ubd "
++ "device %d, err = %d", bitmap_offset, i, -err);
++
++ n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
++ if(n != sizeof(new_bitmap))
++ panic("Couldn't update bitmap of ubd device %d, "
++ "err = %d", i, -n);
++
++ /* Maybe we can map the COW page in, and maybe we can't. If
++ * it is a pre-V3 COW file, we can't, since the alignment will
++ * be wrong. If it is a V3 or later COW file which has been
++ * moved to a system with a larger page size, then maybe we
++ * can't, depending on the exact location of the page.
++ */
++
++ offset += dev->cow.data_offset;
++
++ /* Remove the remapping, putting the original anonymous page
++ * back. If the COW file can be mapped in, that is done.
++ * Otherwise, the COW page is read in.
++ */
++
++ if(!physmem_remove_mapping((void *) address))
++ panic("Address 0x%lx not remapped by ubd device %d",
++ address, i);
++ if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
++ physmem_subst_mapping((void *) address, dev->fd,
++ offset, 1);
++ else {
++ err = os_seek_file(dev->fd, offset);
++ if(err < 0)
++ panic("Couldn't seek to %lld in COW file of "
++ "ubd device %d, err = %d", offset, i,
++ -err);
++
++ n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
++ if(n != PAGE_SIZE)
++ panic("Failed to read page from offset %llx of "
++ "COW file of ubd device %d, err = %d",
++ offset, i, -n);
++ }
++
++ return(1);
++ }
++
++ /* It's not a write on a ubd device */
++ return(0);
++}
++
++static struct remapper ubd_remapper = {
++ .list = LIST_HEAD_INIT(ubd_remapper.list),
++ .proc = ubd_check_remapped,
++};
++
++static int ubd_remapper_setup(void)
++{
++ if(ubd_do_mmap)
++ register_remapper(&ubd_remapper);
++
++ return(0);
++}
++
++__initcall(ubd_remapper_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/ubd_user.c um/arch/um/drivers/ubd_user.c
+--- orig/arch/um/drivers/ubd_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/ubd_user.c 2004-01-10 06:24:52.000000000 -0500
+@@ -0,0 +1,377 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sched.h>
++#include <signal.h>
++#include <string.h>
++#include <netinet/in.h>
++#include <sys/time.h>
++#include <sys/socket.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "ubd_user.h"
++#include "os.h"
++#include "cow.h"
++
++#include <endian.h>
++#include <byteswap.h>
++
++static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
++{
++ struct uml_stat buf1, buf2;
++ int err;
++
++ if(from_cmdline == NULL) return(1);
++ if(!strcmp(from_cmdline, from_cow)) return(1);
++
++ err = os_stat_file(from_cmdline, &buf1);
++ if(err < 0){
++ printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
++ return(1);
++ }
++ err = os_stat_file(from_cow, &buf2);
++ if(err < 0){
++ printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
++ return(1);
++ }
++ if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_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)
++{
++ unsigned long modtime;
++ long long actual;
++ int err;
++
++ err = os_file_modtime(file, &modtime);
++ if(err < 0){
++ printk("Failed to get modification time of backing file "
++ "\"%s\", err = %d\n", file, -err);
++ return(err);
++ }
++
++ err = os_file_size(file, &actual);
++ if(err < 0){
++ printk("Failed to get size of backing file \"%s\", "
++ "err = %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(modtime != mtime){
++ printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
++ "file\n", mtime, modtime);
++ 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(err);
++
++ err = os_read_file(fd, buf, len);
++ if(err < 0)
++ return(err);
++
++ return(0);
++}
++
++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;
++ __u32 version, align;
++ char *backing_file;
++ int fd, err, sectorsize, same, mode = 0644;
++
++ fd = os_open_file(file, *openflags, mode);
++ if(fd < 0){
++ if((fd == -ENOENT) && (create_cow_out != NULL))
++ *create_cow_out = 1;
++ if(!openflags->w ||
++ ((errno != EROFS) && (errno != EACCES))) return(-errno);
++ openflags->w = 0;
++ fd = os_open_file(file, *openflags, mode);
++ if(fd < 0)
++ return(fd);
++ }
++
++ err = os_lock_file(fd, openflags->w);
++ if(err < 0){
++ printk("Failed to lock '%s', err = %d\n", file, -err);
++ goto out_close;
++ }
++
++ if(backing_file_out == NULL) return(fd);
++
++ err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
++ &size, §orsize, &align, 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 out_close;
++ }
++ 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, align, &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 out_close;
++ }
++
++ cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
++ bitmap_len_out, data_offset_out);
++
++ return(fd);
++ out_close:
++ os_close_file(fd);
++ return(err);
++}
++
++int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
++ int sectorsize, int alignment, int *bitmap_offset_out,
++ unsigned long *bitmap_len_out, int *data_offset_out)
++{
++ int err, fd;
++
++ 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 = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
++ bitmap_offset_out, bitmap_len_out,
++ data_offset_out);
++ if(!err)
++ return(fd);
++
++ os_close_file(fd);
++ out:
++ return(err);
++}
++
++/* XXX Just trivial wrappers around os_read_file and os_write_file */
++int read_ubd_fs(int fd, void *buffer, int len)
++{
++ return(os_read_file(fd, buffer, len));
++}
++
++int write_ubd_fs(int fd, char *buffer, int len)
++{
++ return(os_write_file(fd, buffer, len));
++}
++
++static int update_bitmap(struct io_thread_req *req)
++{
++ int n;
++
++ if(req->cow_offset == -1)
++ return(0);
++
++ n = os_seek_file(req->fds[1], req->cow_offset);
++ if(n < 0){
++ printk("do_io - bitmap lseek failed : err = %d\n", -n);
++ return(1);
++ }
++
++ n = os_write_file(req->fds[1], &req->bitmap_words,
++ sizeof(req->bitmap_words));
++ if(n != sizeof(req->bitmap_words)){
++ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
++ req->fds[1]);
++ return(1);
++ }
++
++ return(0);
++}
++
++void do_io(struct io_thread_req *req)
++{
++ char *buf;
++ unsigned long len;
++ int n, nsectors, start, end, bit;
++ int err;
++ __u64 off;
++
++ if(req->op == UBD_MMAP){
++ /* Touch the page to force the host to do any necessary IO to
++ * get it into memory
++ */
++ n = *((volatile int *) req->buffer);
++ req->error = update_bitmap(req);
++ return;
++ }
++
++ 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++;
++
++ off = req->offset + req->offsets[bit] +
++ start * req->sectorsize;
++ len = (end - start) * req->sectorsize;
++ buf = &req->buffer[start * req->sectorsize];
++
++ err = os_seek_file(req->fds[bit], off);
++ if(err < 0){
++ printk("do_io - lseek failed : err = %d\n", -err);
++ req->error = 1;
++ return;
++ }
++ if(req->op == UBD_READ){
++ n = 0;
++ do {
++ buf = &buf[n];
++ len -= n;
++ n = os_read_file(req->fds[bit], buf, len);
++ if (n < 0) {
++ printk("do_io - read failed, err = %d "
++ "fd = %d\n", -n, req->fds[bit]);
++ req->error = 1;
++ return;
++ }
++ } while((n < len) && (n != 0));
++ if (n < len) memset(&buf[n], 0, len - n);
++ }
++ else {
++ n = os_write_file(req->fds[bit], buf, len);
++ if(n != len){
++ printk("do_io - write failed err = %d "
++ "fd = %d\n", -n, req->fds[bit]);
++ req->error = 1;
++ return;
++ }
++ }
++
++ start = end;
++ } while(start < nsectors);
++
++ req->error = update_bitmap(req);
++}
++
++/* Changed in start_io_thread, which is serialized by being called only
++ * from ubd_init, which is an initcall.
++ */
++int kernel_fd = -1;
++
++/* Only changed by the io thread */
++int io_count = 0;
++
++int io_thread(void *arg)
++{
++ struct io_thread_req req;
++ int n;
++
++ signal(SIGWINCH, SIG_IGN);
++ while(1){
++ n = os_read_file(kernel_fd, &req, sizeof(req));
++ if(n != sizeof(req)){
++ if(n < 0)
++ printk("io_thread - read failed, fd = %d, "
++ "err = %d\n", kernel_fd, -n);
++ else {
++ printk("io_thread - short read, fd = %d, "
++ "length = %d\n", kernel_fd, n);
++ }
++ continue;
++ }
++ io_count++;
++ do_io(&req);
++ n = os_write_file(kernel_fd, &req, sizeof(req));
++ if(n != sizeof(req))
++ printk("io_thread - write failed, fd = %d, err = %d\n",
++ kernel_fd, -n);
++ }
++}
++
++int start_io_thread(unsigned long sp, int *fd_out)
++{
++ int pid, fds[2], err;
++
++ err = os_pipe(fds, 1, 1);
++ if(err < 0){
++ printk("start_io_thread - os_pipe failed, err = %d\n", -err);
++ goto out;
++ }
++
++ 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);
++ goto out_close;
++ }
++
++ return(pid);
++
++ out_close:
++ os_close_file(fds[0]);
++ os_close_file(fds[1]);
++ kernel_fd = -1;
++ *fd_out = -1;
++ out:
++ return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm.c um/arch/um/drivers/xterm.c
+--- orig/arch/um/drivers/xterm.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/xterm.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,201 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <termios.h>
++#include <signal.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "chan_user.h"
++#include "helper.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++#include "xterm.h"
++
++struct xterm_chan {
++ int pid;
++ int helper_pid;
++ char *title;
++ int device;
++ int raw;
++ struct termios tt;
++ unsigned long stack;
++ int direct_rcv;
++};
++
++void *xterm_init(char *str, int device, struct chan_opts *opts)
++{
++ struct xterm_chan *data;
++
++ data = malloc(sizeof(*data));
++ if(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,
++ .direct_rcv = !opts->in_kernel } );
++ return(data);
++}
++
++/* Only changed by xterm_setup, which is a setup */
++static char *terminal_emulator = "xterm";
++static char *title_switch = "-T";
++static char *exec_switch = "-e";
++
++static int __init xterm_setup(char *line, int *add)
++{
++ *add = 0;
++ terminal_emulator = line;
++
++ line = strchr(line, ',');
++ if(line == NULL) return(0);
++ *line++ = '\0';
++ if(*line) title_switch = line;
++
++ line = strchr(line, ',');
++ if(line == NULL) return(0);
++ *line++ = '\0';
++ if(*line) exec_switch = line;
++
++ return(0);
++}
++
++__uml_setup("xterm=", xterm_setup,
++"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
++" Specifies an alternate terminal emulator to use for the debugger,\n"
++" consoles, and serial lines when they are attached to the xterm channel.\n"
++" The values are the terminal emulator binary, the switch it uses to set\n"
++" its title, and the switch it uses to execute a subprocess,\n"
++" respectively. The title switch must have the form '<switch> title',\n"
++" not '<switch>=title'. Similarly, the exec switch must have the form\n"
++" '<switch> command arg1 arg2 ...'.\n"
++" The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n"
++" are 'xterm=gnome-terminal,-t,-x'.\n\n"
++);
++
++int xterm_open(int input, int output, int primary, void *d, char **dev_out)
++{
++ struct xterm_chan *data = d;
++ unsigned long stack;
++ int pid, fd, new, err;
++ 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 };
++
++ if(os_access(argv[4], OS_ACC_X_OK) < 0)
++ argv[4] = "port-helper";
++
++ 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);
++ }
++ os_close_file(fd);
++
++ fd = os_create_unix_socket(file, sizeof(file), 1);
++ if(fd < 0){
++ printk("xterm_open : create_unix_socket failed, errno = %d\n",
++ -fd);
++ return(fd);
++ }
++
++ 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, errno = %d\n", -pid);
++ return(pid);
++ }
++
++ if(data->stack == 0) free_stack(stack, 0);
++
++ if(data->direct_rcv)
++ new = os_rcv_fd(fd, &data->helper_pid);
++ else {
++ err = os_set_fd_block(fd, 0);
++ if(err < 0){
++ printk("xterm_open : failed to set descriptor "
++ "non-blocking, err = %d\n", -err);
++ return(err);
++ }
++ new = xterm_fd(fd, &data->helper_pid);
++ }
++ if(new < 0){
++ printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
++ goto out;
++ }
++
++ tcgetattr(new, &data->tt);
++ if(data->raw) raw(new, 0);
++
++ data->pid = pid;
++ *dev_out = NULL;
++ out:
++ unlink(file);
++ return(new);
++}
++
++void xterm_close(int fd, void *d)
++{
++ struct xterm_chan *data = d;
++
++ if(data->pid != -1)
++ os_kill_process(data->pid, 1);
++ data->pid = -1;
++ if(data->helper_pid != -1)
++ os_kill_process(data->helper_pid, 0);
++ data->helper_pid = -1;
++ os_close_file(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 = {
++ .type = "xterm",
++ .init = xterm_init,
++ .open = xterm_open,
++ .close = xterm_close,
++ .read = generic_read,
++ .write = generic_write,
++ .console_write = xterm_console_write,
++ .window_size = generic_window_size,
++ .free = xterm_free,
++ .winch = 1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm.h um/arch/um/drivers/xterm.h
+--- orig/arch/um/drivers/xterm.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/xterm.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __XTERM_H__
++#define __XTERM_H__
++
++extern int xterm_fd(int socket, int *pid_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm_kern.c um/arch/um/drivers/xterm_kern.c
+--- orig/arch/um/drivers/xterm_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/drivers/xterm_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/errno.h"
++#include "linux/slab.h"
++#include "asm/semaphore.h"
++#include "asm/irq.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++#include "kern_util.h"
++#include "os.h"
++#include "xterm.h"
++
++struct xterm_wait {
++ struct semaphore sem;
++ int fd;
++ int pid;
++ int new_fd;
++};
++
++static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++ struct xterm_wait *xterm = data;
++ int fd;
++
++ fd = os_rcv_fd(xterm->fd, &xterm->pid);
++ if(fd == -EAGAIN)
++ return;
++
++ xterm->new_fd = fd;
++ up(&xterm->sem);
++}
++
++int xterm_fd(int socket, int *pid_out)
++{
++ struct xterm_wait *data;
++ int err, ret;
++
++ data = kmalloc(sizeof(*data), GFP_KERNEL);
++ if(data == NULL){
++ printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
++ return(-ENOMEM);
++ }
++ *data = ((struct xterm_wait)
++ { .sem = __SEMAPHORE_INITIALIZER(data->sem, 0),
++ .fd = socket,
++ .pid = -1,
++ .new_fd = -1 });
++
++ err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
++ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
++ "xterm", data);
++ if(err){
++ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
++ "err = %d\n", err);
++ ret = err;
++ goto out;
++ }
++ down(&data->sem);
++
++ free_irq(XTERM_IRQ, data);
++
++ ret = data->new_fd;
++ *pid_out = data->pid;
++ out:
++ kfree(data);
++
++ return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/dyn_link.ld.in um/arch/um/dyn_link.ld.in
+--- orig/arch/um/dyn_link.ld.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/dyn_link.ld.in 2004-01-10 04:28:44.000000000 -0500
+@@ -0,0 +1,171 @@
++OUTPUT_FORMAT("ELF_FORMAT")
++OUTPUT_ARCH(ELF_ARCH)
++ENTRY(_start)
++SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
++/* Do we need any of these for elf?
++ __DYNAMIC = 0; */
++SECTIONS
++{
++ . = START() + SIZEOF_HEADERS;
++ .interp : { *(.interp) }
++ __binary_start = .;
++ . = ALIGN(4096); /* Init code and data */
++ _stext = .;
++ __init_begin = .;
++ .text.init : { *(.text.init) }
++
++ . = ALIGN(4096);
++
++ /* Read-only sections, merged into text segment: */
++ .hash : { *(.hash) }
++ .dynsym : { *(.dynsym) }
++ .dynstr : { *(.dynstr) }
++ .gnu.version : { *(.gnu.version) }
++ .gnu.version_d : { *(.gnu.version_d) }
++ .gnu.version_r : { *(.gnu.version_r) }
++ .rel.init : { *(.rel.init) }
++ .rela.init : { *(.rela.init) }
++ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
++ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
++ .rel.fini : { *(.rel.fini) }
++ .rela.fini : { *(.rela.fini) }
++ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
++ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
++ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
++ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
++ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
++ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
++ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
++ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
++ .rel.ctors : { *(.rel.ctors) }
++ .rela.ctors : { *(.rela.ctors) }
++ .rel.dtors : { *(.rel.dtors) }
++ .rela.dtors : { *(.rela.dtors) }
++ .rel.got : { *(.rel.got) }
++ .rela.got : { *(.rela.got) }
++ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
++ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
++ .rel.plt : { *(.rel.plt) }
++ .rela.plt : { *(.rela.plt) }
++ .init : {
++ KEEP (*(.init))
++ } =0x90909090
++ .plt : { *(.plt) }
++ .text : {
++ *(.text .stub .text.* .gnu.linkonce.t.*)
++ /* .gnu.warning sections are handled specially by elf32.em. */
++ *(.gnu.warning)
++ } =0x90909090
++ .fini : {
++ KEEP (*(.fini))
++ } =0x90909090
++
++ PROVIDE (__etext = .);
++ PROVIDE (_etext = .);
++ PROVIDE (etext = .);
++ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
++ .rodata1 : { *(.rodata1) }
++ .eh_frame_hdr : { *(.eh_frame_hdr) }
++
++
++ . = ALIGN(4096);
++ PROVIDE (_sdata = .);
++
++include(`arch/um/common.ld.in')
++
++ /* Ensure the __preinit_array_start label is properly aligned. We
++ could instead move the label definition inside the section, but
++ the linker would then create the section even if it turns out to
++ be empty, which isn't pretty. */
++ . = ALIGN(32 / 8);
++ .preinit_array : { *(.preinit_array) }
++ .init_array : { *(.init_array) }
++ .fini_array : { *(.fini_array) }
++ .data : {
++ . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
++ *(.data.init_task)
++ *(.data .data.* .gnu.linkonce.d.*)
++ SORT(CONSTRUCTORS)
++ }
++ .data1 : { *(.data1) }
++ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
++ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
++ .eh_frame : { KEEP (*(.eh_frame)) }
++ .gcc_except_table : { *(.gcc_except_table) }
++ .dynamic : { *(.dynamic) }
++ .ctors : {
++ /* gcc uses crtbegin.o to find the start of
++ the constructors, so we make sure it is
++ first. Because this is a wildcard, it
++ doesn't matter if the user does not
++ actually link against crtbegin.o; the
++ linker won't look for a file to match a
++ wildcard. The wildcard also means that it
++ doesn't matter which directory crtbegin.o
++ is in. */
++ KEEP (*crtbegin.o(.ctors))
++ /* We don't want to include the .ctor section from
++ from the crtend.o file until after the sorted ctors.
++ The .ctor section from the crtend file contains the
++ end of ctors marker and it must be last */
++ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
++ KEEP (*(SORT(.ctors.*)))
++ KEEP (*(.ctors))
++ }
++ .dtors : {
++ KEEP (*crtbegin.o(.dtors))
++ KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
++ KEEP (*(SORT(.dtors.*)))
++ KEEP (*(.dtors))
++ }
++ .jcr : { KEEP (*(.jcr)) }
++ .got : { *(.got.plt) *(.got) }
++ _edata = .;
++ PROVIDE (edata = .);
++ __bss_start = .;
++ .bss : {
++ *(.dynbss)
++ *(.bss .bss.* .gnu.linkonce.b.*)
++ *(COMMON)
++ /* Align here to ensure that the .bss section occupies space up to
++ _end. Align after .bss to ensure correct alignment even if the
++ .bss section disappears because there are no input sections. */
++ . = ALIGN(32 / 8);
++ . = ALIGN(32 / 8);
++ }
++ _end = .;
++ PROVIDE (end = .);
++ /* Stabs debugging sections. */
++ .stab 0 : { *(.stab) }
++ .stabstr 0 : { *(.stabstr) }
++ .stab.excl 0 : { *(.stab.excl) }
++ .stab.exclstr 0 : { *(.stab.exclstr) }
++ .stab.index 0 : { *(.stab.index) }
++ .stab.indexstr 0 : { *(.stab.indexstr) }
++ .comment 0 : { *(.comment) }
++ /* DWARF debug sections.
++ Symbols in the DWARF debugging sections are relative to the beginning
++ of the section so we begin them at 0. */
++ /* DWARF 1 */
++ .debug 0 : { *(.debug) }
++ .line 0 : { *(.line) }
++ /* GNU DWARF 1 extensions */
++ .debug_srcinfo 0 : { *(.debug_srcinfo) }
++ .debug_sfnames 0 : { *(.debug_sfnames) }
++ /* DWARF 1.1 and DWARF 2 */
++ .debug_aranges 0 : { *(.debug_aranges) }
++ .debug_pubnames 0 : { *(.debug_pubnames) }
++ /* DWARF 2 */
++ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
++ .debug_abbrev 0 : { *(.debug_abbrev) }
++ .debug_line 0 : { *(.debug_line) }
++ .debug_frame 0 : { *(.debug_frame) }
++ .debug_str 0 : { *(.debug_str) }
++ .debug_loc 0 : { *(.debug_loc) }
++ .debug_macinfo 0 : { *(.debug_macinfo) }
++ /* SGI/MIPS DWARF 2 extensions */
++ .debug_weaknames 0 : { *(.debug_weaknames) }
++ .debug_funcnames 0 : { *(.debug_funcnames) }
++ .debug_typenames 0 : { *(.debug_typenames) }
++ .debug_varnames 0 : { *(.debug_varnames) }
++}
+diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs.h um/arch/um/fs/hostfs/hostfs.h
+--- orig/arch/um/fs/hostfs/hostfs.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hostfs/hostfs.h 2003-12-17 10:52:50.000000000 -0500
+@@ -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, int append);
++extern int file_type(const char *path, int *rdev);
++extern void *open_dir(char *path, int *err_out);
++extern char *read_dir(void *stream, unsigned long long *pos,
++ unsigned long long *ino_out, int *len_out);
++extern void close_file(void *stream);
++extern void close_dir(void *stream);
++extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
++extern int write_file(int fd, unsigned long long *offset, const char *buf,
++ int len);
++extern int lseek_file(int fd, long long offset, int whence);
++extern int file_create(char *name, int ur, int uw, int ux, int gr,
++ int gw, int gx, int or, int ow, int ox);
++extern int set_attr(const char *file, struct hostfs_iattr *attrs);
++extern int make_symlink(const char *from, const char *to);
++extern int unlink_file(const char *file);
++extern int do_mkdir(const char *file, int mode);
++extern int do_rmdir(const char *file);
++extern int do_mknod(const char *file, int mode, int dev);
++extern int link_file(const char *from, const char *to);
++extern int do_readlink(char *file, char *buf, int size);
++extern int rename_file(char *from, char *to);
++extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
++ long long *bfree_out, long long *bavail_out,
++ long long *files_out, long long *ffree_out,
++ void *fsid_out, int fsid_size, long *namelen_out,
++ long *spare_out);
++
++#endif
+diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs_kern.c um/arch/um/fs/hostfs/hostfs_kern.c
+--- orig/arch/um/fs/hostfs/hostfs_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hostfs/hostfs_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,965 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.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"
++#include "init.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,
++};
++
++#define DEFAULT_ROOT "/"
++
++/* Changed in hostfs_args before the kernel starts running */
++static char *jail_dir = NULL;
++static int append = 0;
++
++#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 int __init hostfs_args(char *options, int *add)
++{
++ char *ptr;
++
++ ptr = strchr(options, ',');
++ if(ptr != NULL)
++ *ptr++ = '\0';
++ if(*options != '\0')
++ jail_dir = options;
++
++ options = ptr;
++ while(options){
++ ptr = strchr(options, ',');
++ if(ptr != NULL)
++ *ptr++ = '\0';
++ if(*options != '\0'){
++ if(!strcmp(options, "append"))
++ append = 1;
++ else printf("hostfs_args - unsupported option - %s\n",
++ options);
++ }
++ options = ptr;
++ }
++ return(0);
++}
++
++__uml_setup("hostfs=", hostfs_args,
++"hostfs=<root dir>,<flags>,...\n"
++" This is used to set hostfs parameters. The root directory argument\n"
++" is used to confine all hostfs mounts to within the specified directory\n"
++" tree on the host. If this isn't specified, then a user inside UML can\n"
++" mount anything on the host that's accessible to the user that's running\n"
++" it.\n"
++" The only flag currently supported is 'append', which specifies that all\n"
++" files opened by hostfs will be opened in append mode.\n\n"
++);
++
++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 char *follow_link(char *link)
++{
++ int len, n;
++ char *name, *resolved, *end;
++
++ len = 64;
++ while(1){
++ n = -ENOMEM;
++ name = kmalloc(len, GFP_KERNEL);
++ if(name == NULL)
++ goto out;
++
++ n = do_readlink(link, name, len);
++ if(n < len)
++ break;
++ len *= 2;
++ kfree(name);
++ }
++ if(n < 0)
++ goto out_free;
++
++ if(*name == '/')
++ return(name);
++
++ end = strrchr(link, '/');
++ if(end == NULL)
++ return(name);
++
++ *(end + 1) = '\0';
++ len = strlen(link) + strlen(name) + 1;
++
++ resolved = kmalloc(len, GFP_KERNEL);
++ if(resolved == NULL){
++ n = -ENOMEM;
++ goto out_free;
++ }
++
++ sprintf(resolved, "%s%s", link, name);
++ kfree(name);
++ kfree(link);
++ return(resolved);
++
++ out_free:
++ kfree(name);
++ out:
++ return(ERR_PTR(n));
++}
++
++static int read_inode(struct inode *ino)
++{
++ char *name;
++ int err;
++
++ err = -ENOMEM;
++ name = inode_name(ino, 0);
++ if(name == NULL)
++ goto out;
++
++ if(file_type(name, NULL) == OS_TYPE_SYMLINK){
++ name = follow_link(name);
++ if(IS_ERR(name)){
++ err = PTR_ERR(name);
++ goto out;
++ }
++ }
++
++ err = read_name(ino, name);
++ kfree(name);
++ out:
++ 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);
++
++ /* The file may already have been opened, but with the wrong access,
++ * so this resets things and reopens the file with the new access.
++ */
++ 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, append);
++ 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;
++
++ memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
++
++ 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,
++/* .set_page_dirty = __set_page_dirty_nobuffers, */
++ .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:
++ make_bad_inode(inode);
++ 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, fd;
++
++ inode = get_inode(dir->i_sb, dentry, &error);
++ if(error) return(error);
++ name = dentry_name(dentry, 0);
++ if(name == NULL){
++ iput(inode);
++ return(-ENOMEM);
++ }
++ fd = 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(fd < 0)
++ error = fd;
++ else error = read_name(inode, name);
++
++ kfree(name);
++ if(error){
++ iput(inode);
++ return(error);
++ }
++ inode->u.hostfs_i.fd = fd;
++ inode->u.hostfs_i.mode = FMODE_READ | FMODE_WRITE;
++ 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;
++
++ from_name = inode_dentry_name(ino, from);
++ if(from_name == 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;
++
++ file = inode_dentry_name(ino, dentry);
++ if(file == NULL) return(-ENOMEM);
++ if(append)
++ return(-EPERM);
++
++ err = unlink_file(file);
++ kfree(file);
++ return(err);
++}
++
++int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
++{
++ char *file;
++ int err;
++
++ file = inode_dentry_name(ino, dentry);
++ if(file == 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;
++
++ file = inode_dentry_name(ino, dentry);
++ if(file == 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;
++
++ file = inode_dentry_name(ino, dentry);
++ if(file == 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;
++
++ from_name = inode_dentry_name(from_ino, from);
++ if(from_name == NULL)
++ return(-ENOMEM);
++ to_name = inode_dentry_name(to_ino, to);
++ if(to_name == 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;
++
++ if(append)
++ attr->ia_valid &= ~ATTR_SIZE;
++
++ 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);
++ if(err)
++ return(err);
++
++ return(inode_setattr(dentry->d_inode, attr));
++}
++
++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 == PAGE_CACHE_SIZE)
++ err = -E2BIG;
++ else if(err > 0){
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ if (PageError(page)) ClearPageError(page);
++ err = 0;
++ }
++ kunmap(page);
++ UnlockPage(page);
++ return(err);
++}
++
++static struct address_space_operations hostfs_link_aops = {
++ .readpage = hostfs_link_readpage,
++};
++
++static char *get_root(char *mount_arg)
++{
++ char *root, *slash = "";
++ int len = 0;
++
++ if(jail_dir != NULL){
++ len += strlen(jail_dir);
++ if((*jail_dir == '\0') ||
++ (jail_dir[strlen(jail_dir) - 1] != '/'))
++ slash = "/";
++ len += strlen(slash);
++ }
++
++ if((mount_arg == NULL) || (*mount_arg == '\0'))
++ mount_arg = DEFAULT_ROOT;
++
++ len += strlen(mount_arg) + 1;
++
++ root = kmalloc(len, GFP_KERNEL);
++ if(root == NULL)
++ return(NULL);
++
++ if(jail_dir != NULL)
++ sprintf(root, "%s%s%s", jail_dir, slash, mount_arg);
++ else
++ strcpy(root, mount_arg);
++
++ return(root);
++}
++
++struct super_block *hostfs_read_super(struct super_block *sb, void *data,
++ int silent)
++{
++ struct inode *root_inode;
++ char *root_dir;
++
++ sb->s_blocksize = 1024;
++ sb->s_blocksize_bits = 10;
++ sb->s_magic = HOSTFS_SUPER_MAGIC;
++ sb->s_op = &hostfs_sbops;
++
++ root_inode = get_inode(sb, NULL, NULL);
++ if(root_inode == NULL)
++ goto out;
++
++ root_dir = get_root(data);
++ if(root_dir == NULL)
++ goto out_put;
++
++ root_inode->u.hostfs_i.host_filename = root_dir;
++ sb->s_root = d_alloc_root(root_inode);
++ if(sb->s_root == NULL)
++ goto out_free;
++
++ if(read_inode(root_inode))
++ goto out_dput;
++ return(sb);
++
++ out_dput:
++ dput(sb->s_root);
++ out_free:
++ kfree(root_dir);
++ out_put:
++ make_bad_inode(root_inode);
++ iput(root_inode);
++ out:
++ return(NULL);
++}
++
++DECLARE_FSTYPE(hostfs_type, "hostfs", hostfs_read_super, 0);
++
++static int __init init_hostfs(void)
++{
++ return(register_filesystem(&hostfs_type));
++}
++
++static void __exit exit_hostfs(void)
++{
++ unregister_filesystem(&hostfs_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs_user.c um/arch/um/fs/hostfs/hostfs_user.c
+--- orig/arch/um/fs/hostfs/hostfs_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hostfs/hostfs_user.c 2003-11-14 08:51:20.000000000 -0500
+@@ -0,0 +1,359 @@
++/*
++ * 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);
++ if(rdev != NULL)
++ *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 append)
++{
++ 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");
++
++ if(append)
++ mode |= O_APPEND;
++ 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, err;
++
++ err = os_seek_file(fd, *offset);
++ if(err)
++ return(err);
++
++ n = os_read_file(fd, buf, len);
++ if(n < 0)
++ return(n);
++
++ *offset += n;
++ return(n);
++}
++
++int write_file(int fd, unsigned long long *offset, const char *buf, int len)
++{
++ int n, err;
++
++ err = os_seek_file(fd, *offset);
++ if(err)
++ return(err);
++
++ n = os_write_file(fd, buf, len);
++ if(n < 0)
++ return(n);
++
++ *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 | O_RDWR, mode);
++ if(fd < 0)
++ return(-errno);
++ return(fd);
++}
++
++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 n;
++
++ n = readlink(file, buf, size);
++ if(n < 0)
++ return(-errno);
++ if(n < size)
++ buf[n] = '\0';
++ return(n);
++}
++
++int rename_file(char *from, char *to)
++{
++ int err;
++
++ err = rename(from, to);
++ if(err < 0) return(-errno);
++ return(0);
++}
++
++int do_statfs(char *root, long *bsize_out, long long *blocks_out,
++ long long *bfree_out, long long *bavail_out,
++ long long *files_out, long long *ffree_out,
++ void *fsid_out, int fsid_size, long *namelen_out,
++ long *spare_out)
++{
++ struct statfs64 buf;
++ int err;
++
++ err = statfs64(root, &buf);
++ if(err < 0) return(-errno);
++ *bsize_out = buf.f_bsize;
++ *blocks_out = buf.f_blocks;
++ *bfree_out = buf.f_bfree;
++ *bavail_out = buf.f_bavail;
++ *files_out = buf.f_files;
++ *ffree_out = buf.f_ffree;
++ memcpy(fsid_out, &buf.f_fsid,
++ sizeof(buf.f_fsid) > fsid_size ? fsid_size :
++ sizeof(buf.f_fsid));
++ *namelen_out = buf.f_namelen;
++ spare_out[0] = buf.f_spare[0];
++ spare_out[1] = buf.f_spare[1];
++ spare_out[2] = buf.f_spare[2];
++ spare_out[3] = buf.f_spare[3];
++ spare_out[4] = buf.f_spare[4];
++ spare_out[5] = buf.f_spare[5];
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/Makefile um/arch/um/fs/hostfs/Makefile
+--- orig/arch/um/fs/hostfs/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hostfs/Makefile 2003-10-21 03:26:06.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)
++
++USER_OBJS = $(filter %_user.o,$(obj-y))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+diff -Naur -X ../exclude-files orig/arch/um/fs/hppfs/hppfs_kern.c um/arch/um/fs/hppfs/hppfs_kern.c
+--- orig/arch/um/fs/hppfs/hppfs_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hppfs/hppfs_kern.c 2004-01-08 23:35:58.000000000 -0500
+@@ -0,0 +1,737 @@
++/*
++ * 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 <linux/ctype.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 super_operations hppfs_sbops;
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++ int *error);
++
++static int is_pid(struct dentry *dentry)
++{
++ struct super_block *sb;
++ int i;
++
++ sb = dentry->d_sb;
++ if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
++ return(0);
++
++ for(i = 0; i < dentry->d_name.len; i++){
++ if(!isdigit(dentry->d_name.name[i]))
++ return(0);
++ }
++ return(1);
++}
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++ struct dentry *parent;
++ char *root, *name;
++ const char *seg_name;
++ int len, seg_len;
++
++ len = 0;
++ parent = dentry;
++ while(parent->d_parent != parent){
++ if(is_pid(parent))
++ len += strlen("pid") + 1;
++ else 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){
++ if(is_pid(parent)){
++ seg_name = "pid";
++ seg_len = strlen("pid");
++ }
++ else {
++ seg_name = parent->d_name.name;
++ seg_len = parent->d_name.len;
++ }
++
++ len -= seg_len + 1;
++ name[len] = '/';
++ strncpy(&name[len + 1], seg_name, seg_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("file_removed : 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, int is_user)
++{
++ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
++ ssize_t n;
++
++ read = file->f_dentry->d_inode->i_fop->read;
++ if(read == NULL)
++ return(-EOPNOTSUPP);
++
++ if(!is_user)
++ set_fs(KERNEL_DS);
++
++ n = (*read)(file, buf, count, &file->f_pos);
++
++ if(!is_user)
++ 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, err = %d\n", -err);
++ 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;
++ copy_to_user(buf, &data->contents[off], count);
++ *ppos += count;
++ }
++ else if(hppfs->host_fd != -1){
++ err = os_seek_file(hppfs->host_fd, *ppos);
++ if(err < 0){
++ printk("hppfs_read : seek failed, err = %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, 1);
++
++ 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;
++ if(write == NULL)
++ return(-EOPNOTSUPP);
++
++ 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)) > 0) {
++ err = os_write_file(fd, data->contents, n);
++ if(err != n)
++ printk("hppfs_get_data : failed to write out "
++ "%d bytes, err = %d\n", n, -err);
++ }
++ err = os_shutdown_socket(fd, 0, 1);
++ if(err < 0){
++ 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, err = %d\n", -n);
++ 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', err = %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', err = %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;
++ if(readdir == NULL)
++ return(-EOPNOTSUPP);
++
++ 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;
++ if(readlink == NULL)
++ return(-EOPNOTSUPP);
++ 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 int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ struct file proc_file;
++ struct dentry *proc_dentry;
++ int (*follow_link)(struct dentry *, struct nameidata *);
++ 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);
++
++ follow_link = proc_dentry->d_inode->i_op->follow_link;
++ if(follow_link == NULL)
++ return(-EOPNOTSUPP);
++ n = (*follow_link)(proc_dentry, nd);
++
++ 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,
++ .follow_link = hppfs_follow_link,
++};
++
++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 = new_inode(sb);
++ 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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/fs/hppfs/Makefile um/arch/um/fs/hppfs/Makefile
+--- orig/arch/um/fs/hppfs/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/hppfs/Makefile 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/fs/Makefile um/arch/um/fs/Makefile
+--- orig/arch/um/fs/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/fs/Makefile 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,23 @@
++#
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := built-in.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:
+diff -Naur -X ../exclude-files orig/arch/um/include/2_5compat.h um/arch/um/include/2_5compat.h
+--- orig/arch/um/include/2_5compat.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/2_5compat.h 2003-11-07 02:49:26.000000000 -0500
+@@ -0,0 +1,33 @@
++/*
++ * 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"
++
++#define INIT_ELV(queue, elv) elevator_init(elv, ELV_NOOP)
++
++#define ELV_NOOP ELEVATOR_NOOP
++
++#define INIT_HARDSECT(arr, maj, sizes) arr[maj] = sizes
++
++#define IS_WRITE(req) ((req)->cmd == WRITE)
++
++#define SET_PRI(task) \
++ do { (task)->nice = 20; (task)->counter = -100; } while(0);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/chan_kern.h um/arch/um/include/chan_kern.h
+--- orig/arch/um/include/chan_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/chan_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,56 @@
++/*
++ * 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;
++ char *dev;
++ 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);
++extern int chan_config_string(struct list_head *chans, char *str, int size,
++ char **error_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/chan_user.h um/arch/um/include/chan_user.h
+--- orig/arch/um/include/chan_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/chan_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHAN_USER_H__
++#define __CHAN_USER_H__
++
++#include "init.h"
++
++struct chan_opts {
++ void (*announce)(char *dev_name, int dev);
++ char *xterm_title;
++ int raw;
++ unsigned long tramp_stack;
++ int in_kernel;
++};
++
++enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
++
++struct chan_ops {
++ char *type;
++ void *(*init)(char *, int, struct chan_opts *);
++ int (*open)(int, int, int, void *, char **);
++ 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);
++
++#define __channel_help(fn, prefix) \
++__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
++" Attach a console or serial line to a host channel. See\n" \
++" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
++" description of this switch.\n\n" \
++);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/choose-mode.h um/arch/um/include/choose-mode.h
+--- orig/arch/um/include/choose-mode.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/choose-mode.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHOOSE_MODE_H__
++#define __CHOOSE_MODE_H__
++
++#include "uml-config.h"
++
++#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS)
++#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
++
++#elif defined(UML_CONFIG_MODE_SKAS)
++#define CHOOSE_MODE(tt, skas) (skas)
++
++#elif defined(UML_CONFIG_MODE_TT)
++#define CHOOSE_MODE(tt, skas) (tt)
++#endif
++
++#define CHOOSE_MODE_PROC(tt, skas, args...) \
++ CHOOSE_MODE(tt(args), skas(args))
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/frame.h um/arch/um/include/frame.h
+--- orig/arch/um/include/frame.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/frame.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,53 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_H_
++#define __FRAME_H_
++
++#include "sysdep/frame.h"
++
++struct frame_common {
++ void *data;
++ int len;
++ int sig_index;
++ int sr_index;
++ int sr_relative;
++ int sp_index;
++ struct arch_frame_data arch;
++};
++
++struct sc_frame {
++ struct frame_common common;
++ int sc_index;
++};
++
++extern struct sc_frame signal_frame_sc;
++
++extern struct sc_frame signal_frame_sc_sr;
++
++struct si_frame {
++ struct frame_common common;
++ int sip_index;
++ int si_index;
++ int ucp_index;
++ int uc_index;
++};
++
++extern struct si_frame signal_frame_si;
++
++extern void capture_signal_stack(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/frame_kern.h um/arch/um/include/frame_kern.h
+--- orig/arch/um/include/frame_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/frame_kern.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/frame_user.h um/arch/um/include/frame_user.h
+--- orig/arch/um/include/frame_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/frame_user.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/helper.h um/arch/um/include/helper.h
+--- orig/arch/um/include/helper.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/helper.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/init.h um/arch/um/include/init.h
+--- orig/arch/um/include/init.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/init.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/initrd.h um/arch/um/include/initrd.h
+--- orig/arch/um/include/initrd.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/initrd.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/irq_kern.h um/arch/um/include/irq_kern.h
+--- orig/arch/um/include/irq_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/irq_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_KERN_H__
++#define __IRQ_KERN_H__
++
++#include "linux/interrupt.h"
++
++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
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/irq_user.h um/arch/um/include/irq_user.h
+--- orig/arch/um/include/irq_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/irq_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,35 @@
++/*
++ * 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, union 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);
++extern int activate_ipi(int fd, int pid);
++extern unsigned long irq_lock(void);
++extern void irq_unlock(unsigned long flags);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/kern.h um/arch/um/include/kern.h
+--- orig/arch/um/include/kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __KERN_H__
++#define __KERN_H__
++
++/* These are all user-mode things which are convenient to call directly
++ * from kernel code and for which writing a wrapper is too much of a pain.
++ * The regular include files can't be included because this file is included
++ * only into kernel code, and user-space includes conflict with kernel
++ * includes.
++ */
++
++extern int errno;
++
++extern int 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);
++extern int ptrace(int op, int pid, long addr, long data);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/kern_util.h um/arch/um/include/kern_util.h
+--- orig/arch/um/include/kern_util.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/kern_util.h 2003-11-10 00:58:10.000000000 -0500
+@@ -0,0 +1,123 @@
++/*
++ * 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;
++extern int nsyscalls;
++
++#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
++#define UML_ROUND_UP(addr) \
++ UML_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 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);
++extern unsigned long handle_page_fault(unsigned long address, unsigned long ip,
++ int is_write, int is_user,
++ int *code_out);
++extern void syscall_ready(void);
++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 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, union 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 int next_syscall_index(int max);
++extern int next_trap_index(int max);
++extern void cpu_idle(void);
++extern void finish_fork(void);
++extern void paging_init(void);
++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, union uml_pt_regs *regs);
++extern int external_pid(void *t);
++extern void boot_timer_handler(int sig);
++extern void interrupt_end(void);
++extern void initial_thread_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, union uml_pt_regs *regs);
++extern void not_implemented(void);
++extern int user_context(unsigned long sp);
++extern void timer_irq(union 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 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 void set_kmem_end(unsigned long);
++extern void uml_cleanup(void);
++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 int strlen_user_proc(char *str);
++extern void bus_handler(int sig, union uml_pt_regs *regs);
++extern void winch(int sig, union 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 void free_irq(unsigned int, void *);
++extern int um_in_interrupt(void);
++extern int cpu(void);
++extern unsigned long long time_stamp(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/line.h um/arch/um/include/line.h
+--- orig/arch/um/include/line.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/line.h 2003-11-07 02:25:37.000000000 -0500
+@@ -0,0 +1,103 @@
++/*
++ * 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"
++#include "mconsole_kern.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 mc_device mc;
++};
++
++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;
++};
++
++#define LINES_INIT(n) { num : n }
++
++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 int line_setup(struct line *lines, int num, char *init,
++ int all_allowed);
++extern int line_write(struct line *line, struct tty_struct *tty, int from_user,
++ const char *buf, int len);
++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);
++extern int line_config(struct line *lines, int num, char *str);
++extern int line_remove(struct line *lines, int num, char *str);
++extern int line_get_config(char *dev, struct line *lines, int num, char *str,
++ int size, char **error_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/Makefile um/arch/um/include/Makefile
+--- orig/arch/um/include/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/Makefile 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/include/mconsole.h um/arch/um/include/mconsole.h
+--- orig/arch/um/include/mconsole.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mconsole.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,103 @@
++/*
++ * 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__
++
++#ifndef __KERNEL__
++#include <stdint.h>
++#define u32 uint32_t
++#endif
++
++#define MCONSOLE_MAGIC (0xcafebabe)
++#define MCONSOLE_MAX_DATA (512)
++#define MCONSOLE_VERSION 2
++
++struct mconsole_request {
++ u32 magic;
++ u32 version;
++ u32 len;
++ char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_reply {
++ u32 err;
++ u32 more;
++ u32 len;
++ char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_notify {
++ u32 magic;
++ u32 version;
++ enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
++ MCONSOLE_USER_NOTIFY } type;
++ u32 len;
++ char data[MCONSOLE_MAX_DATA];
++};
++
++struct mc_request;
++
++enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
++
++struct mconsole_command
++{
++ char *command;
++ void (*handler)(struct mc_request *req);
++ enum mc_context context;
++};
++
++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 void mconsole_log(struct mc_request *req);
++extern void mconsole_proc(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);
++extern void lock_notify(void);
++extern void unlock_notify(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mconsole_kern.h um/arch/um/include/mconsole_kern.h
+--- orig/arch/um/include/mconsole_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mconsole_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2001, 2002 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 (*get_config)(char *, char *, int, char **);
++ int (*remove)(char *);
++};
++
++#define CONFIG_CHUNK(str, size, current, chunk, end) \
++do { \
++ current += strlen(chunk); \
++ if(current >= size) \
++ str = NULL; \
++ if(str != NULL){ \
++ strcpy(str, chunk); \
++ str += strlen(chunk); \
++ } \
++ if(end) \
++ current++; \
++} while(0)
++
++#ifdef CONFIG_MCONSOLE
++
++extern void mconsole_register_dev(struct mc_device *new);
++
++#else
++
++static inline void mconsole_register_dev(struct mc_device *new)
++{
++}
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mem.h um/arch/um/include/mem.h
+--- orig/arch/um/include/mem.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mem.h 2004-01-16 11:14:38.000000000 -0500
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_H__
++#define __MEM_H__
++
++#include "linux/types.h"
++
++extern void set_kmem_end(unsigned long new);
++extern int phys_mapping(unsigned long phys, __u64 *offset_out);
++extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
++extern int is_remapped(void *virt);
++extern int physmem_remove_mapping(void *virt);
++extern void physmem_forget_descriptor(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mem_kern.h um/arch/um/include/mem_kern.h
+--- orig/arch/um/include/mem_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mem_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_KERN_H__
++#define __MEM_KERN_H__
++
++#include "linux/list.h"
++#include "linux/types.h"
++
++struct remapper {
++ struct list_head list;
++ int (*proc)(int, unsigned long, int, __u64);
++};
++
++extern void register_remapper(struct remapper *info);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mem_user.h um/arch/um/include/mem_user.h
+--- orig/arch/um/include/mem_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mem_user.h 2004-01-10 00:11:06.000000000 -0500
+@@ -0,0 +1,81 @@
++/*
++ * 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 iomem_region {
++ struct iomem_region *next;
++ char *driver;
++ int fd;
++ int size;
++ unsigned long phys;
++ unsigned long virt;
++};
++
++extern struct iomem_region *iomem_regions;
++extern int iomem_size;
++
++#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_memory(void *entry);
++extern unsigned long find_iomem(char *driver, unsigned long *len_out);
++extern int init_maps(unsigned long physmem, unsigned long iomem,
++ unsigned long highmem);
++extern unsigned long get_vm(unsigned long len);
++extern void setup_physmem(unsigned long start, unsigned long usable,
++ unsigned long len, unsigned long highmem);
++extern void add_iomem(char *name, int fd, unsigned long size);
++extern unsigned long phys_offset(unsigned long phys);
++extern void unmap_physmem(void);
++extern void map_memory(unsigned long virt, unsigned long phys,
++ unsigned long len, int r, int w, int x);
++extern int protect_memory(unsigned long addr, unsigned long len,
++ int r, int w, int x, int must_succeed);
++extern unsigned long get_kmem_end(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mode.h um/arch/um/include/mode.h
+--- orig/arch/um/include/mode.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mode.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_H__
++#define __MODE_H__
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "../kernel/tt/include/mode.h"
++#endif
++
++#ifdef UML_CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mode.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/mode_kern.h um/arch/um/include/mode_kern.h
+--- orig/arch/um/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/mode_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_KERN_H__
++#define __MODE_KERN_H__
++
++#include "linux/config.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/mode_kern.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mode_kern.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/net_kern.h um/arch/um/include/net_kern.h
+--- orig/arch/um/include/net_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/net_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#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"
++
++struct uml_net {
++ struct list_head list;
++ struct net_device *dev;
++ int 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 {
++ void (*init)(struct net_device *, void *);
++ 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 *, char **, void *);
++ struct net_user_info *user;
++ struct net_kern_info *kern;
++ int private_size;
++ int setup_size;
++};
++
++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 **mac_out, char **gate_addr);
++extern void register_transport(struct transport *new);
++extern unsigned short eth_protocol(struct sk_buff *skb);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/net_user.h um/arch/um/include/net_user.h
+--- orig/arch/um/include/net_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/net_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#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);
++
++extern char *split_if_spec(char *str, ...);
++
++extern int dev_netmask(void *d, void *m);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/os.h um/arch/um/include/os.h
+--- orig/arch/um/include/os.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/os.h 2003-12-17 10:48:12.000000000 -0500
+@@ -0,0 +1,180 @@
++/*
++ * 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
++
++/* os_access() flags */
++#define OS_ACC_F_OK 0 /* Test for existence. */
++#define OS_ACC_X_OK 1 /* Test for execute permission. */
++#define OS_ACC_W_OK 2 /* Test for write permission. */
++#define OS_ACC_R_OK 4 /* Test for read permission. */
++#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
++
++/*
++ * types taken from stat_file() in hostfs_user.c
++ * (if they are wrong here, they are wrong there...).
++ */
++struct uml_stat {
++ int ust_dev; /* device */
++ unsigned long long ust_ino; /* inode */
++ int ust_mode; /* protection */
++ int ust_nlink; /* number of hard links */
++ int ust_uid; /* user ID of owner */
++ int ust_gid; /* group ID of owner */
++ unsigned long long ust_size; /* total size, in bytes */
++ int ust_blksize; /* blocksize for filesystem I/O */
++ unsigned long long ust_blocks; /* number of blocks allocated */
++ unsigned long ust_atime; /* time of last access */
++ unsigned long ust_mtime; /* time of last modification */
++ unsigned long ust_ctime; /* time of last change */
++};
++
++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 */
++ unsigned int cl : 1; /* FD_CLOEXEC */
++};
++
++#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \
++ .t = 0, .a = 0, .e = 0, .cl = 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);
++}
++
++static inline struct openflags of_cloexec(struct openflags flags)
++{
++ flags.cl = 1;
++ return(flags);
++}
++
++extern int os_stat_file(const char *file_name, struct uml_stat *buf);
++extern int os_stat_fd(const int fd, struct uml_stat *buf);
++extern int os_access(const char *file, int mode);
++extern void os_print_error(int error, const char* str);
++extern int os_get_exec_close(int fd, int *close_on_exec);
++extern int os_set_exec_close(int fd, int close_on_exec);
++extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
++extern int os_window_size(int fd, int *rows, int *cols);
++extern int os_new_tty_pgrp(int fd, int pid);
++extern int os_get_ifname(int fd, char *namebuf);
++extern int os_set_slip(int fd);
++extern int os_set_owner(int fd, int pid);
++extern int os_sigio_async(int master, int slave);
++extern int os_mode_fd(int fd, int mode);
++
++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, void *buf, int len);
++extern int os_write_file(int fd, const void *buf, int count);
++extern int os_file_size(char *file, long long *size_out);
++extern int os_file_modtime(char *file, unsigned long *modtime);
++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_create_unix_socket(char *file, int len, int close_on_exec);
++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, int close_on_exec);
++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_lock_file(int fd, int excl);
++
++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, int reap_child);
++extern void os_usr1_process(int pid);
++extern int os_getpid(void);
++
++extern int os_map_memory(void *virt, int fd, unsigned long long off,
++ unsigned long len, int r, int w, int x);
++extern int os_protect_memory(void *addr, unsigned long len,
++ int r, int w, int x);
++extern int os_unmap_memory(void *addr, int len);
++extern void os_flush_stdout(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/process.h um/arch/um/include/process.h
+--- orig/arch/um/include/process.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/process.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/ptrace_user.h um/arch/um/include/ptrace_user.h
+--- orig/arch/um/include/ptrace_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/ptrace_user.h 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/include/sigcontext.h um/arch/um/include/sigcontext.h
+--- orig/arch/um/include/sigcontext.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sigcontext.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,25 @@
++/*
++ * 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 void sc_to_sc(void *to_ptr, void *from_ptr);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sigio.h um/arch/um/include/sigio.h
+--- orig/arch/um/include/sigio.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sigio.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,28 @@
++/*
++ * 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);
++extern void sigio_lock(void);
++extern void sigio_unlock(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/signal_kern.h um/arch/um/include/signal_kern.h
+--- orig/arch/um/include/signal_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/signal_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGNAL_KERN_H__
++#define __SIGNAL_KERN_H__
++
++extern int have_signals(void *t);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/signal_user.h um/arch/um/include/signal_user.h
+--- orig/arch/um/include/signal_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/signal_user.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/skas_ptrace.h um/arch/um/include/skas_ptrace.h
+--- orig/arch/um/include/skas_ptrace.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/skas_ptrace.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_PTRACE_H
++#define __SKAS_PTRACE_H
++
++struct ptrace_faultinfo {
++ int is_write;
++ unsigned long addr;
++};
++
++struct ptrace_ldt {
++ int func;
++ void *ptr;
++ unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/syscall_user.h um/arch/um/include/syscall_user.h
+--- orig/arch/um/include/syscall_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/syscall_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,23 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSCALL_USER_H
++#define __SYSCALL_USER_H
++
++extern int record_syscall_start(int syscall);
++extern void record_syscall_end(int index, int result);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/checksum.h um/arch/um/include/sysdep-i386/checksum.h
+--- orig/arch/um/include/sysdep-i386/checksum.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/checksum.h 2004-01-13 23:40:05.000000000 -0500
+@@ -0,0 +1,218 @@
++/*
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SYSDEP_CHECKSUM_H
++#define __UM_SYSDEP_CHECKSUM_H
++
++#include "linux/string.h"
++#include "asm/uaccess.h"
++
++/*
++ * computes the checksum of a memory block at buff, length len,
++ * and adds in "sum" (32-bit)
++ *
++ * returns a 32-bit number suitable for feeding into itself
++ * or csum_tcpudp_magic
++ *
++ * this function must be called with even lengths, except
++ * for the last fragment, which may be odd
++ *
++ * it's best to have buff aligned on a 32-bit boundary
++ */
++unsigned int csum_partial(const unsigned char * buff, int len,
++ unsigned int sum);
++
++/*
++ * the same as csum_partial, but copies from src while it
++ * checksums, and handles user-space pointer exceptions correctly, when needed.
++ *
++ * here even more important to align src and dst on a 32-bit (or even
++ * better 64-bit) boundary
++ */
++
++unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
++ int sum, int *err_ptr);
++unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
++ int sum, int *err_ptr);
++
++/*
++ * Note: when you get a NULL pointer exception here this means someone
++ * passed in an incorrect kernel address to one of these functions.
++ *
++ * If you use these functions directly please don't forget the
++ * verify_area().
++ */
++
++static __inline__
++unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
++ int len, int sum)
++{
++ memcpy(dst, src, len);
++ return(csum_partial(dst, len, sum));
++}
++
++static __inline__
++unsigned int csum_partial_copy_from_user(const char *src, char *dst,
++ int len, int sum, int *err_ptr)
++{
++ return csum_partial_copy_from(src, dst, len, sum, err_ptr);
++}
++
++/*
++ * These are the old (and unsafe) way of doing checksums, a warning message
++ * will be printed if they are used and an exception occurs.
++ *
++ * these functions should go away after some time.
++ */
++
++#define csum_partial_copy_fromuser csum_partial_copy_from_user
++unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
++
++/*
++ * This is a version of ip_compute_csum() optimized for IP headers,
++ * which always checksum on 4 octet boundaries.
++ *
++ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
++ * Arnt Gulbrandsen.
++ */
++static inline unsigned short ip_fast_csum(unsigned char * iph,
++ unsigned int ihl)
++{
++ unsigned int sum;
++
++ __asm__ __volatile__(
++ "movl (%1), %0 ;\n"
++ "subl $4, %2 ;\n"
++ "jbe 2f ;\n"
++ "addl 4(%1), %0 ;\n"
++ "adcl 8(%1), %0 ;\n"
++ "adcl 12(%1), %0 ;\n"
++"1: adcl 16(%1), %0 ;\n"
++ "lea 4(%1), %1 ;\n"
++ "decl %2 ;\n"
++ "jne 1b ;\n"
++ "adcl $0, %0 ;\n"
++ "movl %0, %2 ;\n"
++ "shrl $16, %0 ;\n"
++ "addw %w2, %w0 ;\n"
++ "adcl $0, %0 ;\n"
++ "notl %0 ;\n"
++"2: ;\n"
++ /* Since the input registers which are loaded with iph and ipl
++ are modified, we must also specify them as outputs, or gcc
++ will assume they contain their original values. */
++ : "=r" (sum), "=r" (iph), "=r" (ihl)
++ : "1" (iph), "2" (ihl));
++ return(sum);
++}
++
++/*
++ * Fold a partial checksum
++ */
++
++static inline unsigned int csum_fold(unsigned int sum)
++{
++ __asm__(
++ "addl %1, %0 ;\n"
++ "adcl $0xffff, %0 ;\n"
++ : "=r" (sum)
++ : "r" (sum << 16), "0" (sum & 0xffff0000)
++ );
++ return (~sum) >> 16;
++}
++
++static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
++ unsigned long daddr,
++ unsigned short len,
++ unsigned short proto,
++ unsigned int sum)
++{
++ __asm__(
++ "addl %1, %0 ;\n"
++ "adcl %2, %0 ;\n"
++ "adcl %3, %0 ;\n"
++ "adcl $0, %0 ;\n"
++ : "=r" (sum)
++ : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
++ return sum;
++}
++
++/*
++ * computes the checksum of the TCP/UDP pseudo-header
++ * returns a 16-bit checksum, already complemented
++ */
++static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
++ unsigned long daddr,
++ unsigned short len,
++ unsigned short proto,
++ unsigned int sum)
++{
++ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
++}
++
++/*
++ * this routine is used for miscellaneous IP-like checksums, mainly
++ * in icmp.c
++ */
++
++static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
++{
++ return csum_fold (csum_partial(buff, len, 0));
++}
++
++#define _HAVE_ARCH_IPV6_CSUM
++static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
++ struct in6_addr *daddr,
++ __u32 len,
++ unsigned short proto,
++ unsigned int sum)
++{
++ __asm__(
++ "addl 0(%1), %0 ;\n"
++ "adcl 4(%1), %0 ;\n"
++ "adcl 8(%1), %0 ;\n"
++ "adcl 12(%1), %0 ;\n"
++ "adcl 0(%2), %0 ;\n"
++ "adcl 4(%2), %0 ;\n"
++ "adcl 8(%2), %0 ;\n"
++ "adcl 12(%2), %0 ;\n"
++ "adcl %3, %0 ;\n"
++ "adcl %4, %0 ;\n"
++ "adcl $0, %0 ;\n"
++ : "=&r" (sum)
++ : "r" (saddr), "r" (daddr),
++ "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
++
++ return csum_fold(sum);
++}
++
++/*
++ * Copy and checksum to user
++ */
++#define HAVE_CSUM_COPY_USER
++static __inline__ unsigned int csum_and_copy_to_user(const char *src,
++ char *dst, int len,
++ int sum, int *err_ptr)
++{
++ if (access_ok(VERIFY_WRITE, dst, len))
++ return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
++
++ if (len)
++ *err_ptr = -EFAULT;
++
++ return -1; /* invalid checksum */
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame.h um/arch/um/include/sysdep-i386/frame.h
+--- orig/arch/um/include/sysdep-i386/frame.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/frame.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,29 @@
++/*
++ * 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 fp_start;
++ unsigned long sr;
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame_kern.h um/arch/um/include/sysdep-i386/frame_kern.h
+--- orig/arch/um/include/sysdep-i386/frame_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/frame_kern.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,69 @@
++/*
++ * 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_uc(unsigned long sp)
++{
++ unsigned long uc;
++
++ uc = sp + signal_frame_si.uc_index -
++ signal_frame_si.common.sp_index - 4;
++ return((void *) uc);
++}
++
++static inline void *sp_to_rt_sc(unsigned long sp)
++{
++ unsigned long sc;
++
++ sc = sp - signal_frame_si.common.sp_index +
++ signal_frame_si.common.len - 4;
++ return((void *) sc);
++}
++
++static inline void *sp_to_mask(unsigned long sp)
++{
++ unsigned long mask;
++
++ mask = sp - signal_frame_sc.common.sp_index +
++ signal_frame_sc.common.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.common.sp_index +
++ signal_frame_si.common.len +
++ sc_size(&signal_frame_si.common.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame_user.h um/arch/um/include/sysdep-i386/frame_user.h
+--- orig/arch/um/include/sysdep-i386/frame_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/frame_user.h 2004-01-14 03:54:47.000000000 -0500
+@@ -0,0 +1,91 @@
++/*
++ * 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 sigcontext 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,
++ void *end, unsigned long srp)
++{
++ unsigned long sr = *((unsigned long *) srp);
++
++ data->fp_start = (unsigned long) end;
++ if((sr & PAGE_MASK) == ((unsigned long) end & PAGE_MASK))
++ data->sr = sr;
++ else data->sr = 0;
++}
++
++static inline void setup_arch_frame(struct arch_frame_data_raw *in,
++ struct arch_frame_data *out)
++{
++ unsigned long fpstate_start = in->fp_start;
++
++ if(in->sr == 0){
++ fpstate_start &= ~PAGE_MASK;
++ out->fpstate_size = PAGE_SIZE - fpstate_start;
++ }
++ else {
++ out->fpstate_size = in->sr - 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).
++ */
++
++#define frame_restorer() \
++({ \
++ unsigned long *fp; \
++\
++ fp = __builtin_frame_address(0); \
++ ((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.
++ */
++
++#define frame_sp() \
++({ \
++ unsigned long *fp; \
++\
++ fp = __builtin_frame_address(0); \
++ ((unsigned long) (fp + 1)); \
++})
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/ptrace.h um/arch/um/include/sysdep-i386/ptrace.h
+--- orig/arch/um/include/sysdep-i386/ptrace.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/ptrace.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,193 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_I386_PTRACE_H
++#define __SYSDEP_I386_PTRACE_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "ptrace-tt.h"
++#endif
++
++#ifdef UML_CONFIG_MODE_SKAS
++#include "ptrace-skas.h"
++#endif
++
++#include "choose-mode.h"
++
++union uml_pt_regs {
++#ifdef UML_CONFIG_MODE_TT
++ struct tt_regs {
++ long syscall;
++ void *sc;
++ } tt;
++#endif
++#ifdef UML_CONFIG_MODE_SKAS
++ struct skas_regs {
++ unsigned long regs[HOST_FRAME_SIZE];
++ unsigned long fp[HOST_FP_SIZE];
++ unsigned long xfp[HOST_XFP_SIZE];
++ unsigned long fault_addr;
++ unsigned long fault_type;
++ unsigned long trap_type;
++ long syscall;
++ int is_user;
++ } skas;
++#endif
++};
++
++#define EMPTY_UML_PT_REGS { }
++
++extern int mode_tt;
++
++#define UPT_SC(r) ((r)->tt.sc)
++#define UPT_IP(r) \
++ CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
++#define UPT_SP(r) \
++ CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
++#define UPT_EFLAGS(r) \
++ CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
++#define UPT_EAX(r) \
++ CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
++#define UPT_EBX(r) \
++ CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
++#define UPT_ECX(r) \
++ CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
++#define UPT_EDX(r) \
++ CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
++#define UPT_ESI(r) \
++ CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
++#define UPT_EDI(r) \
++ CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
++#define UPT_EBP(r) \
++ CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
++#define UPT_ORIG_EAX(r) \
++ CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
++#define UPT_CS(r) \
++ CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
++#define UPT_SS(r) \
++ CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
++#define UPT_DS(r) \
++ CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
++#define UPT_ES(r) \
++ CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
++#define UPT_FS(r) \
++ CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
++#define UPT_GS(r) \
++ CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
++
++#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
++#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
++#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
++#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
++#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
++#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
++
++extern int user_context(unsigned long sp);
++
++#define UPT_IS_USER(r) \
++ CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user)
++
++struct syscall_args {
++ unsigned long args[6];
++};
++
++#define SYSCALL_ARGS(r) ((struct syscall_args) \
++ { .args = { UPT_SYSCALL_ARG1(r), \
++ UPT_SYSCALL_ARG2(r), \
++ UPT_SYSCALL_ARG3(r), \
++ UPT_SYSCALL_ARG4(r), \
++ UPT_SYSCALL_ARG5(r), \
++ UPT_SYSCALL_ARG6(r) } } )
++
++#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(r, res) \
++ CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \
++ REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res)))
++
++#define UPT_RESTART_SYSCALL(r) \
++ CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \
++ REGS_RESTART_SYSCALL((r)->skas.regs))
++
++#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
++#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
++#define UPT_SYSCALL_RET(r) UPT_EAX(r)
++
++#define UPT_SEGV_IS_FIXABLE(r) \
++ CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
++ REGS_SEGV_IS_FIXABLE(&r->skas))
++
++#define UPT_FAULT_ADDR(r) \
++ CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
++
++#define UPT_FAULT_WRITE(r) \
++ CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/ptrace_user.h um/arch/um/include/sysdep-i386/ptrace_user.h
+--- orig/arch/um/include/sysdep-i386/ptrace_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/ptrace_user.h 2003-10-21 03:26:06.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
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/sigcontext.h um/arch/um/include/sysdep-i386/sigcontext.h
+--- orig/arch/um/include/sysdep-i386/sigcontext.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/sigcontext.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_SIGCONTEXT_I386_H
++#define __SYS_SIGCONTEXT_I386_H
++
++#include "sc.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) SC_EAX(sc) = (result)
++
++#define SC_FAULT_ADDR(sc) SC_CR2(sc)
++#define SC_FAULT_TYPE(sc) SC_ERR(sc)
++
++#define FAULT_WRITE(err) (err & 2)
++#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
++
++#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
++
++#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
++
++/* 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)
++
++/* This is Page Fault */
++#define SEGV_IS_FIXABLE(trap) (trap == 14)
++
++#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/syscalls.h um/arch/um/include/sysdep-i386/syscalls.h
+--- orig/arch/um/include/sysdep-i386/syscalls.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-i386/syscalls.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/unistd.h"
++#include "sysdep/ptrace.h"
++
++typedef long syscall_handler_t(struct pt_regs);
++
++#define EXECUTE_SYSCALL(syscall, regs) \
++ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs))
++
++extern syscall_handler_t sys_modify_ldt;
++extern syscall_handler_t old_mmap_i386;
++extern syscall_handler_t old_select;
++extern syscall_handler_t sys_ni_syscall;
++
++#define ARCH_SYSCALLS \
++ [ __NR_mmap ] = old_mmap_i386, \
++ [ __NR_select ] = old_select, \
++ [ __NR_vm86old ] = sys_ni_syscall, \
++ [ __NR_modify_ldt ] = sys_modify_ldt, \
++ [ __NR_lchown32 ] = sys_lchown, \
++ [ __NR_getuid32 ] = sys_getuid, \
++ [ __NR_getgid32 ] = sys_getgid, \
++ [ __NR_geteuid32 ] = sys_geteuid, \
++ [ __NR_getegid32 ] = sys_getegid, \
++ [ __NR_setreuid32 ] = sys_setreuid, \
++ [ __NR_setregid32 ] = sys_setregid, \
++ [ __NR_getgroups32 ] = sys_getgroups, \
++ [ __NR_setgroups32 ] = sys_setgroups, \
++ [ __NR_fchown32 ] = sys_fchown, \
++ [ __NR_setresuid32 ] = sys_setresuid, \
++ [ __NR_getresuid32 ] = sys_getresuid, \
++ [ __NR_setresgid32 ] = sys_setresgid, \
++ [ __NR_getresgid32 ] = sys_getresgid, \
++ [ __NR_chown32 ] = sys_chown, \
++ [ __NR_setuid32 ] = sys_setuid, \
++ [ __NR_setgid32 ] = sys_setgid, \
++ [ __NR_setfsuid32 ] = sys_setfsuid, \
++ [ __NR_setfsgid32 ] = sys_setfsgid, \
++ [ __NR_pivot_root ] = sys_pivot_root, \
++ [ __NR_mincore ] = sys_mincore, \
++ [ __NR_madvise ] = sys_madvise, \
++ [ 222 ] = sys_ni_syscall,
++
++/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
++
++#define LAST_ARCH_SYSCALL 222
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/ptrace.h um/arch/um/include/sysdep-ia64/ptrace.h
+--- orig/arch/um/include/sysdep-ia64/ptrace.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ia64/ptrace.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/sigcontext.h um/arch/um/include/sysdep-ia64/sigcontext.h
+--- orig/arch/um/include/sysdep-ia64/sigcontext.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ia64/sigcontext.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/syscalls.h um/arch/um/include/sysdep-ia64/syscalls.h
+--- orig/arch/um/include/sysdep-ia64/syscalls.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ia64/syscalls.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/ptrace.h um/arch/um/include/sysdep-ppc/ptrace.h
+--- orig/arch/um/include/sysdep-ppc/ptrace.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ppc/ptrace.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/sigcontext.h um/arch/um/include/sysdep-ppc/sigcontext.h
+--- orig/arch/um/include/sysdep-ppc/sigcontext.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ppc/sigcontext.h 2003-10-21 03:26:06.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 *_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 *_sc = (sc); \
++ long retval = -1; \
++ switch (_sc->regs->trap) { \
++ case 0x300: \
++ /* data exception */ \
++ retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
++ break; \
++ case 0x400: \
++ /* instruction exception: not a write */ \
++ retval = 0; \
++ break; \
++ default: \
++ panic("SC_FAULT_ADDR: unhandled trap type\n"); \
++ } \
++ retval; \
++ })
++
++#define SC_IP(sc) ((sc)->regs->nip)
++#define SC_SP(sc) ((sc)->regs->gpr[1])
++#define SEGV_IS_FIXABLE(sc) (1)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/syscalls.h um/arch/um/include/sysdep-ppc/syscalls.h
+--- orig/arch/um/include/sysdep-ppc/syscalls.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysdep-ppc/syscalls.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/sysrq.h um/arch/um/include/sysrq.h
+--- orig/arch/um/include/sysrq.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/sysrq.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SYSRQ_H
++#define __UM_SYSRQ_H
++
++extern void show_trace(unsigned long *stack);
++
++#endif
+diff -Naur -X ../exclude-files orig/arch/um/include/tempfile.h um/arch/um/include/tempfile.h
+--- orig/arch/um/include/tempfile.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/tempfile.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TEMPFILE_H__
++#define __TEMPFILE_H__
++
++extern int make_tempfile(const char *template, char **tempname, int do_unlink);
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/time_user.h um/arch/um/include/time_user.h
+--- orig/arch/um/include/time_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/time_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TIME_USER_H__
++#define __TIME_USER_H__
++
++extern void timer(void);
++extern void switch_timers(int to_real);
++extern void set_interval(int timer_type);
++extern void idle_sleep(int secs);
++extern void enable_timer(void);
++extern unsigned long time_lock(void);
++extern void time_unlock(unsigned long);
++
++#endif
+diff -Naur -X ../exclude-files orig/arch/um/include/tlb.h um/arch/um/include/tlb.h
+--- orig/arch/um/include/tlb.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/tlb.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/ubd_user.h um/arch/um/include/ubd_user.h
+--- orig/arch/um/include/ubd_user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/ubd_user.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,79 @@
++/*
++ * 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, UBD_MMAP };
++
++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 long cow_offset;
++ unsigned long bitmap_words[2];
++ int map_fd;
++ unsigned long long map_offset;
++ 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 alignment, 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);
++
++static inline int ubd_test_bit(__u64 bit, unsigned char *data)
++{
++ __u64 n;
++ int bits, off;
++
++ bits = sizeof(data[0]) * 8;
++ n = bit / bits;
++ off = bit % bits;
++ return((data[n] & (1 << off)) != 0);
++}
++
++static inline void ubd_set_bit(__u64 bit, unsigned char *data)
++{
++ __u64 n;
++ int bits, off;
++
++ bits = sizeof(data[0]) * 8;
++ n = bit / bits;
++ off = bit % bits;
++ data[n] |= (1 << off);
++}
++
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/umid.h um/arch/um/include/umid.h
+--- orig/arch/um/include/umid.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/umid.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UMID_H__
++#define __UMID_H__
++
++extern int umid_file_name(char *name, char *buf, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/uml_uaccess.h um/arch/um/include/uml_uaccess.h
+--- orig/arch/um/include/uml_uaccess.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/uml_uaccess.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UML_UACCESS_H__
++#define __UML_UACCESS_H__
++
++extern int __do_copy_to_user(void *to, const void *from, int n,
++ void **fault_addr, void **fault_catcher);
++extern 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);
++void __do_copy(void *to, const void *from, int n);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/um_mmu.h um/arch/um/include/um_mmu.h
+--- orig/arch/um/include/um_mmu.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/um_mmu.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __ARCH_UM_MMU_H
++#define __ARCH_UM_MMU_H
++
++#include "linux/config.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/mmu.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mmu.h"
++#endif
++
++typedef union {
++#ifdef CONFIG_MODE_TT
++ struct mmu_context_tt tt;
++#endif
++#ifdef CONFIG_MODE_SKAS
++ struct mmu_context_skas skas;
++#endif
++} mm_context_t;
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/umn.h um/arch/um/include/umn.h
+--- orig/arch/um/include/umn.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/umn.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/um_uaccess.h um/arch/um/include/um_uaccess.h
+--- orig/arch/um/include/um_uaccess.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/um_uaccess.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,124 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __ARCH_UM_UACCESS_H
++#define __ARCH_UM_UACCESS_H
++
++#include "linux/config.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/uaccess.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/uaccess.h"
++#endif
++
++#define access_ok(type, addr, size) \
++ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
++
++static inline int verify_area(int type, const void * addr, unsigned long size)
++{
++ return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
++ size));
++}
++
++static inline int copy_from_user(void *to, const void *from, int n)
++{
++ return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
++ from, n));
++}
++
++static inline int copy_to_user(void *to, const void *from, int n)
++{
++ return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to,
++ from, n));
++}
++
++/*
++ * strncpy_from_user: - Copy a NUL terminated string from userspace.
++ * @dst: Destination address, in kernel space. This buffer must be at
++ * least @count bytes long.
++ * @src: Source address, in user space.
++ * @count: Maximum number of bytes to copy, including the trailing NUL.
++ *
++ * Copies a NUL-terminated string from userspace to kernel space.
++ *
++ * On success, returns the length of the string (not including the trailing
++ * NUL).
++ *
++ * If access to userspace fails, returns -EFAULT (some data may have been
++ * copied).
++ *
++ * If @count is smaller than the length of the string, copies @count bytes
++ * and returns @count.
++ */
++
++static inline int strncpy_from_user(char *dst, const char *src, int count)
++{
++ return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
++ dst, src, count));
++}
++
++/*
++ * __clear_user: - Zero a block of memory in user space, with less checking.
++ * @to: Destination address, in user space.
++ * @n: Number of bytes to zero.
++ *
++ * Zero a block of memory in user space. Caller must check
++ * the specified block with access_ok() before calling this function.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
++static inline int __clear_user(void *mem, int len)
++{
++ return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
++}
++
++/*
++ * clear_user: - Zero a block of memory in user space.
++ * @to: Destination address, in user space.
++ * @n: Number of bytes to zero.
++ *
++ * Zero a block of memory in user space.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
++static inline int clear_user(void *mem, int len)
++{
++ return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
++}
++
++/*
++ * strlen_user: - Get the size of a string in user space.
++ * @str: The string to measure.
++ * @n: The maximum valid length
++ *
++ * Get the size of a NUL-terminated string in user space.
++ *
++ * Returns the size of the string INCLUDING the terminating NUL.
++ * On exception, returns 0.
++ * If the string is too long, returns a value greater than @n.
++ */
++static inline int strnlen_user(const void *str, int len)
++{
++ return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/user.h um/arch/um/include/user.h
+--- orig/arch/um/include/user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/user.h 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/include/user_util.h um/arch/um/include/user_util.h
+--- orig/arch/um/include/user_util.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/include/user_util.h 2003-11-09 11:36:31.000000000 -0500
+@@ -0,0 +1,103 @@
++/*
++ * 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 mode_tt;
++
++extern int grantpt(int __fd);
++extern int unlockpt(int __fd);
++extern char *ptsname(int __fd);
++
++struct cpu_task {
++ int pid;
++ void *task;
++};
++
++extern struct cpu_task cpu_tasks[];
++
++struct signal_info {
++ void (*handler)(int, union uml_pt_regs *);
++ int is_irq;
++};
++
++extern struct signal_info sig_info[];
++
++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 unsigned long highmem;
++
++extern char host_info[];
++
++extern char saved_command_line[];
++extern char command_line[];
++
++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 stop(void);
++extern void stack_protections(unsigned long address);
++extern void task_protections(unsigned long address);
++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 int start_fork_tramp(void *arg, unsigned long temp_stack,
++ int clone_flags, int (*tramp)(void *));
++extern int linux_main(int argc, char **argv);
++extern void set_cmdline(char *cmd);
++extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
++extern int get_pty(void);
++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 setup_machinename(char *machine_out);
++extern void setup_hostinfo(void);
++extern void add_arg(char *cmd_line, char *arg);
++extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
++extern void init_new_thread_signals(int altstack);
++extern void do_exec(int old_pid, int new_pid);
++extern void tracer_panic(char *msg, ...);
++extern char *get_umid(int only_if_set);
++extern void do_longjmp(void *p, int val);
++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 void write_sigio_workaround(void);
++extern void arch_check_bugs(void);
++extern int cpu_feature(char *what, char *buf, int len);
++extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
++extern int arch_fixup(unsigned long address, void *sc_ptr);
++extern int can_do_skas(void);
++extern void arch_init_thread(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/checksum.c um/arch/um/kernel/checksum.c
+--- orig/arch/um/kernel/checksum.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/checksum.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,42 @@
++#include "asm/uaccess.h"
++#include "linux/errno.h"
++
++extern unsigned int arch_csum_partial(const char *buff, int len, int sum);
++
++extern unsigned int csum_partial(char *buff, int len, int sum)
++{
++ return(arch_csum_partial(buff, len, sum));
++}
++
++unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
++ int sum, int *err_ptr)
++{
++ if(copy_to_user(dst, src, len)){
++ *err_ptr = -EFAULT;
++ return(-1);
++ }
++
++ return(arch_csum_partial(src, len, sum));
++}
++
++unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
++ int sum, int *err_ptr)
++{
++ if(copy_from_user(dst, src, len)){
++ *err_ptr = -EFAULT;
++ return(-1);
++ }
++
++ return(arch_csum_partial(dst, len, sum));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/config.c.in um/arch/um/kernel/config.c.in
+--- orig/arch/um/kernel/config.c.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/config.c.in 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,32 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "init.h"
++
++static __initdata char *config = "CONFIG";
++
++static int __init print_config(char *line, int *add)
++{
++ printf("%s", config);
++ exit(0);
++}
++
++__uml_setup("--showconfig", print_config,
++"--showconfig\n"
++" Prints the config file that this UML binary was generated from.\n\n"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/exec_kern.c um/arch/um/kernel/exec_kern.c
+--- orig/arch/um/kernel/exec_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/exec_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,86 @@
++/*
++ * 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"
++#include "time_user.h"
++#include "choose-mode.h"
++#include "mode_kern.h"
++
++void flush_thread(void)
++{
++ CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
++}
++
++void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
++{
++ CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
++}
++
++extern void log_exec(char **argv, void *tty);
++
++static int execve1(char *file, char **argv, char **env)
++{
++ int error;
++
++#ifdef CONFIG_TTY_LOG
++ log_exec(argv, current->tty);
++#endif
++ 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)
++{
++ int err;
++
++ err = execve1(file, argv, env);
++ if(!err)
++ do_longjmp(current->thread.exec_buf, 1);
++ return(err);
++}
++
++int sys_execve(char *file, char **argv, char **env)
++{
++ int error;
++ char *filename;
++
++ lock_kernel();
++ filename = getname((char *) file);
++ error = PTR_ERR(filename);
++ if (IS_ERR(filename)) goto out;
++ error = execve1(filename, argv, env);
++ putname(filename);
++ out:
++ unlock_kernel();
++ return(error);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/exitcode.c um/arch/um/kernel/exitcode.c
+--- orig/arch/um/kernel/exitcode.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/exitcode.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/ctype.h"
++#include "linux/proc_fs.h"
++#include "asm/uaccess.h"
++
++/* If read and write race, the read will still atomically read a valid
++ * value.
++ */
++int uml_exitcode = 0;
++
++static int read_proc_exitcode(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", uml_exitcode);
++ len -= off;
++ if(len <= off+count) *eof = 1;
++ *start = page + off;
++ if(len > count) len = count;
++ if(len < 0) len = 0;
++ return(len);
++}
++
++static int write_proc_exitcode(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char *end, buf[sizeof("nnnnn\0")];
++ int tmp;
++
++ if(copy_from_user(buf, buffer, count))
++ return(-EFAULT);
++ tmp = simple_strtol(buf, &end, 0);
++ if((*end != '\0') && !isspace(*end))
++ return(-EINVAL);
++ uml_exitcode = tmp;
++ return(count);
++}
++
++static int make_proc_exitcode(void)
++{
++ struct proc_dir_entry *ent;
++
++ ent = create_proc_entry("exitcode", 0600, &proc_root);
++ if(ent == NULL){
++ printk("make_proc_exitcode : Failed to register "
++ "/proc/exitcode\n");
++ return(0);
++ }
++
++ ent->read_proc = read_proc_exitcode;
++ ent->write_proc = write_proc_exitcode;
++
++ return(0);
++}
++
++__initcall(make_proc_exitcode);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/frame.c um/arch/um/kernel/frame.c
+--- orig/arch/um/kernel/frame.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/frame.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,341 @@
++/*
++ * 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/syscall.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 : PTRACE_CONT 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(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
++ printf("capture_stack : Expected exit signal 9, "
++ "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);
++}
++
++struct common_raw {
++ void *stack;
++ int size;
++ unsigned long sig;
++ unsigned long sr;
++ unsigned long sp;
++ struct arch_frame_data_raw arch;
++};
++
++#define SA_RESTORER (0x04000000)
++
++typedef unsigned long old_sigset_t;
++
++struct old_sigaction {
++ __sighandler_t handler;
++ old_sigset_t sa_mask;
++ unsigned long sa_flags;
++ void (*sa_restorer)(void);
++};
++
++static void child_common(struct common_raw *common, sighandler_t handler,
++ int restorer, int flags)
++{
++ stack_t ss = ((stack_t) { .ss_sp = common->stack,
++ .ss_flags = 0,
++ .ss_size = common->size });
++ int err;
++
++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++ printf("PTRACE_TRACEME failed, errno = %d\n", errno);
++ }
++ if(sigaltstack(&ss, NULL) < 0){
++ printf("sigaltstack failed - errno = %d\n", errno);
++ kill(getpid(), SIGKILL);
++ }
++
++ if(restorer){
++ struct sigaction sa;
++
++ sa.sa_handler = handler;
++ sigemptyset(&sa.sa_mask);
++ sa.sa_flags = SA_ONSTACK | flags;
++ err = sigaction(SIGUSR1, &sa, NULL);
++ }
++ else {
++ struct old_sigaction sa;
++
++ sa.handler = handler;
++ sa.sa_mask = 0;
++ sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
++ err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
++ }
++
++ if(err < 0){
++ printf("sigaction failed - errno = %d\n", errno);
++ kill(getpid(), SIGKILL);
++ }
++
++ os_stop_process(os_getpid());
++}
++
++/* Changed only during early boot */
++struct sc_frame signal_frame_sc;
++
++struct sc_frame signal_frame_sc_sr;
++
++struct sc_frame_raw {
++ struct common_raw common;
++ unsigned long sc;
++ int restorer;
++};
++
++/* Changed only during early boot */
++static struct sc_frame_raw *raw_sc = NULL;
++
++static void sc_handler(int sig, struct sigcontext sc)
++{
++ raw_sc->common.sig = (unsigned long) &sig;
++ raw_sc->common.sr = frame_restorer();
++ raw_sc->common.sp = frame_sp();
++ raw_sc->sc = (unsigned long) ≻
++ setup_arch_frame_raw(&raw_sc->common.arch, &sc + 1, raw_sc->common.sr);
++
++ os_stop_process(os_getpid());
++ kill(getpid(), SIGKILL);
++}
++
++static int sc_child(void *arg)
++{
++ raw_sc = arg;
++ child_common(&raw_sc->common, (sighandler_t) sc_handler,
++ raw_sc->restorer, 0);
++ return(-1);
++}
++
++/* Changed only during early boot */
++struct si_frame signal_frame_si;
++
++struct si_frame_raw {
++ struct common_raw common;
++ unsigned long sip;
++ unsigned long si;
++ unsigned long ucp;
++ unsigned long uc;
++};
++
++/* Changed only during early boot */
++static struct si_frame_raw *raw_si = NULL;
++
++static void si_handler(int sig, siginfo_t *si, struct ucontext *ucontext)
++{
++ raw_si->common.sig = (unsigned long) &sig;
++ raw_si->common.sr = frame_restorer();
++ raw_si->common.sp = frame_sp();
++ raw_si->sip = (unsigned long) &si;
++ raw_si->si = (unsigned long) si;
++ raw_si->ucp = (unsigned long) &ucontext;
++ raw_si->uc = (unsigned long) ucontext;
++ setup_arch_frame_raw(&raw_si->common.arch,
++ ucontext->uc_mcontext.fpregs, raw_si->common.sr);
++
++ os_stop_process(os_getpid());
++ kill(getpid(), SIGKILL);
++}
++
++static int si_child(void *arg)
++{
++ raw_si = arg;
++ child_common(&raw_si->common, (sighandler_t) si_handler, 1,
++ SA_SIGINFO);
++ return(-1);
++}
++
++static int relative_sr(unsigned long sr, int sr_index, void *stack,
++ void *framep)
++{
++ unsigned long *srp = (unsigned long *) sr;
++ unsigned long frame = (unsigned long) framep;
++
++ if((*srp & PAGE_MASK) == (unsigned long) stack){
++ *srp -= sr;
++ *((unsigned long *) (frame + sr_index)) = *srp;
++ return(1);
++ }
++ else return(0);
++}
++
++static unsigned long capture_stack_common(int (*proc)(void *), void *arg,
++ struct common_raw *common_in,
++ void *top, void *sigstack,
++ int stack_len,
++ struct frame_common *common_out)
++{
++ unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
++
++ common_in->stack = (void *) sigstack;
++ common_in->size = stack_len;
++ common_out->len = capture_stack(proc, arg, top, sig_top,
++ &common_out->data);
++ base = sig_top - common_out->len;
++ common_out->sig_index = common_in->sig - base;
++ common_out->sp_index = common_in->sp - base;
++ common_out->sr_index = common_in->sr - base;
++ common_out->sr_relative = relative_sr(common_in->sr,
++ common_out->sr_index, sigstack,
++ common_out->data);
++ return(base);
++}
++
++void capture_signal_stack(void)
++{
++ struct sc_frame_raw raw_sc;
++ struct si_frame_raw raw_si;
++ void *stack, *sigstack;
++ unsigned long 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 *);
++
++ /* Get the sigcontext, no sigrestorer layout */
++ raw_sc.restorer = 0;
++ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
++ (void *) top, sigstack, PAGE_SIZE,
++ &signal_frame_sc.common);
++
++ signal_frame_sc.sc_index = raw_sc.sc - base;
++ setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc.common.arch);
++
++ /* Ditto for the sigcontext, sigrestorer layout */
++ raw_sc.restorer = 1;
++ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
++ (void *) top, sigstack, PAGE_SIZE,
++ &signal_frame_sc_sr.common);
++ signal_frame_sc_sr.sc_index = raw_sc.sc - base;
++ setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc_sr.common.arch);
++
++ /* And the siginfo layout */
++
++ base = capture_stack_common(si_child, &raw_si, &raw_si.common,
++ (void *) top, sigstack, PAGE_SIZE,
++ &signal_frame_si.common);
++ signal_frame_si.sip_index = raw_si.sip - base;
++ signal_frame_si.si_index = raw_si.si - base;
++ signal_frame_si.ucp_index = raw_si.ucp - base;
++ signal_frame_si.uc_index = raw_si.uc - base;
++ setup_arch_frame(&raw_si.common.arch, &signal_frame_si.common.arch);
++
++ if((munmap(stack, PAGE_SIZE) < 0) ||
++ (munmap(sigstack, PAGE_SIZE) < 0)){
++ printf("capture_signal_stack : munmap failed - errno = %d\n",
++ errno);
++ exit(1);
++ }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/frame_kern.c um/arch/um/kernel/frame_kern.c
+--- orig/arch/um/kernel/frame_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/frame_kern.c 2003-11-19 03:32:43.000000000 -0500
+@@ -0,0 +1,174 @@
++/*
++ * 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 "asm/uaccess.h"
++#include "asm/ucontext.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "sysdep/ptrace.h"
++#include "choose-mode.h"
++#include "mode.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)
++{
++ unsigned long sr;
++
++ if(sr_relative){
++ sr = (unsigned long) restorer;
++ sr += start + sr_index;
++ restorer = (void (*)(void)) sr;
++ }
++
++ return(copy_to_user((void *) (start + sr_index), &restorer,
++ sizeof(restorer)));
++}
++
++extern int userspace_pid[];
++
++static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from,
++ struct arch_frame_data *arch)
++{
++ return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
++ arch),
++ copy_sc_to_user_skas(userspace_pid[0], to, fp,
++ &from->regs,
++ current->thread.cr2,
++ current->thread.err)));
++}
++
++static int copy_ucontext_to_user(struct ucontext *uc, void *fp, sigset_t *set,
++ unsigned long sp)
++{
++ int err = 0;
++
++ err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
++ err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
++ err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
++ err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs,
++ &signal_frame_si.common.arch);
++ err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
++ return(err);
++}
++
++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;
++ void *sip, *ucp, *fp;
++
++ start = stack_top - signal_frame_si.common.len;
++ sip = (void *) (start + signal_frame_si.si_index);
++ ucp = (void *) (start + signal_frame_si.uc_index);
++ fp = (void *) (((unsigned long) ucp) + sizeof(struct ucontext));
++
++ if(restorer == NULL)
++ panic("setup_signal_stack_si - no restorer");
++
++ if(copy_to_user((void *) start, signal_frame_si.common.data,
++ signal_frame_si.common.len) ||
++ copy_to_user((void *) (start + signal_frame_si.common.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_ucontext_to_user(ucp, fp, mask, PT_REGS_SP(regs)) ||
++ copy_to_user((void *) (start + signal_frame_si.ucp_index), &ucp,
++ sizeof(ucp)) ||
++ copy_restorer(restorer, start, signal_frame_si.common.sr_index,
++ signal_frame_si.common.sr_relative))
++ return(1);
++
++ PT_REGS_IP(regs) = handler;
++ PT_REGS_SP(regs) = start + signal_frame_si.common.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)
++{
++ struct frame_common *frame = &signal_frame_sc_sr.common;
++ void *user_sc;
++ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
++ unsigned long sigs, sr;
++ unsigned long start = stack_top - frame->len - sig_size;
++
++ user_sc = (void *) (start + signal_frame_sc_sr.sc_index);
++ if(restorer == NULL){
++ frame = &signal_frame_sc.common;
++ user_sc = (void *) (start + signal_frame_sc.sc_index);
++ sr = (unsigned long) frame->data;
++ sr += frame->sr_index;
++ sr = *((unsigned long *) sr);
++ restorer = ((void (*)(void)) sr);
++ }
++
++ sigs = start + frame->len;
++ if(copy_to_user((void *) start, frame->data, frame->len) ||
++ copy_to_user((void *) (start + frame->sig_index), &sig,
++ sizeof(sig)) ||
++ copy_sc_to_user(user_sc, NULL, regs,
++ &signal_frame_sc.common.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, frame->sr_index, frame->sr_relative))
++ return(1);
++
++ PT_REGS_IP(regs) = handler;
++ PT_REGS_SP(regs) = start + frame->sp_index;
++
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/gmon_syms.c um/arch/um/kernel/gmon_syms.c
+--- orig/arch/um/kernel/gmon_syms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/gmon_syms.c 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/gprof_syms.c um/arch/um/kernel/gprof_syms.c
+--- orig/arch/um/kernel/gprof_syms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/gprof_syms.c 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/helper.c um/arch/um/kernel/helper.c
+--- orig/arch/um/kernel/helper.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/helper.c 2003-11-08 07:41:30.000000000 -0500
+@@ -0,0 +1,170 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sched.h>
++#include <sys/signal.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "kern_util.h"
++#include "os.h"
++
++struct helper_data {
++ void (*pre_exec)(void*);
++ void *pre_data;
++ char **argv;
++ int fd;
++};
++
++/* Debugging aid, changed only from gdb */
++int helper_pause = 0;
++
++static void helper_hup(int sig)
++{
++}
++
++static int helper_child(void *arg)
++{
++ struct helper_data *data = arg;
++ char **argv = data->argv;
++ int errval;
++
++ if(helper_pause){
++ signal(SIGHUP, helper_hup);
++ pause();
++ }
++ if(data->pre_exec != NULL)
++ (*data->pre_exec)(data->pre_data);
++ execvp(argv[0], argv);
++ errval = errno;
++ printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
++ os_write_file(data->fd, &errval, sizeof(errval));
++ os_kill_process(os_getpid(), 0);
++ return(0);
++}
++
++/* XXX The alloc_stack here breaks if this is called in the tracing thread */
++
++int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
++ unsigned long *stack_out)
++{
++ struct helper_data data;
++ unsigned long stack, sp;
++ int pid, fds[2], 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 < 0){
++ printk("run_helper : pipe failed, err = %d\n", -err);
++ goto out_free;
++ }
++
++ err = os_set_exec_close(fds[1], 1);
++ if(err < 0){
++ printk("run_helper : setting FD_CLOEXEC failed, err = %d\n",
++ -err);
++ goto out_close;
++ }
++
++ sp = stack + page_size() - sizeof(void *);
++ data.pre_exec = pre_exec;
++ data.pre_data = pre_data;
++ data.argv = argv;
++ data.fd = fds[1];
++ pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
++ if(pid < 0){
++ printk("run_helper : clone failed, errno = %d\n", errno);
++ err = -errno;
++ goto out_close;
++ }
++
++ os_close_file(fds[1]);
++ n = os_read_file(fds[0], &err, sizeof(err));
++ if(n < 0){
++ printk("run_helper : read on pipe failed, err = %d\n", -n);
++ err = n;
++ goto out_kill;
++ }
++ else if(n != 0){
++ waitpid(pid, NULL, 0);
++ pid = -errno;
++ }
++
++ if(stack_out == NULL) free_stack(stack, 0);
++ else *stack_out = stack;
++ return(pid);
++
++ out_kill:
++ os_kill_process(pid, 1);
++ out_close:
++ os_close_file(fds[0]);
++ os_close_file(fds[1]);
++ out_free:
++ free_stack(stack, 0);
++ return(err);
++}
++
++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",
++ errno);
++ pid = -errno;
++ }
++ if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
++ printk("run_helper_thread - thread returned status "
++ "0x%x\n", status);
++ free_stack(stack, stack_order);
++ }
++ else *stack_out = stack;
++ return(pid);
++}
++
++int helper_wait(int pid, int block)
++{
++ int ret;
++
++ ret = waitpid(pid, NULL, WNOHANG);
++ if(ret < 0){
++ printk("helper_wait : waitpid failed, errno = %d\n", errno);
++ return(-errno);
++ }
++ return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/initrd_kern.c um/arch/um/kernel/initrd_kern.c
+--- orig/arch/um/kernel/initrd_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/initrd_kern.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/blk.h"
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "initrd.h"
++#include "init.h"
++#include "os.h"
++
++/* Changed by uml_initrd_setup, which is a setup */
++static char *initrd __initdata = NULL;
++
++static int __init read_initrd(void)
++{
++ void *area;
++ long long size;
++ int err;
++
++ if(initrd == NULL) return 0;
++ err = os_file_size(initrd, &size);
++ if(err) return 0;
++ area = alloc_bootmem(size);
++ if(area == NULL) return 0;
++ if(load_initrd(initrd, area, size) == -1) return 0;
++ initrd_start = (unsigned long) area;
++ initrd_end = initrd_start + size;
++ return 0;
++}
++
++__uml_postsetup(read_initrd);
++
++static int __init uml_initrd_setup(char *line, int *add)
++{
++ initrd = line;
++ return 0;
++}
++
++__uml_setup("initrd=", uml_initrd_setup,
++"initrd=<initrd image>\n"
++" This is used to boot UML from an initrd image. The argument is the\n"
++" name of the file containing the image.\n\n"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/initrd_user.c um/arch/um/kernel/initrd_user.c
+--- orig/arch/um/kernel/initrd_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/initrd_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <errno.h>
++
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "initrd.h"
++#include "os.h"
++
++int load_initrd(char *filename, void *buf, int size)
++{
++ int fd, n;
++
++ fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
++ if(fd < 0){
++ printk("Opening '%s' failed - err = %d\n", filename, -fd);
++ return(-1);
++ }
++ n = os_read_file(fd, buf, size);
++ if(n != size){
++ printk("Read of %d bytes from '%s' failed, err = %d\n", size,
++ filename, -n);
++ return(-1);
++ }
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/init_task.c um/arch/um/kernel/init_task.c
+--- orig/arch/um/kernel/init_task.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/init_task.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "linux/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)
++{
++ return((struct task_struct *)
++ __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER));
++}
++
++void unprotect_stack(unsigned long stack)
++{
++ protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * 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, CONFIG_KERNEL_STACK_ORDER);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/irq.c um/arch/um/kernel/irq.c
+--- orig/arch/um/kernel/irq.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/irq.c 2003-12-16 22:45:27.000000000 -0500
+@@ -0,0 +1,840 @@
++/*
++ * 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"
++#include "irq_kern.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
++};
++
++/*
++ * Generic, controller-independent functions:
++ */
++
++int get_irq_list(char *buf)
++{
++ int i, j;
++ unsigned long flags;
++ 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++) {
++ spin_lock_irqsave(&irq_desc[i].lock, flags);
++ action = irq_desc[i].action;
++ if (!action)
++ goto end;
++ 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';
++ end:
++ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
++ }
++ 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", 0L);
++ 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, union 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 err;
++
++ err = request_irq(irq, handler, irqflags, devname, dev_id);
++ if(err)
++ return(err);
++
++ if(fd != -1)
++ err = activate_fd(irq, fd, type, dev_id);
++ return(err);
++}
++
++/* 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;
++ old = *p;
++ if (old != 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;
++ }
++}
++
++/* These are initialized by sysctl_init, which is called from init/main.c */
++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];
++
++/* These are read and written as longs, so a read won't see a partial write
++ * even during a race.
++ */
++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 HEX_DIGITS 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;
++}
++
++/* Read and written as a long */
++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);
++}
++
++static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED;
++
++unsigned long irq_lock(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&irq_spinlock, flags);
++ return(flags);
++}
++
++void irq_unlock(unsigned long flags)
++{
++ spin_unlock_irqrestore(&irq_spinlock, flags);
++}
++
++unsigned long probe_irq_on(void)
++{
++ return(0);
++}
++
++int probe_irq_off(unsigned long val)
++{
++ return(0);
++}
++
++static unsigned int startup_SIGIO_irq(unsigned int irq)
++{
++ return(0);
++}
++
++static void shutdown_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGIO(unsigned int irq)
++{
++}
++
++static void end_SIGIO_irq(unsigned int irq)
++{
++}
++
++static unsigned int startup_SIGVTALRM_irq(unsigned int irq)
++{
++ return(0);
++}
++
++static void shutdown_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGVTALRM(unsigned int irq)
++{
++}
++
++static void end_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static struct hw_interrupt_type SIGIO_irq_type = {
++ "SIGIO",
++ startup_SIGIO_irq,
++ shutdown_SIGIO_irq,
++ enable_SIGIO_irq,
++ disable_SIGIO_irq,
++ mask_and_ack_SIGIO,
++ end_SIGIO_irq,
++ NULL
++};
++
++static struct hw_interrupt_type SIGVTALRM_irq_type = {
++ "SIGVTALRM",
++ startup_SIGVTALRM_irq,
++ shutdown_SIGVTALRM_irq,
++ enable_SIGVTALRM_irq,
++ disable_SIGVTALRM_irq,
++ mask_and_ack_SIGVTALRM,
++ end_SIGVTALRM_irq,
++ NULL
++};
++
++void __init init_IRQ(void)
++{
++ int i;
++
++ irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
++ irq_desc[TIMER_IRQ].action = 0;
++ irq_desc[TIMER_IRQ].depth = 1;
++ irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
++ enable_irq(TIMER_IRQ);
++ for(i=1;i<NR_IRQS;i++){
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = 0;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &SIGIO_irq_type;
++ enable_irq(i);
++ }
++ init_irq_signals(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/irq_user.c um/arch/um/kernel/irq_user.c
+--- orig/arch/um/kernel/irq_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/irq_user.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,424 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++#include <string.h>
++#include <sys/poll.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++#include "sigio.h"
++#include "irq_user.h"
++#include "os.h"
++
++struct irq_fd {
++ struct irq_fd *next;
++ void *id;
++ int fd;
++ int type;
++ int irq;
++ int pid;
++ int events;
++ int current_events;
++ int freed;
++};
++
++static struct irq_fd *active_fds = NULL;
++static struct irq_fd **last_irq_ptr = &active_fds;
++
++static struct pollfd *pollfds = NULL;
++static int pollfds_num = 0;
++static int pollfds_size = 0;
++
++extern int io_count, intr_count;
++
++void sigio_handler(int sig, union uml_pt_regs *regs)
++{
++ struct irq_fd *irq_fd, *next;
++ int i, n;
++
++ if(smp_sigio_handler()) return;
++ while(1){
++ n = poll(pollfds, pollfds_num, 0);
++ if(n < 0){
++ if(errno == EINTR) continue;
++ printk("sigio_handler : poll returned %d, "
++ "errno = %d\n", n, errno);
++ break;
++ }
++ if(n == 0) break;
++
++ irq_fd = active_fds;
++ for(i = 0; i < pollfds_num; i++){
++ if(pollfds[i].revents != 0){
++ irq_fd->current_events = pollfds[i].revents;
++ pollfds[i].fd = -1;
++ }
++ irq_fd = irq_fd->next;
++ }
++
++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
++ next = irq_fd->next;
++ if(irq_fd->current_events != 0){
++ irq_fd->current_events = 0;
++ do_IRQ(irq_fd->irq, regs);
++
++ /* This is here because the next irq may be
++ * freed in the handler. If a console goes
++ * away, both the read and write irqs will be
++ * freed. After do_IRQ, ->next will point to
++ * a good IRQ.
++ * Irqs can't be freed inside their handlers,
++ * so the next best thing is to have them
++ * marked as needing freeing, so that they
++ * can be freed here.
++ */
++ next = irq_fd->next;
++ if(irq_fd->freed)
++ free_irq(irq_fd->irq, irq_fd->id);
++ }
++ }
++ }
++}
++
++int activate_ipi(int fd, int pid)
++{
++ return(os_set_fd_async(fd, pid));
++}
++
++static void maybe_sigio_broken(int fd, int type)
++{
++ if(isatty(fd)){
++ if((type == IRQ_WRITE) && !pty_output_sigio){
++ write_sigio_workaround();
++ add_sigio_fd(fd, 0);
++ }
++ else if((type == IRQ_READ) && !pty_close_sigio){
++ write_sigio_workaround();
++ add_sigio_fd(fd, 1);
++ }
++ }
++}
++
++int activate_fd(int irq, int fd, int type, void *dev_id)
++{
++ struct pollfd *tmp_pfd;
++ struct irq_fd *new_fd, *irq_fd;
++ unsigned long flags;
++ int pid, events, err, n, size;
++
++ pid = os_getpid();
++ err = os_set_fd_async(fd, pid);
++ if(err < 0)
++ goto out;
++
++ new_fd = um_kmalloc(sizeof(*new_fd));
++ err = -ENOMEM;
++ if(new_fd == NULL)
++ goto out;
++
++ if(type == IRQ_READ) events = POLLIN | POLLPRI;
++ else events = POLLOUT;
++ *new_fd = ((struct irq_fd) { .next = NULL,
++ .id = dev_id,
++ .fd = fd,
++ .type = type,
++ .irq = irq,
++ .pid = pid,
++ .events = events,
++ .current_events = 0,
++ .freed = 0 } );
++
++ /* Critical section - locked by a spinlock because this stuff can
++ * be changed from interrupt handlers. The stuff above is done
++ * outside the lock because it allocates memory.
++ */
++
++ /* Actually, it only looks like it can be called from interrupt
++ * context. The culprit is reactivate_fd, which calls
++ * maybe_sigio_broken, which calls write_sigio_workaround,
++ * which calls activate_fd. However, write_sigio_workaround should
++ * only be called once, at boot time. That would make it clear that
++ * this is called only from process context, and can be locked with
++ * a semaphore.
++ */
++ flags = irq_lock();
++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
++ if((irq_fd->fd == fd) && (irq_fd->type == type)){
++ printk("Registering fd %d twice\n", fd);
++ printk("Irqs : %d, %d\n", irq_fd->irq, irq);
++ printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
++ goto out_unlock;
++ }
++ }
++
++ n = pollfds_num;
++ if(n == pollfds_size){
++ while(1){
++ /* Here we have to drop the lock in order to call
++ * kmalloc, which might sleep. If something else
++ * came in and changed the pollfds array, we free
++ * the buffer and try again.
++ */
++ irq_unlock(flags);
++ size = (pollfds_num + 1) * sizeof(pollfds[0]);
++ tmp_pfd = um_kmalloc(size);
++ flags = irq_lock();
++ if(tmp_pfd == NULL)
++ goto out_unlock;
++ if(n == pollfds_size)
++ break;
++ kfree(tmp_pfd);
++ }
++ if(pollfds != NULL){
++ memcpy(tmp_pfd, pollfds,
++ sizeof(pollfds[0]) * pollfds_size);
++ kfree(pollfds);
++ }
++ pollfds = tmp_pfd;
++ pollfds_size++;
++ }
++
++ if(type == IRQ_WRITE)
++ fd = -1;
++
++ pollfds[pollfds_num] = ((struct pollfd) { .fd = fd,
++ .events = events,
++ .revents = 0 });
++ pollfds_num++;
++
++ *last_irq_ptr = new_fd;
++ last_irq_ptr = &new_fd->next;
++
++ irq_unlock(flags);
++
++ /* This calls activate_fd, so it has to be outside the critical
++ * section.
++ */
++ maybe_sigio_broken(fd, type);
++
++ return(0);
++
++ out_unlock:
++ irq_unlock(flags);
++ kfree(new_fd);
++ out:
++ return(err);
++}
++
++static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
++{
++ struct irq_fd **prev;
++ unsigned long flags;
++ int i = 0;
++
++ flags = irq_lock();
++ prev = &active_fds;
++ while(*prev != NULL){
++ if((*test)(*prev, arg)){
++ struct irq_fd *old_fd = *prev;
++ if((pollfds[i].fd != -1) &&
++ (pollfds[i].fd != (*prev)->fd)){
++ printk("free_irq_by_cb - mismatch between "
++ "active_fds and pollfds, fd %d vs %d\n",
++ (*prev)->fd, pollfds[i].fd);
++ goto out;
++ }
++ memcpy(&pollfds[i], &pollfds[i + 1],
++ (pollfds_num - i - 1) * sizeof(pollfds[0]));
++ pollfds_num--;
++ if(last_irq_ptr == &old_fd->next)
++ last_irq_ptr = prev;
++ *prev = (*prev)->next;
++ if(old_fd->type == IRQ_WRITE)
++ ignore_sigio_fd(old_fd->fd);
++ kfree(old_fd);
++ continue;
++ }
++ prev = &(*prev)->next;
++ i++;
++ }
++ out:
++ irq_unlock(flags);
++}
++
++struct irq_and_dev {
++ int irq;
++ void *dev;
++};
++
++static int same_irq_and_dev(struct irq_fd *irq, void *d)
++{
++ struct irq_and_dev *data = d;
++
++ return((irq->irq == data->irq) && (irq->id == data->dev));
++}
++
++void free_irq_by_irq_and_dev(int irq, void *dev)
++{
++ struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
++ .dev = dev });
++
++ free_irq_by_cb(same_irq_and_dev, &data);
++}
++
++static int same_fd(struct irq_fd *irq, void *fd)
++{
++ return(irq->fd == *((int *) fd));
++}
++
++void free_irq_by_fd(int fd)
++{
++ free_irq_by_cb(same_fd, &fd);
++}
++
++static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
++{
++ struct irq_fd *irq;
++ int i = 0;
++
++ for(irq=active_fds; irq != NULL; irq = irq->next){
++ if((irq->fd == fd) && (irq->irq == irqnum)) break;
++ i++;
++ }
++ if(irq == NULL){
++ printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
++ goto out;
++ }
++ if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
++ printk("find_irq_by_fd - mismatch between active_fds and "
++ "pollfds, fd %d vs %d, need %d\n", irq->fd,
++ pollfds[i].fd, fd);
++ irq = NULL;
++ goto out;
++ }
++ *index_out = i;
++ out:
++ return(irq);
++}
++
++void free_irq_later(int irq, void *dev_id)
++{
++ struct irq_fd *irq_fd;
++ unsigned long flags;
++
++ flags = irq_lock();
++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
++ if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
++ break;
++ }
++ if(irq_fd == NULL){
++ printk("free_irq_later found no irq, irq = %d, "
++ "dev_id = 0x%p\n", irq, dev_id);
++ goto out;
++ }
++ irq_fd->freed = 1;
++ out:
++ irq_unlock(flags);
++}
++
++void reactivate_fd(int fd, int irqnum)
++{
++ struct irq_fd *irq;
++ unsigned long flags;
++ int i;
++
++ flags = irq_lock();
++ irq = find_irq_by_fd(fd, irqnum, &i);
++ if(irq == NULL){
++ irq_unlock(flags);
++ return;
++ }
++
++ pollfds[i].fd = irq->fd;
++
++ irq_unlock(flags);
++
++ /* This calls activate_fd, so it has to be outside the critical
++ * section.
++ */
++ maybe_sigio_broken(fd, irq->type);
++}
++
++void deactivate_fd(int fd, int irqnum)
++{
++ struct irq_fd *irq;
++ unsigned long flags;
++ int i;
++
++ flags = irq_lock();
++ irq = find_irq_by_fd(fd, irqnum, &i);
++ if(irq == NULL)
++ goto out;
++ pollfds[i].fd = -1;
++ out:
++ irq_unlock(flags);
++}
++
++void forward_ipi(int fd, int pid)
++{
++ int err;
++
++ err = os_set_owner(fd, pid);
++ if(err < 0)
++ printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
++ "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
++}
++
++void forward_interrupts(int pid)
++{
++ struct irq_fd *irq;
++ unsigned long flags;
++ int err;
++
++ flags = irq_lock();
++ for(irq=active_fds;irq != NULL;irq = irq->next){
++ err = os_set_owner(irq->fd, pid);
++ if(err < 0){
++ /* XXX Just remove the irq rather than
++ * print out an infinite stream of these
++ */
++ printk("Failed to forward %d to pid %d, err = %d\n",
++ irq->fd, pid, -err);
++ }
++
++ irq->pid = pid;
++ }
++ irq_unlock(flags);
++}
++
++void init_irq_signals(int on_sigstack)
++{
++ __sighandler_t h;
++ int flags;
++
++ flags = on_sigstack ? SA_ONSTACK : 0;
++ if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
++ else h = boot_timer_handler;
++
++ set_handler(SIGVTALRM, h, flags | SA_RESTART,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
++ set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ signal(SIGWINCH, SIG_IGN);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/ksyms.c um/arch/um/kernel/ksyms.c
+--- orig/arch/um/kernel/ksyms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/ksyms.c 2004-01-23 00:44:09.000000000 -0500
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/module.h"
++#include "linux/string.h"
++#include "linux/smp_lock.h"
++#include "linux/spinlock.h"
++#include "asm/current.h"
++#include "asm/delay.h"
++#include "asm/processor.h"
++#include "asm/unistd.h"
++#include "asm/pgalloc.h"
++#include "asm/pgtable.h"
++#include "asm/page.h"
++#include "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(get_signals);
++EXPORT_SYMBOL(kernel_thread);
++EXPORT_SYMBOL(__const_udelay);
++EXPORT_SYMBOL(__udelay);
++EXPORT_SYMBOL(sys_waitpid);
++EXPORT_SYMBOL(task_size);
++EXPORT_SYMBOL(flush_tlb_range);
++EXPORT_SYMBOL(host_task_size);
++EXPORT_SYMBOL(arch_validate);
++EXPORT_SYMBOL(get_kmem_end);
++
++EXPORT_SYMBOL(high_physmem);
++EXPORT_SYMBOL(empty_zero_page);
++EXPORT_SYMBOL(um_virt_to_phys);
++EXPORT_SYMBOL(__virt_to_page);
++EXPORT_SYMBOL(to_phys);
++EXPORT_SYMBOL(to_virt);
++EXPORT_SYMBOL(mode_tt);
++EXPORT_SYMBOL(handle_page_fault);
++
++#ifdef CONFIG_MODE_TT
++EXPORT_SYMBOL(copy_from_user_tt);
++EXPORT_SYMBOL(copy_to_user_tt);
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++EXPORT_SYMBOL(copy_to_user_skas);
++EXPORT_SYMBOL(copy_from_user_skas);
++#endif
++
++EXPORT_SYMBOL(os_stat_fd);
++EXPORT_SYMBOL(os_stat_file);
++EXPORT_SYMBOL(os_access);
++EXPORT_SYMBOL(os_print_error);
++EXPORT_SYMBOL(os_get_exec_close);
++EXPORT_SYMBOL(os_set_exec_close);
++EXPORT_SYMBOL(os_getpid);
++EXPORT_SYMBOL(os_open_file);
++EXPORT_SYMBOL(os_read_file);
++EXPORT_SYMBOL(os_write_file);
++EXPORT_SYMBOL(os_seek_file);
++EXPORT_SYMBOL(os_lock_file);
++EXPORT_SYMBOL(os_pipe);
++EXPORT_SYMBOL(os_file_type);
++EXPORT_SYMBOL(os_file_mode);
++EXPORT_SYMBOL(os_file_size);
++EXPORT_SYMBOL(os_flush_stdout);
++EXPORT_SYMBOL(os_close_file);
++EXPORT_SYMBOL(os_set_fd_async);
++EXPORT_SYMBOL(os_set_fd_block);
++EXPORT_SYMBOL(helper_wait);
++EXPORT_SYMBOL(os_shutdown_socket);
++EXPORT_SYMBOL(os_create_unix_socket);
++EXPORT_SYMBOL(os_connect_socket);
++EXPORT_SYMBOL(os_accept_connection);
++EXPORT_SYMBOL(os_ioctl_generic);
++EXPORT_SYMBOL(os_rcv_fd);
++EXPORT_SYMBOL(run_helper);
++EXPORT_SYMBOL(start_thread);
++EXPORT_SYMBOL(dump_thread);
++
++/* This is here because UML expands open to sys_open, not to a system
++ * call instruction.
++ */
++EXPORT_SYMBOL(sys_open);
++EXPORT_SYMBOL(sys_lseek);
++EXPORT_SYMBOL(sys_read);
++EXPORT_SYMBOL(sys_wait4);
++
++#ifdef CONFIG_SMP
++
++/* required for SMP */
++
++extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
++EXPORT_SYMBOL_NOVERS(__write_lock_failed);
++
++extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
++EXPORT_SYMBOL_NOVERS(__read_lock_failed);
++
++EXPORT_SYMBOL(kernel_flag_cacheline);
++EXPORT_SYMBOL(smp_num_cpus);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/Makefile um/arch/um/kernel/Makefile
+--- orig/arch/um/kernel/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/Makefile 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,73 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.o
++
++obj-y = config.o checksum.o exec_kern.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 \
++ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
++ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
++ syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \
++ time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \
++ um_arch.o umid.o user_syms.o user_util.o
++
++obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
++obj-$(CONFIG_GPROF) += gprof_syms.o
++obj-$(CONFIG_GCOV) += gmon_syms.o
++obj-$(CONFIG_TTY_LOG) += tty_log.o
++
++subdir-$(CONFIG_MODE_TT) += tt
++subdir-$(CONFIG_MODE_SKAS) += skas
++
++user-objs-$(CONFIG_TTY_LOG) += tty_log.o
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++# 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)) $(user-objs-y) config.o helper.o \
++ process.o tempfile.o time.o umid.o user_util.o
++
++DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__
++DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__
++
++export-objs-$(CONFIG_GPROF) += gprof_syms.o
++export-objs-$(CONFIG_GCOV) += gmon_syms.o
++
++export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o $(export-objs-y)
++
++CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
++ -I/usr/include -I../include
++
++CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++# This has to be separate because it needs be compiled with frame pointers
++# regardless of how the rest of the kernel is built.
++
++frame.o: frame.c
++ $(CC) $(CFLAGS_$@) -c -o $@ $<
++
++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
++
++config.c : config.c.in $(TOPDIR)/.config
++ $(PERL) -e $(QUOTE) < config.c.in > $@
++
++clean:
++ $(RM) config.c
++ for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper: clean
+diff -Naur -X ../exclude-files orig/arch/um/kernel/mem.c um/arch/um/kernel/mem.c
+--- orig/arch/um/kernel/mem.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/mem.c 2003-12-22 01:25:00.000000000 -0500
+@@ -0,0 +1,336 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/mm.h"
++#include "linux/bootmem.h"
++#include "linux/highmem.h"
++#include "asm/page.h"
++#include "asm/fixmap.h"
++#include "asm/pgalloc.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mem_user.h"
++#include "uml_uaccess.h"
++#include "os.h"
++
++extern char __binary_start;
++
++/* Changed during early boot */
++unsigned long *empty_zero_page = NULL;
++unsigned long *empty_bad_page = NULL;
++pgd_t swapper_pg_dir[1024];
++unsigned long highmem;
++int kmalloc_ok = 0;
++
++static unsigned long brk_end;
++static unsigned long totalram_pages = 0;
++
++void unmap_physmem(void)
++{
++ os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
++}
++
++static void map_cb(void *unused)
++{
++ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
++}
++
++#ifdef CONFIG_HIGHMEM
++static void setup_highmem(unsigned long highmem_start,
++ unsigned long highmem_len)
++{
++ struct page *page;
++ unsigned long highmem_pfn;
++ int i;
++
++ highmem_start_page = virt_to_page(highmem_start);
++
++ highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
++ for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
++ page = &mem_map[highmem_pfn + i];
++ ClearPageReserved(page);
++ set_bit(PG_highmem, &page->flags);
++ atomic_set(&page->count, 1);
++ __free_page(page);
++ }
++}
++#endif
++
++void mem_init(void)
++{
++ unsigned long start;
++
++ /* clear the zero-page */
++ memset((void *) empty_zero_page, 0, PAGE_SIZE);
++
++ /* Map in the area just after the brk now that kmalloc is about
++ * to be turned on.
++ */
++ brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
++ map_cb(NULL);
++ initial_thread_cb(map_cb, NULL);
++ free_bootmem(__pa(brk_end), uml_reserved - brk_end);
++ uml_reserved = brk_end;
++
++ /* Fill in any hole at the start of the binary */
++ start = (unsigned long) &__binary_start;
++ if(uml_physmem != start){
++ map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
++ 1, 1, 0);
++ }
++
++ /* this will put all low memory onto the freelists */
++ totalram_pages = free_all_bootmem();
++ totalram_pages += highmem >> PAGE_SHIFT;
++ num_physpages = totalram_pages;
++ printk(KERN_INFO "Memory: %luk available\n",
++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
++ kmalloc_ok = 1;
++
++#ifdef CONFIG_HIGHMEM
++ setup_highmem(end_iomem, highmem);
++#endif
++}
++
++static void __init fixrange_init(unsigned long start, unsigned long end,
++ pgd_t *pgd_base)
++{
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ int i, j;
++ unsigned long vaddr;
++
++ vaddr = start;
++ i = __pgd_offset(vaddr);
++ j = __pmd_offset(vaddr);
++ pgd = pgd_base + i;
++
++ for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
++ pmd = (pmd_t *)pgd;
++ for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
++ if (pmd_none(*pmd)) {
++ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++ set_pmd(pmd, __pmd(_KERNPG_TABLE +
++ (unsigned long) __pa(pte)));
++ if (pte != pte_offset(pmd, 0))
++ BUG();
++ }
++ vaddr += PMD_SIZE;
++ }
++ j = 0;
++ }
++}
++
++#ifdef CONFIG_HIGHMEM
++pte_t *kmap_pte;
++pgprot_t kmap_prot;
++
++#define kmap_get_fixmap_pte(vaddr) \
++ pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
++
++void __init kmap_init(void)
++{
++ unsigned long kmap_vstart;
++
++ /* cache the first kmap pte */
++ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
++ kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
++
++ kmap_prot = PAGE_KERNEL;
++}
++
++static void init_highmem(void)
++{
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ unsigned long vaddr;
++
++ /*
++ * Permanent kmaps:
++ */
++ vaddr = PKMAP_BASE;
++ fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
++
++ pgd = swapper_pg_dir + __pgd_offset(vaddr);
++ pmd = pmd_offset(pgd, vaddr);
++ pte = pte_offset(pmd, vaddr);
++ pkmap_page_table = pte;
++
++ kmap_init();
++}
++
++#endif /* CONFIG_HIGHMEM */
++
++void paging_init(void)
++{
++ unsigned long zones_size[MAX_NR_ZONES], vaddr;
++ int i;
++
++ empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
++ empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
++ for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
++ zones_size[i] = 0;
++ zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
++ zones_size[2] = highmem >> PAGE_SHIFT;
++ free_area_init(zones_size);
++
++ /*
++ * Fixed mappings, only the page table structure has to be
++ * created - mappings will be set by set_fixmap():
++ */
++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
++ fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
++
++#if CONFIG_HIGHMEM
++ init_highmem();
++#endif
++}
++
++struct page *arch_validate(struct page *page, int mask, int order)
++{
++ unsigned long addr, zero = 0;
++ int i;
++
++ again:
++ if(page == NULL) return(page);
++ if(PageHighMem(page)) return(page);
++
++ addr = (unsigned long) page_address(page);
++ for(i = 0; i < (1 << order); i++){
++ current->thread.fault_addr = (void *) addr;
++ if(__do_copy_to_user((void *) 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;
++}
++
++/* 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();
++}
++
++/* Changed by meminfo_compat, which is a setup */
++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 = highmem >> PAGE_SHIFT;
++ val->freehigh = nr_free_highpages();
++ val->mem_unit = PAGE_SIZE;
++ if(meminfo_22){
++ val->freeram <<= PAGE_SHIFT;
++ val->bufferram <<= PAGE_SHIFT;
++ val->totalram <<= PAGE_SHIFT;
++ val->sharedram <<= PAGE_SHIFT;
++ }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/mem_user.c um/arch/um/kernel/mem_user.c
+--- orig/arch/um/kernel/mem_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/mem_user.c 2004-01-10 00:19:09.000000000 -0500
+@@ -0,0 +1,216 @@
++/*
++ * arch/um/kernel/mem_user.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ * user side memory routines for supporting IO memory inside user mode linux
++ *
++ * Copyright (C) 2001 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/mman.h>
++#include "kern_util.h"
++#include "user.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "init.h"
++#include "os.h"
++#include "tempfile.h"
++#include "kern_constants.h"
++
++extern struct mem_region physmem_region;
++
++#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
++
++static int create_tmp_file(unsigned long len)
++{
++ int fd, err;
++ char zero;
++
++ fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
++ if(fd < 0) {
++ os_print_error(fd, "make_tempfile");
++ exit(1);
++ }
++
++ err = os_mode_fd(fd, 0777);
++ if(err < 0){
++ os_print_error(err, "os_mode_fd");
++ exit(1);
++ }
++ err = os_seek_file(fd, len);
++ if(err < 0){
++ os_print_error(err, "os_seek_file");
++ exit(1);
++ }
++ zero = 0;
++ err = os_write_file(fd, &zero, 1);
++ if(err != 1){
++ os_print_error(err, "os_write_file");
++ exit(1);
++ }
++
++ return(fd);
++}
++
++static int have_devanon(void)
++{
++ int fd;
++
++ printk("Checking for /dev/anon on the host...");
++ fd = open("/dev/anon", O_RDWR);
++ if(fd < 0){
++ printk("Not available (open failed with errno %d)\n", errno);
++ return(0);
++ }
++
++ printk("OK\n");
++ return(1);
++}
++
++static int create_anon_file(unsigned long len)
++{
++ void *addr;
++ int fd;
++
++ fd = open("/dev/anon", O_RDWR);
++ if(fd < 0) {
++ os_print_error(fd, "opening /dev/anon");
++ exit(1);
++ }
++
++ addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0);
++ if(addr == MAP_FAILED){
++ os_print_error((int) addr, "mapping physmem file");
++ exit(1);
++ }
++ munmap(addr, len);
++
++ return(fd);
++}
++
++int create_mem_file(unsigned long len)
++{
++ int err, fd;
++
++ if(have_devanon())
++ fd = create_anon_file(len);
++ else fd = create_tmp_file(len);
++
++ err = os_set_exec_close(fd, 1);
++ if(err < 0)
++ os_print_error(err, "exec_close");
++ return(fd);
++}
++
++struct iomem_region *iomem_regions = NULL;
++int iomem_size = 0;
++
++static int __init parse_iomem(char *str, int *add)
++{
++ struct iomem_region *new;
++ struct uml_stat buf;
++ char *file, *driver;
++ int fd, err;
++
++ driver = str;
++ file = strchr(str,',');
++ if(file == NULL){
++ printf("parse_iomem : failed to parse iomem\n");
++ goto out;
++ }
++ *file = '\0';
++ file++;
++ fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
++ if(fd < 0){
++ os_print_error(fd, "parse_iomem - Couldn't open io file");
++ goto out;
++ }
++
++ err = os_stat_fd(fd, &buf);
++ if(err < 0){
++ os_print_error(err, "parse_iomem - cannot stat_fd file");
++ goto out_close;
++ }
++
++ new = malloc(sizeof(*new));
++ if(new == NULL){
++ perror("Couldn't allocate iomem_region struct");
++ goto out_close;
++ }
++
++ *new = ((struct iomem_region) { .next = iomem_regions,
++ .driver = driver,
++ .fd = fd,
++ .size = buf.ust_size,
++ .phys = 0,
++ .virt = 0 });
++ iomem_regions = new;
++ iomem_size += new->size + UM_KERN_PAGE_SIZE;
++
++ return(0);
++ out_close:
++ os_close_file(fd);
++ out:
++ return(1);
++}
++
++__uml_setup("iomem=", parse_iomem,
++"iomem=<name>,<file>\n"
++" Configure <file> as an IO memory region named <name>.\n\n"
++);
++
++int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
++ int must_succeed)
++{
++ int err;
++
++ err = os_protect_memory((void *) addr, len, r, w, x);
++ if(err < 0){
++ if(must_succeed)
++ panic("protect failed, err = %d", -err);
++ else return(err);
++ }
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/mprot.h um/arch/um/kernel/mprot.h
+--- orig/arch/um/kernel/mprot.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/mprot.h 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __MPROT_H__
++#define __MPROT_H__
++
++extern void no_access(unsigned long addr, unsigned int len);
++
++#endif
+diff -Naur -X ../exclude-files orig/arch/um/kernel/physmem.c um/arch/um/kernel/physmem.c
+--- orig/arch/um/kernel/physmem.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/physmem.c 2004-01-16 23:38:02.000000000 -0500
+@@ -0,0 +1,446 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/ghash.h"
++#include "linux/slab.h"
++#include "linux/vmalloc.h"
++#include "linux/bootmem.h"
++#include "asm/types.h"
++#include "asm/pgtable.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "mode_kern.h"
++#include "mem.h"
++#include "mem_user.h"
++#include "os.h"
++#include "kern.h"
++#include "init.h"
++
++#define PHYS_HASHSIZE (8192)
++
++struct phys_desc;
++
++DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
++
++struct phys_desc {
++ struct virtmem_ptrs virt_ptrs;
++ int fd;
++ __u64 offset;
++ void *virt;
++ unsigned long phys;
++ struct list_head list;
++};
++
++struct virtmem_table virtmem_hash;
++
++static int virt_cmp(void *virt1, void *virt2)
++{
++ return(virt1 != virt2);
++}
++
++static int virt_hash(void *virt)
++{
++ unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
++ return(addr % PHYS_HASHSIZE);
++}
++
++DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp,
++ virt_hash);
++
++LIST_HEAD(descriptor_mappings);
++
++struct desc_mapping {
++ int fd;
++ struct list_head list;
++ struct list_head pages;
++};
++
++static struct desc_mapping *find_mapping(int fd)
++{
++ struct desc_mapping *desc;
++ struct list_head *ele;
++
++ list_for_each(ele, &descriptor_mappings){
++ desc = list_entry(ele, struct desc_mapping, list);
++ if(desc->fd == fd)
++ return(desc);
++ }
++
++ return(NULL);
++}
++
++static struct desc_mapping *descriptor_mapping(int fd)
++{
++ struct desc_mapping *desc;
++
++ desc = find_mapping(fd);
++ if(desc != NULL)
++ return(desc);
++
++ desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
++ if(desc == NULL)
++ return(NULL);
++
++ *desc = ((struct desc_mapping)
++ { .fd = fd,
++ .list = LIST_HEAD_INIT(desc->list),
++ .pages = LIST_HEAD_INIT(desc->pages) });
++ list_add(&desc->list, &descriptor_mappings);
++
++ return(desc);
++}
++
++int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
++{
++ struct desc_mapping *fd_maps;
++ struct phys_desc *desc;
++ unsigned long phys;
++ int err;
++
++ fd_maps = descriptor_mapping(fd);
++ if(fd_maps == NULL)
++ return(-ENOMEM);
++
++ phys = __pa(virt);
++ if(find_virtmem_hash(&virtmem_hash, virt) != NULL)
++ panic("Address 0x%p is already substituted\n", virt);
++
++ err = -ENOMEM;
++ desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
++ if(desc == NULL)
++ goto out;
++
++ *desc = ((struct phys_desc)
++ { .virt_ptrs = { NULL, NULL },
++ .fd = fd,
++ .offset = offset,
++ .virt = virt,
++ .phys = __pa(virt),
++ .list = LIST_HEAD_INIT(desc->list) });
++ insert_virtmem_hash(&virtmem_hash, desc);
++
++ list_add(&desc->list, &fd_maps->pages);
++
++ virt = (void *) ((unsigned long) virt & PAGE_MASK);
++ err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
++ if(!err)
++ goto out;
++
++ remove_virtmem_hash(&virtmem_hash, desc);
++ kfree(desc);
++ out:
++ return(err);
++}
++
++static int physmem_fd = -1;
++
++static void remove_mapping(struct phys_desc *desc)
++{
++ void *virt = desc->virt;
++ int err;
++
++ remove_virtmem_hash(&virtmem_hash, desc);
++ list_del(&desc->list);
++ kfree(desc);
++
++ err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
++ if(err)
++ panic("Failed to unmap block device page from physical memory, "
++ "errno = %d", -err);
++}
++
++int physmem_remove_mapping(void *virt)
++{
++ struct phys_desc *desc;
++
++ virt = (void *) ((unsigned long) virt & PAGE_MASK);
++ desc = find_virtmem_hash(&virtmem_hash, virt);
++ if(desc == NULL)
++ return(0);
++
++ remove_mapping(desc);
++ return(1);
++}
++
++void physmem_forget_descriptor(int fd)
++{
++ struct desc_mapping *desc;
++ struct phys_desc *page;
++ struct list_head *ele, *next;
++ __u64 offset;
++ void *addr;
++ int err;
++
++ desc = find_mapping(fd);
++ if(desc == NULL)
++ return;
++
++ list_for_each_safe(ele, next, &desc->pages){
++ page = list_entry(ele, struct phys_desc, list);
++ offset = page->offset;
++ addr = page->virt;
++ remove_mapping(page);
++ err = os_seek_file(fd, offset);
++ if(err)
++ panic("physmem_forget_descriptor - failed to seek "
++ "to %lld in fd %d, error = %d\n",
++ offset, fd, -err);
++ err = os_read_file(fd, addr, PAGE_SIZE);
++ if(err < 0)
++ panic("physmem_forget_descriptor - failed to read "
++ "from fd %d to 0x%p, error = %d\n",
++ fd, addr, -err);
++ }
++
++ list_del(&desc->list);
++ kfree(desc);
++}
++
++void arch_free_page(struct page *page, int order)
++{
++ void *virt;
++ int i;
++
++ for(i = 0; i < (1 << order); i++){
++ virt = __va(page_to_phys(page + i));
++ physmem_remove_mapping(virt);
++ }
++}
++
++int is_remapped(void *virt)
++{
++ return(find_virtmem_hash(&virtmem_hash, virt) != NULL);
++}
++
++/* Changed during early boot */
++unsigned long high_physmem;
++
++extern unsigned long physmem_size;
++
++void *to_virt(unsigned long phys)
++{
++ return((void *) uml_physmem + phys);
++}
++
++unsigned long to_phys(void *virt)
++{
++ return(((unsigned long) virt) - uml_physmem);
++}
++
++int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
++{
++ struct page *p, *map;
++ unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
++ unsigned long iomem_len, iomem_pages, total_len, total_pages;
++ int i;
++
++ phys_pages = physmem >> PAGE_SHIFT;
++ phys_len = phys_pages * sizeof(struct page);
++
++ iomem_pages = iomem >> PAGE_SHIFT;
++ iomem_len = iomem_pages * sizeof(struct page);
++
++ highmem_pages = highmem >> PAGE_SHIFT;
++ highmem_len = highmem_pages * sizeof(struct page);
++
++ total_pages = phys_pages + iomem_pages + highmem_pages;
++ total_len = phys_len + iomem_pages + highmem_len;
++
++ if(kmalloc_ok){
++ map = kmalloc(total_len, GFP_KERNEL);
++ if(map == NULL)
++ map = vmalloc(total_len);
++ }
++ else map = alloc_bootmem_low_pages(total_len);
++
++ if(map == NULL)
++ return(-ENOMEM);
++
++ for(i = 0; i < total_pages; i++){
++ p = &map[i];
++ set_page_count(p, 0);
++ SetPageReserved(p);
++ INIT_LIST_HEAD(&p->list);
++ }
++
++ mem_map = map;
++ max_mapnr = total_pages;
++ return(0);
++}
++
++struct page *phys_to_page(const unsigned long phys)
++{
++ return(&mem_map[phys >> PAGE_SHIFT]);
++}
++
++struct page *__virt_to_page(const unsigned long virt)
++{
++ return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
++}
++
++unsigned long page_to_phys(struct page *page)
++{
++ return((page - mem_map) << PAGE_SHIFT);
++}
++
++pte_t mk_pte(struct page *page, pgprot_t pgprot)
++{
++ pte_t pte;
++
++ pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot);
++ if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte));
++ return(pte);
++}
++
++/* Changed during early boot */
++static unsigned long kmem_top = 0;
++
++unsigned long get_kmem_end(void)
++{
++ if(kmem_top == 0)
++ kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
++ return(kmem_top);
++}
++
++void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
++ int r, int w, int x)
++{
++ __u64 offset;
++ int fd, err;
++
++ fd = phys_mapping(phys, &offset);
++ err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
++ if(err)
++ panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
++ "err = %d\n", virt, fd, offset, len, r, w, x, err);
++}
++
++#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
++
++void setup_physmem(unsigned long start, unsigned long reserve_end,
++ unsigned long len, unsigned long highmem)
++{
++ unsigned long reserve = reserve_end - start;
++ int pfn = PFN_UP(__pa(reserve_end));
++ int delta = (len - reserve) >> PAGE_SHIFT;
++ int err, offset, bootmap_size;
++
++ physmem_fd = create_mem_file(len + highmem);
++
++ offset = uml_reserved - uml_physmem;
++ err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
++ len - offset, 1, 1, 0);
++ if(err < 0){
++ os_print_error(err, "Mapping memory");
++ exit(1);
++ }
++
++ bootmap_size = init_bootmem(pfn, pfn + delta);
++ free_bootmem(__pa(reserve_end) + bootmap_size,
++ len - bootmap_size - reserve);
++}
++
++int phys_mapping(unsigned long phys, __u64 *offset_out)
++{
++ struct phys_desc *desc = find_virtmem_hash(&virtmem_hash,
++ __va(phys & PAGE_MASK));
++ int fd = -1;
++
++ if(desc != NULL){
++ fd = desc->fd;
++ *offset_out = desc->offset;
++ }
++ else if(phys < physmem_size){
++ fd = physmem_fd;
++ *offset_out = phys;
++ }
++ else if(phys < __pa(end_iomem)){
++ struct iomem_region *region = iomem_regions;
++
++ while(region != NULL){
++ if((phys >= region->phys) &&
++ (phys < region->phys + region->size)){
++ fd = region->fd;
++ *offset_out = phys - region->phys;
++ break;
++ }
++ region = region->next;
++ }
++ }
++ else if(phys < __pa(end_iomem) + highmem){
++ fd = physmem_fd;
++ *offset_out = phys - iomem_size;
++ }
++
++ return(fd);
++}
++
++static int __init uml_mem_setup(char *line, int *add)
++{
++ char *retptr;
++ physmem_size = memparse(line,&retptr);
++ return 0;
++}
++__uml_setup("mem=", uml_mem_setup,
++"mem=<Amount of desired ram>\n"
++" This controls how much \"physical\" memory the kernel allocates\n"
++" for the system. The size is specified as a number followed by\n"
++" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
++" This is not related to the amount of memory in the host. It can\n"
++" be more, and the excess, if it's ever used, will just be swapped out.\n"
++" Example: mem=64M\n\n"
++);
++
++unsigned long find_iomem(char *driver, unsigned long *len_out)
++{
++ struct iomem_region *region = iomem_regions;
++
++ while(region != NULL){
++ if(!strcmp(region->driver, driver)){
++ *len_out = region->size;
++ return(region->virt);
++ }
++ }
++
++ return(0);
++}
++
++int setup_iomem(void)
++{
++ struct iomem_region *region = iomem_regions;
++ unsigned long iomem_start = high_physmem + PAGE_SIZE;
++ int err;
++
++ while(region != NULL){
++ err = os_map_memory((void *) iomem_start, region->fd, 0,
++ region->size, 1, 1, 0);
++ if(err)
++ printk("Mapping iomem region for driver '%s' failed, "
++ "errno = %d\n", region->driver, -err);
++ else {
++ region->virt = iomem_start;
++ region->phys = __pa(region->virt);
++ }
++
++ iomem_start += region->size + PAGE_SIZE;
++ region = region->next;
++ }
++
++ return(0);
++}
++
++__initcall(setup_iomem);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/process.c um/arch/um/kernel/process.c
+--- orig/arch/um/kernel/process.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/process.c 2004-01-31 02:47:57.000000000 -0500
+@@ -0,0 +1,289 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <signal.h>
++#include <sched.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <stdlib.h>
++#include <setjmp.h>
++#include <sys/time.h>
++#include <sys/ptrace.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>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++#include "irq_user.h"
++#include "ptrace_user.h"
++#include "time_user.h"
++#include "init.h"
++#include "os.h"
++#include "uml-config.h"
++#include "choose-mode.h"
++#include "mode.h"
++#ifdef UML_CONFIG_MODE_SKAS
++#include "skas.h"
++#include "skas_ptrace.h"
++#endif
++
++void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
++{
++ int flags = 0, pages;
++
++ if(sig_stack != NULL){
++ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
++ set_sigstack(sig_stack, pages * page_size());
++ flags = SA_ONSTACK;
++ }
++ if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
++}
++
++void init_new_thread_signals(int altstack)
++{
++ int flags = altstack ? SA_ONSTACK : 0;
++
++ /* NODEFER is set here because SEGV isn't turned back on when the
++ * handler is ready to receive signals. This causes any segfault
++ * during a copy_user to kill the process because the fault is blocked.
++ */
++ set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags,
++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++ set_handler(SIGUSR2, (__sighandler_t) sig_handler,
++ SA_NOMASK | flags, -1);
++ signal(SIGHUP, SIG_IGN);
++
++ init_irq_signals(altstack);
++}
++
++struct tramp {
++ int (*tramp)(void *);
++ void *tramp_data;
++ unsigned long temp_stack;
++ int flags;
++ int pid;
++};
++
++/* See above for why sigkill is here */
++
++int sigkill = SIGKILL;
++
++int outer_tramp(void *arg)
++{
++ struct tramp *t;
++ int sig = sigkill;
++
++ t = arg;
++ t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
++ t->flags, t->tramp_data);
++ if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
++ kill(os_getpid(), sig);
++ _exit(0);
++}
++
++int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
++ int clone_flags, int (*tramp)(void *))
++{
++ struct tramp arg;
++ unsigned long sp;
++ int new_pid, status, err;
++
++ /* The trampoline will run on the temporary stack */
++ sp = stack_sp(temp_stack);
++
++ clone_flags |= CLONE_FILES | SIGCHLD;
++
++ arg.tramp = tramp;
++ arg.tramp_data = thread_arg;
++ arg.temp_stack = temp_stack;
++ arg.flags = clone_flags;
++
++ /* Start the process and wait for it to kill itself */
++ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
++ if(new_pid < 0) return(-errno);
++ while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ;
++ if(err < 0) panic("Waiting for outer trampoline failed - errno = %d",
++ errno);
++ if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
++ panic("outer trampoline didn't exit with SIGKILL, "
++ "status = %d", status);
++
++ return(arg.pid);
++}
++
++void suspend_new_thread(int fd)
++{
++ char c;
++
++ os_stop_process(os_getpid());
++
++ if(os_read_file(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");
++ os_kill_process(pid, 0);
++ }
++ os_stop_process(pid);
++ _exit(os_getpid() == pid);
++}
++
++static int start_ptraced_child(void **stack_out)
++{
++ void *stack;
++ unsigned long sp;
++ int pid, n, status;
++
++ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++ if(stack == MAP_FAILED)
++ panic("check_ptrace : mmap failed, errno = %d", errno);
++ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++ pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
++ if(pid < 0)
++ panic("check_ptrace : clone failed, errno = %d", errno);
++ n = waitpid(pid, &status, WUNTRACED);
++ if(n < 0)
++ panic("check_ptrace : wait failed, errno = %d", errno);
++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
++ panic("check_ptrace : expected SIGSTOP, got status = %d",
++ status);
++
++ *stack_out = stack;
++ return(pid);
++}
++
++static void stop_ptraced_child(int pid, void *stack, int exitcode)
++{
++ int status, n;
++
++ 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) != exitcode))
++ panic("check_ptrace : child exited with status 0x%x", status);
++
++ if(munmap(stack, PAGE_SIZE) < 0)
++ panic("check_ptrace : munmap failed, errno = %d", errno);
++}
++
++void __init check_ptrace(void)
++{
++ void *stack;
++ int pid, syscall, n, status;
++
++ printk("Checking that ptrace can change system call numbers...");
++ pid = start_ptraced_child(&stack);
++
++ 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;
++ }
++ }
++ stop_ptraced_child(pid, stack, 0);
++ printk("OK\n");
++}
++
++int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
++{
++ sigjmp_buf buf;
++ int n;
++
++ *jmp_ptr = &buf;
++ n = sigsetjmp(buf, 1);
++ if(n != 0)
++ return(n);
++ (*fn)(arg);
++ return(0);
++}
++
++int can_do_skas(void)
++{
++#ifdef UML_CONFIG_MODE_SKAS
++ struct ptrace_faultinfo fi;
++ void *stack;
++ int pid, n, ret = 1;
++
++ printf("Checking for the skas3 patch in the host...");
++ pid = start_ptraced_child(&stack);
++
++ n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
++ if(n < 0){
++ if(errno == EIO)
++ printf("not found\n");
++ else printf("No (unexpected errno - %d)\n", errno);
++ ret = 0;
++ }
++ else printf("found\n");
++
++ init_registers(pid);
++ stop_ptraced_child(pid, stack, 1);
++
++ printf("Checking for /proc/mm...");
++ if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
++ printf("not found\n");
++ ret = 0;
++ }
++ else printf("found\n");
++
++ return(ret);
++#else
++ return(0);
++#endif
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/process_kern.c um/arch/um/kernel/process_kern.c
+--- orig/arch/um/kernel/process_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/process_kern.c 2003-11-08 08:37:04.000000000 -0500
+@@ -0,0 +1,396 @@
++/*
++ * 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 "time_user.h"
++#include "tlb.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "2_5compat.h"
++#include "os.h"
++#include "mode.h"
++#include "mode_kern.h"
++#include "choose-mode.h"
++
++/* This is a per-cpu array. A processor only modifies its entry and it only
++ * cares about its entry, so it's OK if another processor is modifying its
++ * entry.
++ */
++struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
++
++struct task_struct *get_task(int pid, int require)
++{
++ struct task_struct *ret;
++
++ read_lock(&tasklist_lock);
++ ret = find_task_by_pid(pid);
++ read_unlock(&tasklist_lock);
++
++ if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
++ return(ret);
++}
++
++int external_pid(void *t)
++{
++ struct task_struct *task = t ? t : current;
++
++ return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
++}
++
++int pid_to_processor_id(int pid)
++{
++ int i;
++
++ for(i = 0; i < 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);
++}
++
++unsigned long alloc_stack(int order, int atomic)
++{
++ unsigned long page;
++ int flags = GFP_KERNEL;
++
++ if(atomic) flags |= GFP_ATOMIC;
++ page = __get_free_pages(flags, order);
++ if(page == 0)
++ return(0);
++ stack_protections(page);
++ return(page);
++}
++
++int 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 0 /* CLONE_UNTRACED for 2.6 */
++ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0);
++#endif
++ if(pid < 0)
++ panic("do_fork failed in kernel_thread, errno = %d", pid);
++ return(pid);
++}
++
++void switch_mm(struct mm_struct *prev, struct mm_struct *next,
++ struct task_struct *tsk, 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->processor] = ((struct cpu_task)
++ { external_pid(task), task });
++}
++
++void *_switch_to(void *prev, void *next)
++{
++ return(CHOOSE_MODE(_switch_to_tt(prev, next),
++ _switch_to_skas(prev, next)));
++}
++
++void interrupt_end(void)
++{
++ if(current->need_resched) schedule();
++ if(current->sigpending != 0) do_signal(0);
++}
++
++void release_thread(struct task_struct *task)
++{
++ CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
++}
++
++void exit_thread(void)
++{
++ CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
++ unprotect_stack((unsigned long) current);
++}
++
++void *get_current(void)
++{
++ return(current);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct * p,
++ struct pt_regs *regs)
++{
++ p->thread = (struct thread_struct) INIT_THREAD;
++ p->thread.kernel_stack = (unsigned long) p + 2 * PAGE_SIZE;
++
++ return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
++ clone_flags, sp, stack_top, p, regs));
++}
++
++void initial_thread_cb(void (*proc)(void *), void *arg)
++{
++ int save_kmalloc_ok = kmalloc_ok;
++
++ kmalloc_ok = 0;
++ CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
++ arg);
++ kmalloc_ok = save_kmalloc_ok;
++}
++
++unsigned long stack_sp(unsigned long page)
++{
++ return(page + PAGE_SIZE - sizeof(void *));
++}
++
++int current_pid(void)
++{
++ return(current->pid);
++}
++
++void cpu_idle(void)
++{
++ CHOOSE_MODE(init_idle_tt(), init_idle_skas());
++
++ 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);
++}
++
++void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
++ pte_t *pte_out)
++{
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++
++ if(task->mm == NULL)
++ return(ERR_PTR(-EINVAL));
++ pgd = pgd_offset(task->mm, addr);
++ pmd = pmd_offset(pgd, addr);
++ if(!pmd_present(*pmd))
++ return(ERR_PTR(-EINVAL));
++ pte = pte_offset(pmd, addr);
++ if(!pte_present(*pte))
++ return(ERR_PTR(-EINVAL));
++ if(pte_out != NULL)
++ *pte_out = *pte;
++ return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
++}
++
++char *current_cmd(void)
++{
++#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
++ return("(Unknown)");
++#else
++ void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
++ return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
++#endif
++}
++
++void force_sigbus(void)
++{
++ printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
++ current->pid);
++ lock_kernel();
++ sigaddset(¤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 not_implemented(void)
++{
++ printk(KERN_DEBUG "Something isn't implemented in here\n");
++}
++
++EXPORT_SYMBOL(not_implemented);
++
++int user_context(unsigned long sp)
++{
++ unsigned long stack;
++
++ stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
++ stack += 2 * PAGE_SIZE;
++ return(stack != 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)();
++}
++
++char *uml_strdup(char *string)
++{
++ char *new;
++
++ new = kmalloc(strlen(string) + 1, GFP_KERNEL);
++ if(new == NULL) return(NULL);
++ strcpy(new, string);
++ return(new);
++}
++
++void *get_init_task(void)
++{
++ return(&init_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));
++}
++
++int strlen_user_proc(char *str)
++{
++ return(strlen_user(str));
++}
++
++int smp_sigio_handler(void)
++{
++#ifdef CONFIG_SMP
++ int cpu = current->processor;
++
++ IPI_handler(cpu);
++ if(cpu != 0)
++ return(1);
++#endif
++ return(0);
++}
++
++int um_in_interrupt(void)
++{
++ return(in_interrupt());
++}
++
++int cpu(void)
++{
++ return(current->processor);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/ptrace.c um/arch/um/kernel/ptrace.c
+--- orig/arch/um/kernel/ptrace.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/ptrace.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,325 @@
++/*
++ * 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"
++#ifdef CONFIG_PROC_MM
++#include "linux/proc_mm.h"
++#endif
++#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)
++{
++}
++
++extern long do_mmap2(struct task_struct *task, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++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 long *)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
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.err,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ if(ret)
++ break;
++ break;
++ }
++ case PTRACE_SIGPENDING:
++ ret = copy_to_user((unsigned long *) data,
++ &child->pending.signal,
++ sizeof(child->pending.signal));
++ break;
++
++ case PTRACE_LDT: {
++ struct ptrace_ldt ldt;
++
++ if(copy_from_user(&ldt, (unsigned long *) data,
++ sizeof(ldt))){
++ ret = -EIO;
++ break;
++ }
++
++ /* This one is confusing, so just punt and return -EIO for
++ * now
++ */
++ ret = -EIO;
++ break;
++ }
++#ifdef CONFIG_PROC_MM
++ case PTRACE_SWITCH_MM: {
++ struct mm_struct *old = child->mm;
++ struct mm_struct *new = proc_mm_get_mm(data);
++
++ if(IS_ERR(new)){
++ ret = PTR_ERR(new);
++ break;
++ }
++
++ atomic_inc(&new->mm_users);
++ child->mm = new;
++ child->active_mm = new;
++ mmput(old);
++ ret = 0;
++ break;
++ }
++#endif
++ default:
++ ret = -EIO;
++ break;
++ }
++ out_tsk:
++ free_task_struct(child);
++ out:
++ unlock_kernel();
++ return ret;
++}
++
++void syscall_trace(void)
++{
++ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
++ != (PT_PTRACED|PT_TRACESYS))
++ return;
++ current->exit_code = SIGTRAP;
++ current->state = TASK_STOPPED;
++ notify_parent(current, SIGCHLD);
++ schedule();
++ /*
++ * this isn't the same as continuing with a signal, but it will do
++ * for normal use. strace only continues with a signal if the
++ * stopping signal is not SIGTRAP. -brl
++ */
++ if (current->exit_code) {
++ send_sig(current->exit_code, current, 1);
++ current->exit_code = 0;
++ }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/reboot.c um/arch/um/kernel/reboot.c
+--- orig/arch/um/kernel/reboot.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/reboot.c 2003-10-21 03:26:06.000000000 -0400
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2000, 2002 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"
++#include "mode.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_SMP
++static void kill_idlers(int me)
++{
++#ifdef CONFIG_MODE_TT
++ struct task_struct *p;
++ int i;
++
++ for(i = 0; i < sizeof(init_tasks)/sizeof(init_tasks[0]); i++){
++ p = init_tasks[i];
++ if((p != NULL) && (p->thread.mode.tt.extern_pid != me) &&
++ (p->thread.mode.tt.extern_pid != -1))
++ os_kill_process(p->thread.mode.tt.extern_pid, 0);
++ }
++#endif
++}
++#endif
++
++static void kill_off_processes(void)
++{
++ CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
++#ifdef CONFIG_SMP
++ kill_idlers(os_getpid());
++#endif
++}
++
++void uml_cleanup(void)
++{
++ kill_off_processes();
++ do_uml_exitcalls();
++}
++
++void machine_restart(char * __unused)
++{
++ do_uml_exitcalls();
++ kill_off_processes();
++ CHOOSE_MODE(reboot_tt(), reboot_skas());
++}
++
++void machine_power_off(void)
++{
++ do_uml_exitcalls();
++ kill_off_processes();
++ CHOOSE_MODE(halt_tt(), halt_skas());
++}
++
++void machine_halt(void)
++{
++ machine_power_off();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/resource.c um/arch/um/kernel/resource.c
+--- orig/arch/um/kernel/resource.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/resource.c 2003-10-21 03:26:06.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/sigio_kern.c um/arch/um/kernel/sigio_kern.c
+--- orig/arch/um/kernel/sigio_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/sigio_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,57 @@
++/*
++ * 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"
++#include "irq_kern.h"
++
++/* Protected by sigio_lock() called from write_sigio_workaround */
++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);
++}
++
++static spinlock_t sigio_spinlock = SPIN_LOCK_UNLOCKED;
++
++void sigio_lock(void)
++{
++ spin_lock(&sigio_spinlock);
++}
++
++void sigio_unlock(void)
++{
++ spin_unlock(&sigio_spinlock);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/sigio_user.c um/arch/um/kernel/sigio_user.c
+--- orig/arch/um/kernel/sigio_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/sigio_user.c 2003-11-07 01:41:13.000000000 -0500
+@@ -0,0 +1,438 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <termios.h>
++#include <pty.h>
++#include <signal.h>
++#include <errno.h>
++#include <string.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include <sys/poll.h>
++#include "init.h"
++#include "user.h"
++#include "kern_util.h"
++#include "sigio.h"
++#include "helper.h"
++#include "os.h"
++
++/* Changed during early boot */
++int pty_output_sigio = 0;
++int pty_close_sigio = 0;
++
++/* Used as a flag during SIGIO testing early in boot */
++static volatile int got_sigio = 0;
++
++void __init handler(int sig)
++{
++ got_sigio = 1;
++}
++
++struct openpty_arg {
++ int master;
++ int slave;
++ int err;
++};
++
++static void openpty_cb(void *arg)
++{
++ struct openpty_arg *info = arg;
++
++ info->err = 0;
++ if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
++ info->err = -errno;
++}
++
++void __init check_one_sigio(void (*proc)(int, int))
++{
++ struct sigaction old, new;
++ struct termios tt;
++ struct openpty_arg pty = { .master = -1, .slave = -1 };
++ int master, slave, err;
++
++ initial_thread_cb(openpty_cb, &pty);
++ if(pty.err){
++ printk("openpty failed, errno = %d\n", -pty.err);
++ return;
++ }
++
++ master = pty.master;
++ slave = pty.slave;
++
++ if((master == -1) || (slave == -1)){
++ printk("openpty failed to allocate a pty\n");
++ return;
++ }
++
++ /* XXX These can fail with EINTR */
++ 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);
++
++ err = os_sigio_async(master, slave);
++ if(err < 0)
++ panic("tty_fds : sigio_async failed, err = %d\n", -err);
++
++ if(sigaction(SIGIO, NULL, &old) < 0)
++ panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
++ new = old;
++ new.sa_handler = handler;
++ if(sigaction(SIGIO, &new, NULL) < 0)
++ panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
++
++ got_sigio = 0;
++ (*proc)(master, slave);
++
++ os_close_file(master);
++ os_close_file(slave);
++
++ if(sigaction(SIGIO, &old, NULL) < 0)
++ panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
++}
++
++static void tty_output(int master, int slave)
++{
++ int n;
++ char buf[512];
++
++ printk("Checking that host ptys support output SIGIO...");
++
++ memset(buf, 0, sizeof(buf));
++
++ while(os_write_file(master, buf, sizeof(buf)) > 0) ;
++ if(errno != EAGAIN)
++ panic("check_sigio : write failed, errno = %d\n", errno);
++ while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
++
++ if(got_sigio){
++ printk("Yes\n");
++ pty_output_sigio = 1;
++ }
++ else if(n == -EAGAIN) printk("No, enabling workaround\n");
++ else panic("check_sigio : read failed, err = %d\n", n);
++}
++
++static void tty_close(int master, int slave)
++{
++ printk("Checking that host ptys support SIGIO on close...");
++
++ os_close_file(slave);
++ if(got_sigio){
++ printk("Yes\n");
++ pty_close_sigio = 1;
++ }
++ else printk("No, enabling workaround\n");
++}
++
++void __init check_sigio(void)
++{
++ if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
++ (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
++ printk("No pseudo-terminals available - skipping pty SIGIO "
++ "check\n");
++ return;
++ }
++ check_one_sigio(tty_output);
++ check_one_sigio(tty_close);
++}
++
++/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
++ * exitcall.
++ */
++static int write_sigio_pid = -1;
++
++/* These arrays are initialized before the sigio thread is started, and
++ * the descriptors closed after it is killed. So, it can't see them change.
++ * On the UML side, they are changed under the sigio_lock.
++ */
++static int write_sigio_fds[2] = { -1, -1 };
++static int sigio_private[2] = { -1, -1 };
++
++struct pollfds {
++ struct pollfd *poll;
++ int size;
++ int used;
++};
++
++/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
++ * synchronizes with it.
++ */
++struct pollfds current_poll = {
++ .poll = NULL,
++ .size = 0,
++ .used = 0
++};
++
++struct pollfds next_poll = {
++ .poll = NULL,
++ .size = 0,
++ .used = 0
++};
++
++static int write_sigio_thread(void *unused)
++{
++ struct pollfds *fds, tmp;
++ struct pollfd *p;
++ int i, n, respond_fd;
++ char c;
++
++ fds = ¤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 = os_read_file(sigio_private[1], &c, sizeof(c));
++ if(n != sizeof(c))
++ printk("write_sigio_thread : "
++ "read failed, err = %d\n", -n);
++ tmp = current_poll;
++ current_poll = next_poll;
++ next_poll = tmp;
++ respond_fd = sigio_private[1];
++ }
++ else {
++ respond_fd = write_sigio_fds[1];
++ fds->used--;
++ memmove(&fds->poll[i], &fds->poll[i + 1],
++ (fds->used - i) * sizeof(*fds->poll));
++ }
++
++ n = os_write_file(respond_fd, &c, sizeof(c));
++ if(n != sizeof(c))
++ printk("write_sigio_thread : write failed, "
++ "err = %d\n", -n);
++ }
++ }
++}
++
++static int need_poll(int n)
++{
++ if(n <= next_poll.size){
++ next_poll.used = n;
++ return(0);
++ }
++ if(next_poll.poll != NULL) kfree(next_poll.poll);
++ next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
++ if(next_poll.poll == NULL){
++ printk("need_poll : failed to allocate new pollfds\n");
++ next_poll.size = 0;
++ next_poll.used = 0;
++ return(-1);
++ }
++ next_poll.size = n;
++ next_poll.used = n;
++ return(0);
++}
++
++static void update_thread(void)
++{
++ unsigned long flags;
++ int n;
++ char c;
++
++ flags = set_signals(0);
++ n = os_write_file(sigio_private[0], &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("update_thread : write failed, err = %d\n", -n);
++ goto fail;
++ }
++
++ n = os_read_file(sigio_private[0], &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("update_thread : read failed, err = %d\n", -n);
++ goto fail;
++ }
++
++ set_signals(flags);
++ return;
++ fail:
++ sigio_lock();
++ if(write_sigio_pid != -1)
++ os_kill_process(write_sigio_pid, 1);
++ write_sigio_pid = -1;
++ os_close_file(sigio_private[0]);
++ os_close_file(sigio_private[1]);
++ os_close_file(write_sigio_fds[0]);
++ os_close_file(write_sigio_fds[1]);
++ sigio_unlock();
++ set_signals(flags);
++}
++
++int add_sigio_fd(int fd, int read)
++{
++ int err = 0, i, n, events;
++
++ sigio_lock();
++ for(i = 0; i < current_poll.used; i++){
++ if(current_poll.poll[i].fd == fd)
++ goto out;
++ }
++
++ n = current_poll.used + 1;
++ err = need_poll(n);
++ if(err)
++ goto out;
++
++ for(i = 0; i < current_poll.used; i++)
++ next_poll.poll[i] = current_poll.poll[i];
++
++ if(read) events = POLLIN;
++ else events = POLLOUT;
++
++ next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd,
++ .events = events,
++ .revents = 0 });
++ update_thread();
++ out:
++ sigio_unlock();
++ return(err);
++}
++
++int ignore_sigio_fd(int fd)
++{
++ struct pollfd *p;
++ int err = 0, i, n = 0;
++
++ sigio_lock();
++ for(i = 0; i < current_poll.used; i++){
++ if(current_poll.poll[i].fd == fd) break;
++ }
++ if(i == current_poll.used)
++ goto out;
++
++ err = need_poll(current_poll.used - 1);
++ if(err)
++ goto out;
++
++ for(i = 0; i < current_poll.used; i++){
++ p = ¤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);
++ err = -1;
++ goto out;
++ }
++
++ update_thread();
++ out:
++ sigio_unlock();
++ return(err);
++}
++
++static int setup_initial_poll(int fd)
++{
++ struct pollfd *p;
++
++ p = um_kmalloc(sizeof(struct pollfd));
++ if(p == NULL){
++ printk("setup_initial_poll : failed to allocate poll\n");
++ return(-1);
++ }
++ *p = ((struct pollfd) { .fd = fd,
++ .events = POLLIN,
++ .revents = 0 });
++ current_poll = ((struct pollfds) { .poll = p,
++ .used = 1,
++ .size = 1 });
++ return(0);
++}
++
++void write_sigio_workaround(void)
++{
++ unsigned long stack;
++ int err;
++
++ sigio_lock();
++ if(write_sigio_pid != -1)
++ goto out;
++
++ err = os_pipe(write_sigio_fds, 1, 1);
++ if(err < 0){
++ printk("write_sigio_workaround - os_pipe 1 failed, "
++ "err = %d\n", -err);
++ goto out;
++ }
++ err = os_pipe(sigio_private, 1, 1);
++ if(err < 0){
++ printk("write_sigio_workaround - os_pipe 2 failed, "
++ "err = %d\n", -err);
++ goto out_close1;
++ }
++ if(setup_initial_poll(sigio_private[1]))
++ goto out_close2;
++
++ write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
++ CLONE_FILES | CLONE_VM, &stack, 0);
++
++ if(write_sigio_pid < 0) goto out_close2;
++
++ if(write_sigio_irq(write_sigio_fds[0]))
++ goto out_kill;
++
++ out:
++ sigio_unlock();
++ return;
++
++ out_kill:
++ os_kill_process(write_sigio_pid, 1);
++ write_sigio_pid = -1;
++ out_close2:
++ os_close_file(sigio_private[0]);
++ os_close_file(sigio_private[1]);
++ out_close1:
++ os_close_file(write_sigio_fds[0]);
++ os_close_file(write_sigio_fds[1]);
++ sigio_unlock();
++}
++
++int read_sigio_fd(int fd)
++{
++ int n;
++ char c;
++
++ n = os_read_file(fd, &c, sizeof(c));
++ if(n != sizeof(c)){
++ if(n < 0) {
++ printk("read_sigio_fd - read failed, err = %d\n", -n);
++ return(n);
++ }
++ else {
++ printk("read_sigio_fd - short read, bytes = %d\n", n);
++ return(-EIO);
++ }
++ }
++ return(n);
++}
++
++static void sigio_cleanup(void)
++{
++ if(write_sigio_pid != -1)
++ os_kill_process(write_sigio_pid, 1);
++}
++
++__uml_exitcall(sigio_cleanup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/signal_kern.c um/arch/um/kernel/signal_kern.c
+--- orig/arch/um/kernel/signal_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/signal_kern.c 2003-11-19 03:50:58.000000000 -0500
+@@ -0,0 +1,369 @@
++/*
++ * 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 "asm/ucontext.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"
++#include "mode.h"
++
++EXPORT_SYMBOL(block_signals);
++EXPORT_SYMBOL(unblock_signals);
++
++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? */
++ signr = current->exit_code;
++ if (!signr)
++ 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:
++ sig_exit(signr, exit_code, &info);
++ /* 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)))
++ (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0);
++
++ 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);
++ }
++}
++
++extern int userspace_pid[];
++
++static int copy_sc_from_user(struct pt_regs *to, void *from,
++ struct arch_frame_data *arch)
++{
++ int ret;
++
++ ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
++ copy_sc_from_user_skas(userspace_pid[0],
++ &to->regs, from));
++ return(ret);
++}
++
++int sys_sigreturn(struct pt_regs regs)
++{
++ void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs));
++ void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs));
++ 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(¤t->thread.regs, sc,
++ &signal_frame_sc.common.arch);
++ return(PT_REGS_SYSCALL_RET(¤t->thread.regs));
++}
++
++int sys_rt_sigreturn(struct pt_regs regs)
++{
++ struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs));
++ int sig_size = _NSIG_WORDS * sizeof(unsigned long);
++
++ spin_lock_irq(¤t->sigmask_lock);
++ copy_from_user(¤t->blocked, &uc->uc_sigmask, sig_size);
++ sigdelsetmask(¤t->blocked, ~_BLOCKABLE);
++ recalc_sigpending(current);
++ spin_unlock_irq(¤t->sigmask_lock);
++ copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext,
++ &signal_frame_si.common.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/signal_user.c um/arch/um/kernel/signal_user.c
+--- orig/arch/um/kernel/signal_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/signal_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,142 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <sys/mman.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "signal_user.h"
++#include "signal_kern.h"
++#include "sysdep/sigcontext.h"
++#include "sigcontext.h"
++
++void set_sigstack(void *sig_stack, int size)
++{
++ stack_t stack = ((stack_t) { .ss_flags = 0,
++ .ss_sp = (__ptr_t) sig_stack,
++ .ss_size = size - sizeof(void *) });
++
++ if(sigaltstack(&stack, NULL) != 0)
++ panic("enabling signal stack failed, errno = %d\n", errno);
++}
++
++void set_handler(int sig, void (*handler)(int), int flags, ...)
++{
++ struct sigaction action;
++ va_list ap;
++ int mask;
++
++ va_start(ap, flags);
++ action.sa_handler = handler;
++ sigemptyset(&action.sa_mask);
++ while((mask = va_arg(ap, int)) != -1){
++ sigaddset(&action.sa_mask, mask);
++ }
++ 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);
++ 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;
++ return(sigs);
++}
++
++int get_signals(void)
++{
++ sigset_t mask;
++
++ if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
++ panic("Failed to get signal mask");
++ return(enable_mask(&mask));
++}
++
++int set_signals(int enable)
++{
++ sigset_t mask;
++ int ret;
++
++ sigemptyset(&mask);
++ if(enable & (1 << SIGIO_BIT))
++ sigaddset(&mask, SIGIO);
++ if(enable & (1 << SIGVTALRM_BIT)){
++ sigaddset(&mask, SIGVTALRM);
++ sigaddset(&mask, SIGALRM);
++ }
++ if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
++ panic("Failed to enable signals");
++ ret = enable_mask(&mask);
++ sigemptyset(&mask);
++ if((enable & (1 << SIGIO_BIT)) == 0)
++ sigaddset(&mask, SIGIO);
++ if((enable & (1 << SIGVTALRM_BIT)) == 0){
++ sigaddset(&mask, SIGVTALRM);
++ sigaddset(&mask, SIGALRM);
++ }
++ if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
++ panic("Failed to block signals");
++
++ return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/exec_kern.c um/arch/um/kernel/skas/exec_kern.c
+--- orig/arch/um/kernel/skas/exec_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/exec_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,41 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "asm/current.h"
++#include "asm/page.h"
++#include "asm/signal.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++#include "tlb.h"
++#include "skas.h"
++#include "mmu.h"
++#include "os.h"
++
++void flush_thread_skas(void)
++{
++ force_flush_all();
++ switch_mm_skas(current->mm->context.skas.mm_fd);
++}
++
++void start_thread_skas(struct pt_regs *regs, unsigned long eip,
++ unsigned long esp)
++{
++ set_fs(USER_DS);
++ PT_REGS_IP(regs) = eip;
++ PT_REGS_SP(regs) = esp;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/exec_user.c um/arch/um/kernel/skas/exec_user.c
+--- orig/arch/um/kernel/skas/exec_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/exec_user.c 2003-10-21 03:26:07.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 <signal.h>
++#include <sched.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include "user.h"
++#include "kern_util.h"
++#include "os.h"
++#include "time_user.h"
++
++static int user_thread_tramp(void *arg)
++{
++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
++ panic("user_thread_tramp - PTRACE_TRACEME failed, "
++ "errno = %d\n", errno);
++ enable_timer();
++ os_stop_process(os_getpid());
++ return(0);
++}
++
++int user_thread(unsigned long stack, int flags)
++{
++ int pid, status;
++
++ pid = clone(user_thread_tramp, (void *) stack_sp(stack),
++ flags | CLONE_FILES | SIGCHLD, NULL);
++ if(pid < 0){
++ printk("user_thread - clone failed, errno = %d\n", errno);
++ return(pid);
++ }
++
++ if(waitpid(pid, &status, WUNTRACED) < 0){
++ printk("user_thread - waitpid failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++ printk("user_thread - trampoline didn't stop, status = %d\n",
++ status);
++ return(-EINVAL);
++ }
++
++ return(pid);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mmu.h um/arch/um/kernel/skas/include/mmu.h
+--- orig/arch/um/kernel/skas/include/mmu.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/mmu.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_MMU_H
++#define __SKAS_MMU_H
++
++#include "linux/list.h"
++#include "linux/spinlock.h"
++
++struct mmu_context_skas {
++ int mm_fd;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mode.h um/arch/um/kernel/skas/include/mode.h
+--- orig/arch/um/kernel/skas/include/mode.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/mode.h 2003-11-19 03:27:36.000000000 -0500
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_SKAS_H__
++#define __MODE_SKAS_H__
++
++extern unsigned long exec_regs[];
++extern unsigned long exec_fp_regs[];
++extern unsigned long exec_fpx_regs[];
++extern int have_fpx_regs;
++
++extern void user_time_init_skas(void);
++extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs,
++ void *from_ptr);
++extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
++ union uml_pt_regs *regs,
++ unsigned long fault_addr, int fault_type);
++extern void sig_handler_common_skas(int sig, void *sc_ptr);
++extern void halt_skas(void);
++extern void reboot_skas(void);
++extern void kill_off_processes_skas(void);
++extern int is_skas_winch(int pid, int fd, void *data);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mode_kern.h um/arch/um/kernel/skas/include/mode_kern.h
+--- orig/arch/um/kernel/skas/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/mode_kern.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_MODE_KERN_H__
++#define __SKAS_MODE_KERN_H__
++
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/ptrace.h"
++
++extern void flush_thread_skas(void);
++extern void *_switch_to_skas(void *prev, void *next);
++extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
++ unsigned long esp);
++extern int copy_thread_skas(int nr, unsigned long clone_flags,
++ unsigned long sp, unsigned long stack_top,
++ struct task_struct *p, struct pt_regs *regs);
++extern void release_thread_skas(struct task_struct *task);
++extern void exit_thread_skas(void);
++extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
++extern void init_idle_skas(void);
++extern void flush_tlb_kernel_vm_skas(void);
++extern void __flush_tlb_one_skas(unsigned long addr);
++extern void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start,
++ unsigned long end);
++extern void flush_tlb_mm_skas(struct mm_struct *mm);
++extern void force_flush_all_skas(void);
++extern long execute_syscall_skas(void *r);
++extern void before_mem_skas(unsigned long unused);
++extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
++ unsigned long *task_size_out);
++extern int start_uml_skas(void);
++extern int external_pid_skas(struct task_struct *task);
++extern int thread_pid_skas(struct thread_struct *thread);
++
++#define kmem_end_skas (host_task_size - 1024 * 1024)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/proc_mm.h um/arch/um/kernel/skas/include/proc_mm.h
+--- orig/arch/um/kernel/skas/include/proc_mm.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/proc_mm.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_PROC_MM_H
++#define __SKAS_PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++ unsigned long addr;
++ unsigned long len;
++ unsigned long prot;
++ unsigned long flags;
++ unsigned long fd;
++ unsigned long offset;
++};
++
++struct mm_munmap {
++ unsigned long addr;
++ unsigned long len;
++};
++
++struct mm_mprotect {
++ unsigned long addr;
++ unsigned long len;
++ unsigned int prot;
++};
++
++struct proc_mm_op {
++ int op;
++ union {
++ struct mm_mmap mmap;
++ struct mm_munmap munmap;
++ struct mm_mprotect mprotect;
++ int copy_segments;
++ } u;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/ptrace-skas.h um/arch/um/kernel/skas/include/ptrace-skas.h
+--- orig/arch/um/kernel/skas/include/ptrace-skas.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/ptrace-skas.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_SKAS_H
++#define __PTRACE_SKAS_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_SKAS
++
++#include "skas_ptregs.h"
++
++#define HOST_FRAME_SIZE 17
++
++#define REGS_IP(r) ((r)[HOST_IP])
++#define REGS_SP(r) ((r)[HOST_SP])
++#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
++#define REGS_EAX(r) ((r)[HOST_EAX])
++#define REGS_EBX(r) ((r)[HOST_EBX])
++#define REGS_ECX(r) ((r)[HOST_ECX])
++#define REGS_EDX(r) ((r)[HOST_EDX])
++#define REGS_ESI(r) ((r)[HOST_ESI])
++#define REGS_EDI(r) ((r)[HOST_EDI])
++#define REGS_EBP(r) ((r)[HOST_EBP])
++#define REGS_CS(r) ((r)[HOST_CS])
++#define REGS_SS(r) ((r)[HOST_SS])
++#define REGS_DS(r) ((r)[HOST_DS])
++#define REGS_ES(r) ((r)[HOST_ES])
++#define REGS_FS(r) ((r)[HOST_FS])
++#define REGS_GS(r) ((r)[HOST_GS])
++
++#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
++
++#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
++
++#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
++
++#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
++
++#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/skas.h um/arch/um/kernel/skas/include/skas.h
+--- orig/arch/um/kernel/skas/include/skas.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/skas.h 2003-11-19 03:00:51.000000000 -0500
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_H
++#define __SKAS_H
++
++#include "sysdep/ptrace.h"
++
++extern int userspace_pid[];
++
++extern void switch_threads(void *me, void *next);
++extern void thread_wait(void *sw, void *fb);
++extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
++ void (*handler)(int));
++extern int start_idle_thread(void *stack, void *switch_buf_ptr,
++ void **fork_buf_ptr);
++extern int user_thread(unsigned long stack, int flags);
++extern void userspace(union uml_pt_regs *regs);
++extern void new_thread_proc(void *stack, void (*handler)(int sig));
++extern void remove_sigstack(void);
++extern void new_thread_handler(int sig);
++extern void handle_syscall(union uml_pt_regs *regs);
++extern void map(int fd, unsigned long virt, unsigned long phys,
++ unsigned long len, int r, int w, int x);
++extern int unmap(int fd, void *addr, int len);
++extern int protect(int fd, unsigned long addr, unsigned long len,
++ int r, int w, int x, int must_succeed);
++extern void user_signal(int sig, union uml_pt_regs *regs);
++extern int singlestepping_skas(void);
++extern int new_mm(int from);
++extern void save_registers(union uml_pt_regs *regs);
++extern void restore_registers(union uml_pt_regs *regs);
++extern void start_userspace(int cpu);
++extern void init_registers(int pid);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/uaccess.h um/arch/um/kernel/skas/include/uaccess.h
+--- orig/arch/um/kernel/skas/include/uaccess.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/include/uaccess.h 2004-01-17 06:35:41.000000000 -0500
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_UACCESS_H
++#define __SKAS_UACCESS_H
++
++#include "asm/errno.h"
++
++#define access_ok_skas(type, addr, size) \
++ ((segment_eq(get_fs(), KERNEL_DS)) || \
++ (((unsigned long) (addr) < TASK_SIZE) && \
++ ((unsigned long) (addr) + (size) <= TASK_SIZE)))
++
++static inline int verify_area_skas(int type, const void * addr,
++ unsigned long size)
++{
++ return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
++}
++
++extern int copy_from_user_skas(void *to, const void *from, int n);
++extern int copy_to_user_skas(void *to, const void *from, int n);
++extern int strncpy_from_user_skas(char *dst, const char *src, int count);
++extern int __clear_user_skas(void *mem, int len);
++extern int clear_user_skas(void *mem, int len);
++extern int strnlen_user_skas(const void *str, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/Makefile um/arch/um/kernel/skas/Makefile
+--- orig/arch/um/kernel/skas/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/Makefile 2003-11-11 06:36:12.000000000 -0500
+@@ -0,0 +1,31 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = skas.o
++
++obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \
++ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
++ uaccess.o
++
++subdir-y = sys-$(SUBARCH)
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
++
++include $(TOPDIR)/Rules.make
++
++include/skas_ptregs.h : util/mk_ptregs
++ util/mk_ptregs > $@
++
++util/mk_ptregs :
++ $(MAKE) -C util
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
++ $(MAKE) -C util clean
++ $(RM) -f include/skas_ptregs.h
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mem.c um/arch/um/kernel/skas/mem.c
+--- orig/arch/um/kernel/skas/mem.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/mem.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "mem_user.h"
++
++unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
++ unsigned long *task_size_out)
++{
++ /* Round up to the nearest 4M */
++ unsigned long top = ROUND_4M((unsigned long) &arg);
++
++ *host_size_out = top;
++ *task_size_out = top;
++ return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mem_user.c um/arch/um/kernel/skas/mem_user.c
+--- orig/arch/um/kernel/skas/mem_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/mem_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <sys/mman.h>
++#include <sys/ptrace.h>
++#include "mem_user.h"
++#include "mem.h"
++#include "user.h"
++#include "os.h"
++#include "proc_mm.h"
++
++void map(int fd, unsigned long virt, unsigned long phys, unsigned long len,
++ int r, int w, int x)
++{
++ struct proc_mm_op map;
++ __u64 offset;
++ int prot, n, phys_fd;
++
++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
++ (x ? PROT_EXEC : 0);
++ phys_fd = phys_mapping(phys, &offset);
++
++ map = ((struct proc_mm_op) { .op = MM_MMAP,
++ .u =
++ { .mmap =
++ { .addr = virt,
++ .len = len,
++ .prot = prot,
++ .flags = MAP_SHARED |
++ MAP_FIXED,
++ .fd = phys_fd,
++ .offset = offset
++ } } } );
++ n = os_write_file(fd, &map, sizeof(map));
++ if(n != sizeof(map))
++ printk("map : /proc/mm map failed, err = %d\n", -n);
++}
++
++int unmap(int fd, void *addr, int len)
++{
++ struct proc_mm_op unmap;
++ int n;
++
++ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
++ .u =
++ { .munmap =
++ { .addr = (unsigned long) addr,
++ .len = len } } } );
++ n = os_write_file(fd, &unmap, sizeof(unmap));
++ if(n != sizeof(unmap)) {
++ if(n < 0)
++ return(n);
++ else if(n > 0)
++ return(-EIO);
++ }
++
++ return(0);
++}
++
++int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
++ int x, int must_succeed)
++{
++ struct proc_mm_op protect;
++ int prot, n;
++
++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
++ (x ? PROT_EXEC : 0);
++
++ protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
++ .u =
++ { .mprotect =
++ { .addr = (unsigned long) addr,
++ .len = len,
++ .prot = prot } } } );
++
++ n = os_write_file(fd, &protect, sizeof(protect));
++ if(n != sizeof(protect)) {
++ if(n == 0) return(0);
++
++ if(must_succeed)
++ panic("protect failed, err = %d", -n);
++
++ return(-EIO);
++ }
++
++ return(0);
++}
++
++void before_mem_skas(unsigned long unused)
++{
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mmu.c um/arch/um/kernel/skas/mmu.c
+--- orig/arch/um/kernel/skas/mmu.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/mmu.c 2003-11-15 22:25:20.000000000 -0500
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/list.h"
++#include "linux/spinlock.h"
++#include "linux/slab.h"
++#include "asm/segment.h"
++#include "asm/mmu.h"
++#include "os.h"
++#include "skas.h"
++
++int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
++{
++ int from;
++
++ if((current->mm != NULL) && (current->mm != &init_mm))
++ from = current->mm->context.skas.mm_fd;
++ else from = -1;
++
++ mm->context.skas.mm_fd = new_mm(from);
++ if(mm->context.skas.mm_fd < 0){
++ printk("init_new_context_skas - new_mm failed, errno = %d\n",
++ mm->context.skas.mm_fd);
++ return(mm->context.skas.mm_fd);
++ }
++
++ return(0);
++}
++
++void destroy_context_skas(struct mm_struct *mm)
++{
++ os_close_file(mm->context.skas.mm_fd);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/process.c um/arch/um/kernel/skas/process.c
+--- orig/arch/um/kernel/skas/process.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/process.c 2004-01-31 02:49:36.000000000 -0500
+@@ -0,0 +1,417 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++#include <setjmp.h>
++#include <sched.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include <sys/mman.h>
++#include <sys/user.h>
++#include <asm/unistd.h>
++#include "user.h"
++#include "ptrace_user.h"
++#include "time_user.h"
++#include "sysdep/ptrace.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "skas.h"
++#include "sysdep/sigcontext.h"
++#include "os.h"
++#include "proc_mm.h"
++#include "skas_ptrace.h"
++#include "chan_user.h"
++
++int is_skas_winch(int pid, int fd, void *data)
++{
++ if(pid != getpid())
++ return(0);
++
++ register_winch_irq(-1, fd, -1, data);
++ return(1);
++}
++
++/* These are set once at boot time and not changed thereafter */
++
++unsigned long exec_regs[FRAME_SIZE];
++unsigned long exec_fp_regs[HOST_FP_SIZE];
++unsigned long exec_fpx_regs[HOST_XFP_SIZE];
++int have_fpx_regs = 1;
++
++static void handle_segv(int pid)
++{
++ struct ptrace_faultinfo fault;
++ int err;
++
++ err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
++ if(err)
++ panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
++ errno);
++
++ segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
++}
++
++static void handle_trap(int pid, union uml_pt_regs *regs)
++{
++ int err, syscall_nr, status;
++
++ syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
++ UPT_SYSCALL_NR(regs) = syscall_nr;
++ if(syscall_nr < 1){
++ relay_signal(SIGTRAP, regs);
++ return;
++ }
++
++ err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
++ if(err < 0)
++ panic("handle_trap - nullifying syscall failed errno = %d\n",
++ errno);
++
++ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
++ if(err < 0)
++ panic("handle_trap - continuing to end of syscall failed, "
++ "errno = %d\n", errno);
++
++ err = waitpid(pid, &status, WUNTRACED);
++ if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
++ panic("handle_trap - failed to wait at end of syscall, "
++ "errno = %d, status = %d\n", errno, status);
++
++ handle_syscall(regs);
++}
++
++static int userspace_tramp(void *arg)
++{
++ init_new_thread_signals(0);
++ enable_timer();
++ ptrace(PTRACE_TRACEME, 0, 0, 0);
++ os_stop_process(os_getpid());
++ return(0);
++}
++
++/* Each element set once, and only accessed by a single processor anyway */
++#define NR_CPUS 1
++int userspace_pid[NR_CPUS];
++
++void start_userspace(int cpu)
++{
++ void *stack;
++ unsigned long sp;
++ int pid, status, n;
++
++ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++ if(stack == MAP_FAILED)
++ panic("start_userspace : mmap failed, errno = %d", errno);
++ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++
++ pid = clone(userspace_tramp, (void *) sp,
++ CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
++ if(pid < 0)
++ panic("start_userspace : clone failed, errno = %d", errno);
++
++ do {
++ n = waitpid(pid, &status, WUNTRACED);
++ if(n < 0)
++ panic("start_userspace : wait failed, errno = %d",
++ errno);
++ } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
++
++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
++ panic("start_userspace : expected SIGSTOP, got status = %d",
++ status);
++
++ if(munmap(stack, PAGE_SIZE) < 0)
++ panic("start_userspace : munmap failed, errno = %d\n", errno);
++
++ userspace_pid[cpu] = pid;
++}
++
++void userspace(union uml_pt_regs *regs)
++{
++ int err, status, op, pid = userspace_pid[0];
++
++ restore_registers(regs);
++
++ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
++ if(err)
++ panic("userspace - PTRACE_SYSCALL failed, errno = %d\n",
++ errno);
++ while(1){
++ err = waitpid(pid, &status, WUNTRACED);
++ if(err < 0)
++ panic("userspace - waitpid failed, errno = %d\n",
++ errno);
++
++ regs->skas.is_user = 1;
++ save_registers(regs);
++
++ if(WIFSTOPPED(status)){
++ switch(WSTOPSIG(status)){
++ case SIGSEGV:
++ handle_segv(pid);
++ break;
++ case SIGTRAP:
++ handle_trap(pid, regs);
++ break;
++ case SIGIO:
++ case SIGVTALRM:
++ case SIGILL:
++ case SIGBUS:
++ case SIGFPE:
++ case SIGWINCH:
++ user_signal(WSTOPSIG(status), regs);
++ break;
++ default:
++ printk("userspace - child stopped with signal "
++ "%d\n", WSTOPSIG(status));
++ }
++ interrupt_end();
++ }
++
++ restore_registers(regs);
++
++ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
++ PTRACE_SYSCALL;
++ err = ptrace(op, pid, 0, 0);
++ if(err)
++ panic("userspace - PTRACE_SYSCALL failed, "
++ "errno = %d\n", errno);
++ }
++}
++
++void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
++ void (*handler)(int))
++{
++ sigjmp_buf switch_buf, fork_buf;
++
++ *switch_buf_ptr = &switch_buf;
++ *fork_buf_ptr = &fork_buf;
++
++ if(sigsetjmp(fork_buf, 1) == 0)
++ new_thread_proc(stack, handler);
++
++ remove_sigstack();
++}
++
++void thread_wait(void *sw, void *fb)
++{
++ sigjmp_buf buf, **switch_buf = sw, *fork_buf;
++
++ *switch_buf = &buf;
++ fork_buf = fb;
++ if(sigsetjmp(buf, 1) == 0)
++ siglongjmp(*fork_buf, 1);
++}
++
++static int move_registers(int pid, int int_op, int fp_op,
++ union uml_pt_regs *regs, unsigned long *fp_regs)
++{
++ if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
++ return(-errno);
++ if(ptrace(fp_op, pid, 0, fp_regs) < 0)
++ return(-errno);
++ return(0);
++}
++
++void save_registers(union uml_pt_regs *regs)
++{
++ unsigned long *fp_regs;
++ int err, fp_op;
++
++ if(have_fpx_regs){
++ fp_op = PTRACE_GETFPXREGS;
++ fp_regs = regs->skas.xfp;
++ }
++ else {
++ fp_op = PTRACE_GETFPREGS;
++ fp_regs = regs->skas.fp;
++ }
++
++ err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs,
++ fp_regs);
++ if(err)
++ panic("save_registers - saving registers failed, errno = %d\n",
++ -err);
++}
++
++void restore_registers(union uml_pt_regs *regs)
++{
++ unsigned long *fp_regs;
++ int err, fp_op;
++
++ if(have_fpx_regs){
++ fp_op = PTRACE_SETFPXREGS;
++ fp_regs = regs->skas.xfp;
++ }
++ else {
++ fp_op = PTRACE_SETFPREGS;
++ fp_regs = regs->skas.fp;
++ }
++
++ err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs,
++ fp_regs);
++ if(err)
++ panic("restore_registers - saving registers failed, "
++ "errno = %d\n", -err);
++}
++
++void switch_threads(void *me, void *next)
++{
++ sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
++
++ *me_ptr = &my_buf;
++ if(sigsetjmp(my_buf, 1) == 0)
++ siglongjmp(*next_buf, 1);
++}
++
++static sigjmp_buf initial_jmpbuf;
++
++/* XXX Make these percpu */
++static void (*cb_proc)(void *arg);
++static void *cb_arg;
++static sigjmp_buf *cb_back;
++
++int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
++{
++ sigjmp_buf **switch_buf = switch_buf_ptr;
++ int n;
++
++ *fork_buf_ptr = &initial_jmpbuf;
++ n = sigsetjmp(initial_jmpbuf, 1);
++ if(n == 0)
++ new_thread_proc((void *) stack, new_thread_handler);
++ else if(n == 1)
++ remove_sigstack();
++ else if(n == 2){
++ (*cb_proc)(cb_arg);
++ siglongjmp(*cb_back, 1);
++ }
++ else if(n == 3){
++ kmalloc_ok = 0;
++ return(0);
++ }
++ else if(n == 4){
++ kmalloc_ok = 0;
++ return(1);
++ }
++ siglongjmp(**switch_buf, 1);
++}
++
++void remove_sigstack(void)
++{
++ stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
++ .ss_sp = NULL,
++ .ss_size = 0 });
++
++ if(sigaltstack(&stack, NULL) != 0)
++ panic("disabling signal stack failed, errno = %d\n", errno);
++}
++
++void initial_thread_cb_skas(void (*proc)(void *), void *arg)
++{
++ sigjmp_buf here;
++
++ cb_proc = proc;
++ cb_arg = arg;
++ cb_back = &here;
++
++ block_signals();
++ if(sigsetjmp(here, 1) == 0)
++ siglongjmp(initial_jmpbuf, 2);
++ unblock_signals();
++
++ cb_proc = NULL;
++ cb_arg = NULL;
++ cb_back = NULL;
++}
++
++void halt_skas(void)
++{
++ block_signals();
++ siglongjmp(initial_jmpbuf, 3);
++}
++
++void reboot_skas(void)
++{
++ block_signals();
++ siglongjmp(initial_jmpbuf, 4);
++}
++
++int new_mm(int from)
++{
++ struct proc_mm_op copy;
++ int n, fd = os_open_file("/proc/mm",
++ of_cloexec(of_write(OPENFLAGS())), 0);
++
++ if(fd < 0)
++ return(fd);
++
++ if(from != -1){
++ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
++ .u =
++ { .copy_segments = from } } );
++ n = os_write_file(fd, ©, sizeof(copy));
++ if(n != sizeof(copy))
++ printk("new_mm : /proc/mm copy_segments failed, "
++ "err = %d\n", -n);
++ }
++
++ return(fd);
++}
++
++void switch_mm_skas(int mm_fd)
++{
++ int err;
++
++#warning need cpu pid in switch_mm_skas
++ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
++ if(err)
++ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
++ errno);
++}
++
++void kill_off_processes_skas(void)
++{
++#warning need to loop over userspace_pids in kill_off_processes_skas
++ os_kill_process(userspace_pid[0], 1);
++}
++
++void init_registers(int pid)
++{
++ int err;
++
++ if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0)
++ panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
++ errno);
++
++ err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
++ if(!err)
++ return;
++
++ have_fpx_regs = 0;
++ if(errno != EIO)
++ panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
++ errno);
++
++ err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
++ if(err)
++ panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
++ errno);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/process_kern.c um/arch/um/kernel/skas/process_kern.c
+--- orig/arch/um/kernel/skas/process_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/process_kern.c 2003-11-19 03:18:25.000000000 -0500
+@@ -0,0 +1,196 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "kern_util.h"
++#include "time_user.h"
++#include "signal_user.h"
++#include "skas.h"
++#include "os.h"
++#include "user_util.h"
++#include "tlb.h"
++#include "frame.h"
++#include "kern.h"
++#include "mode.h"
++
++int singlestepping_skas(void)
++{
++ int ret = current->ptrace & PT_DTRACE;
++
++ current->ptrace &= ~PT_DTRACE;
++ return(ret);
++}
++
++void *_switch_to_skas(void *prev, void *next)
++{
++ struct task_struct *from, *to;
++
++ from = prev;
++ to = next;
++
++ /* XXX need to check runqueues[cpu].idle */
++ if(current->pid == 0)
++ switch_timers(0);
++
++ to->thread.prev_sched = from;
++ set_current(to);
++
++ switch_threads(&from->thread.mode.skas.switch_buf,
++ to->thread.mode.skas.switch_buf);
++
++ if(current->pid == 0)
++ switch_timers(1);
++
++ return(current->thread.prev_sched);
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++void new_thread_handler(int sig)
++{
++ int (*fn)(void *), n;
++ void *arg;
++
++ fn = current->thread.request.u.thread.proc;
++ arg = current->thread.request.u.thread.arg;
++ change_sig(SIGUSR1, 1);
++ thread_wait(¤t->thread.mode.skas.switch_buf,
++ current->thread.mode.skas.fork_buf);
++
++ if(current->thread.prev_sched != NULL)
++ schedule_tail(current->thread.prev_sched);
++ current->thread.prev_sched = NULL;
++
++ /* The return value is 1 if the kernel thread execs a process,
++ * 0 if it just exits
++ */
++ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
++ if(n == 1)
++ userspace(¤t->thread.regs.regs);
++ else do_exit(0);
++}
++
++void new_thread_proc(void *stack, void (*handler)(int sig))
++{
++ init_new_thread_stack(stack, handler);
++ os_usr1_process(os_getpid());
++}
++
++void release_thread_skas(struct task_struct *task)
++{
++}
++
++void exit_thread_skas(void)
++{
++}
++
++void fork_handler(int sig)
++{
++ change_sig(SIGUSR1, 1);
++ thread_wait(¤t->thread.mode.skas.switch_buf,
++ current->thread.mode.skas.fork_buf);
++
++ force_flush_all();
++ if(current->thread.prev_sched != NULL)
++ schedule_tail(current->thread.prev_sched);
++ current->thread.prev_sched = NULL;
++ unblock_signals();
++
++ userspace(¤t->thread.regs.regs);
++}
++
++int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct * p,
++ struct pt_regs *regs)
++{
++ void (*handler)(int);
++
++ if(current->thread.forking){
++ memcpy(&p->thread.regs.regs.skas,
++ ¤t->thread.regs.regs.skas,
++ sizeof(p->thread.regs.regs.skas));
++ REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
++ if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
++
++ handler = fork_handler;
++ }
++ else {
++ memcpy(p->thread.regs.regs.skas.regs, exec_regs,
++ sizeof(p->thread.regs.regs.skas.regs));
++ memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs,
++ sizeof(p->thread.regs.regs.skas.fp));
++ memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs,
++ sizeof(p->thread.regs.regs.skas.xfp));
++ p->thread.request.u.thread = current->thread.request.u.thread;
++ handler = new_thread_handler;
++ }
++
++ new_thread((void *) p->thread.kernel_stack,
++ &p->thread.mode.skas.switch_buf,
++ &p->thread.mode.skas.fork_buf, handler);
++ return(0);
++}
++
++void init_idle_skas(void)
++{
++ cpu_tasks[current->processor].pid = os_getpid();
++}
++
++extern void start_kernel(void);
++
++static int start_kernel_proc(void *unused)
++{
++ int pid;
++
++ block_signals();
++ pid = os_getpid();
++
++ cpu_tasks[0].pid = pid;
++ cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++ cpu_online_map = 1;
++#endif
++ start_kernel();
++ return(0);
++}
++
++int start_uml_skas(void)
++{
++ start_userspace(0);
++ capture_signal_stack();
++ idle_timer();
++
++ init_new_thread_signals(1);
++
++ init_task.thread.request.u.thread.proc = start_kernel_proc;
++ init_task.thread.request.u.thread.arg = NULL;
++ return(start_idle_thread((void *) init_task.thread.kernel_stack,
++ &init_task.thread.mode.skas.switch_buf,
++ &init_task.thread.mode.skas.fork_buf));
++}
++
++int external_pid_skas(struct task_struct *task)
++{
++#warning Need to look up userspace_pid by cpu
++ return(userspace_pid[0]);
++}
++
++int thread_pid_skas(struct thread_struct *thread)
++{
++#warning Need to look up userspace_pid by cpu
++ return(userspace_pid[0]);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/syscall_kern.c um/arch/um/kernel/skas/syscall_kern.c
+--- orig/arch/um/kernel/skas/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/syscall_kern.c 2004-01-04 08:20:29.000000000 -0500
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sys.h"
++#include "asm/errno.h"
++#include "asm/unistd.h"
++#include "asm/ptrace.h"
++#include "asm/current.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++extern syscall_handler_t *sys_call_table[];
++
++long execute_syscall_skas(void *r)
++{
++ struct pt_regs *regs = r;
++ long res;
++ int syscall;
++
++ current->thread.nsyscalls++;
++ nsyscalls++;
++ syscall = UPT_SYSCALL_NR(®s->regs);
++
++ if((syscall >= NR_syscalls) || (syscall < 1))
++ res = -ENOSYS;
++ else res = EXECUTE_SYSCALL(syscall, regs);
++
++ return(res);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/syscall_user.c um/arch/um/kernel/skas/syscall_user.c
+--- orig/arch/um/kernel/skas/syscall_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/syscall_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <signal.h>
++#include "kern_util.h"
++#include "syscall_user.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++
++/* XXX Bogus */
++#define ERESTARTSYS 512
++#define ERESTARTNOINTR 513
++#define ERESTARTNOHAND 514
++
++void handle_syscall(union uml_pt_regs *regs)
++{
++ long result;
++ int index;
++
++ index = record_syscall_start(UPT_SYSCALL_NR(regs));
++
++ syscall_trace();
++ result = execute_syscall(regs);
++
++ REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
++ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
++ (result == -ERESTARTNOINTR))
++ do_signal(result);
++
++ syscall_trace();
++ record_syscall_end(index, result);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/sys-i386/Makefile um/arch/um/kernel/skas/sys-i386/Makefile
+--- orig/arch/um/kernel/skas/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/sys-i386/Makefile 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,17 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = sys-i386.o
++
++obj-y = sigcontext.o
++
++USER_OBJS = sigcontext.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/sys-i386/sigcontext.c um/arch/um/kernel/skas/sys-i386/sigcontext.c
+--- orig/arch/um/kernel/skas/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/sys-i386/sigcontext.c 2003-11-19 03:27:43.000000000 -0500
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <asm/sigcontext.h>
++#include <sys/ptrace.h>
++#include <linux/ptrace.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/ptrace_user.h"
++#include "kern_util.h"
++#include "user.h"
++#include "sigcontext.h"
++#include "mode.h"
++
++int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr)
++{
++ struct sigcontext sc, *from = from_ptr;
++ unsigned long fpregs[FP_FRAME_SIZE];
++ int err;
++
++ err = copy_from_user_proc(&sc, from, sizeof(sc));
++ err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs));
++ if(err)
++ return(err);
++
++ regs->skas.regs[GS] = sc.gs;
++ regs->skas.regs[FS] = sc.fs;
++ regs->skas.regs[ES] = sc.es;
++ regs->skas.regs[DS] = sc.ds;
++ regs->skas.regs[EDI] = sc.edi;
++ regs->skas.regs[ESI] = sc.esi;
++ regs->skas.regs[EBP] = sc.ebp;
++ regs->skas.regs[UESP] = sc.esp;
++ regs->skas.regs[EBX] = sc.ebx;
++ regs->skas.regs[EDX] = sc.edx;
++ regs->skas.regs[ECX] = sc.ecx;
++ regs->skas.regs[EAX] = sc.eax;
++ regs->skas.regs[EIP] = sc.eip;
++ regs->skas.regs[CS] = sc.cs;
++ regs->skas.regs[EFL] = sc.eflags;
++ regs->skas.regs[SS] = sc.ss;
++ regs->skas.fault_addr = sc.cr2;
++ regs->skas.fault_type = FAULT_WRITE(sc.err);
++ regs->skas.trap_type = sc.trapno;
++
++ err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs);
++ if(err < 0){
++ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
++ "errno = %d\n", errno);
++ return(1);
++ }
++
++ return(0);
++}
++
++int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
++ union uml_pt_regs *regs, unsigned long fault_addr,
++ int fault_type)
++{
++ struct sigcontext sc, *to = to_ptr;
++ struct _fpstate *to_fp;
++ unsigned long fpregs[FP_FRAME_SIZE];
++ int err;
++
++ sc.gs = regs->skas.regs[GS];
++ sc.fs = regs->skas.regs[FS];
++ sc.es = regs->skas.regs[ES];
++ sc.ds = regs->skas.regs[DS];
++ sc.edi = regs->skas.regs[EDI];
++ sc.esi = regs->skas.regs[ESI];
++ sc.ebp = regs->skas.regs[EBP];
++ sc.esp = regs->skas.regs[UESP];
++ sc.ebx = regs->skas.regs[EBX];
++ sc.edx = regs->skas.regs[EDX];
++ sc.ecx = regs->skas.regs[ECX];
++ sc.eax = regs->skas.regs[EAX];
++ sc.eip = regs->skas.regs[EIP];
++ sc.cs = regs->skas.regs[CS];
++ sc.eflags = regs->skas.regs[EFL];
++ sc.esp_at_signal = regs->skas.regs[UESP];
++ sc.ss = regs->skas.regs[SS];
++ sc.cr2 = fault_addr;
++ sc.err = TO_SC_ERR(fault_type);
++ sc.trapno = regs->skas.trap_type;
++
++ err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs);
++ if(err < 0){
++ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, "
++ "errno = %d\n", errno);
++ return(1);
++ }
++ to_fp = (struct _fpstate *)
++ (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to)));
++ sc.fpstate = to_fp;
++
++ if(err)
++ return(err);
++
++ return(copy_to_user_proc(to, &sc, sizeof(sc)) ||
++ copy_to_user_proc(to_fp, fpregs, sizeof(fpregs)));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/time.c um/arch/um/kernel/skas/time.c
+--- orig/arch/um/kernel/skas/time.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/time.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <sys/signal.h>
++#include <sys/time.h>
++#include "time_user.h"
++#include "process.h"
++#include "user.h"
++
++void user_time_init_skas(void)
++{
++ if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++ panic("Couldn't set SIGALRM handler");
++ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++ panic("Couldn't set SIGVTALRM handler");
++ set_interval(ITIMER_VIRTUAL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/tlb.c um/arch/um/kernel/skas/tlb.c
+--- orig/arch/um/kernel/skas/tlb.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/tlb.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,153 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/mmu.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "skas.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, fd;
++
++ if(mm == NULL) return;
++ fd = mm->context.skas.mm_fd;
++ for(addr = start_addr; addr < end_addr;){
++ 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(fd, (void *) addr, PAGE_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ if(pte_present(*npte))
++ map(fd, addr,
++ pte_val(*npte) & PAGE_MASK,
++ PAGE_SIZE, r, w, x);
++ }
++ else if(pte_newprot(*npte)){
++ protect(fd, addr, PAGE_SIZE, r, w, x, 1);
++ }
++ *npte = pte_mkuptodate(*npte);
++ addr += PAGE_SIZE;
++ }
++ else {
++ if(force || pmd_newpage(*npmd)){
++ err = unmap(fd, (void *) addr, PMD_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ pmd_mkuptodate(*npmd);
++ }
++ addr += PMD_SIZE;
++ }
++ }
++}
++
++static void flush_kernel_vm_range(unsigned long start, unsigned long end)
++{
++ 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 = os_unmap_memory((void *) addr,
++ PAGE_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ if(pte_present(*pte))
++ map_memory(addr,
++ pte_val(*pte) & PAGE_MASK,
++ PAGE_SIZE, 1, 1, 1);
++ }
++ else if(pte_newprot(*pte)){
++ updated = 1;
++ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
++ }
++ addr += PAGE_SIZE;
++ }
++ else {
++ if(pmd_newpage(*pmd)){
++ updated = 1;
++ err = os_unmap_memory((void *) addr, PMD_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ }
++ addr += PMD_SIZE;
++ }
++ }
++}
++
++void flush_tlb_kernel_vm_skas(void)
++{
++ flush_kernel_vm_range(start_vm, end_vm);
++}
++
++void __flush_tlb_one_skas(unsigned long addr)
++{
++ flush_kernel_vm_range(addr, addr + PAGE_SIZE);
++}
++
++void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start,
++ unsigned long end)
++{
++ if(mm == NULL)
++ flush_kernel_vm_range(start, end);
++ else fix_range(mm, start, end, 0);
++}
++
++void flush_tlb_mm_skas(struct mm_struct *mm)
++{
++ flush_tlb_kernel_vm_skas();
++ fix_range(mm, 0, host_task_size, 0);
++}
++
++void force_flush_all_skas(void)
++{
++ fix_range(current->mm, 0, host_task_size, 1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/trap_user.c um/arch/um/kernel/skas/trap_user.c
+--- orig/arch/um/kernel/skas/trap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/trap_user.c 2004-01-21 01:17:05.000000000 -0500
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include <errno.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "task.h"
++#include "sigcontext.h"
++
++void sig_handler_common_skas(int sig, void *sc_ptr)
++{
++ struct sigcontext *sc = sc_ptr;
++ struct skas_regs *r;
++ struct signal_info *info;
++ int save_errno = errno;
++ int save_user;
++
++ r = &TASK_REGS(get_current())->skas;
++ save_user = r->is_user;
++ r->is_user = 0;
++ r->fault_addr = SC_FAULT_ADDR(sc);
++ r->fault_type = SC_FAULT_TYPE(sc);
++ r->trap_type = SC_TRAP_TYPE(sc);
++
++ change_sig(SIGUSR1, 1);
++ info = &sig_info[sig];
++ if(!info->is_irq) unblock_signals();
++
++ (*info->handler)(sig, (union uml_pt_regs *) r);
++
++ errno = save_errno;
++ r->is_user = save_user;
++}
++
++extern int missed_ticks[];
++
++void user_signal(int sig, union uml_pt_regs *regs)
++{
++ struct signal_info *info;
++
++ regs->skas.is_user = 1;
++ regs->skas.fault_addr = 0;
++ regs->skas.fault_type = 0;
++ regs->skas.trap_type = 0;
++ info = &sig_info[sig];
++ (*info->handler)(sig, regs);
++
++ unblock_signals();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/uaccess.c um/arch/um/kernel/skas/uaccess.c
+--- orig/arch/um/kernel/skas/uaccess.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/uaccess.c 2003-12-22 01:30:09.000000000 -0500
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/string.h"
++#include "linux/fs.h"
++#include "linux/highmem.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++
++extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
++ pte_t *pte_out);
++
++static unsigned long maybe_map(unsigned long virt, int is_write)
++{
++ pte_t pte;
++
++ void *phys = um_virt_to_phys(current, virt, &pte);
++ int dummy_code;
++
++ if(IS_ERR(phys) || (is_write && !pte_write(pte))){
++ if(!handle_page_fault(virt, 0, is_write, 0, &dummy_code))
++ return(0);
++ phys = um_virt_to_phys(current, virt, NULL);
++ }
++ return((unsigned long) phys);
++}
++
++static int do_op(unsigned long addr, int len, int is_write,
++ int (*op)(unsigned long addr, int len, void *arg), void *arg)
++{
++ struct page *page;
++ int n;
++
++ addr = maybe_map(addr, is_write);
++ if(addr == -1)
++ return(-1);
++
++ page = phys_to_page(addr);
++ addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
++ n = (*op)(addr, len, arg);
++ kunmap(page);
++
++ return(n);
++}
++
++static int buffer_op(unsigned long addr, int len, int is_write,
++ int (*op)(unsigned long addr, int len, void *arg),
++ void *arg)
++{
++ int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
++ int remain = len, n;
++
++ n = do_op(addr, size, is_write, op, arg);
++ if(n != 0)
++ return(n < 0 ? remain : 0);
++
++ addr += size;
++ remain -= size;
++ if(remain == 0)
++ return(0);
++
++ while(addr < ((addr + remain) & PAGE_MASK)){
++ n = do_op(addr, PAGE_SIZE, is_write, op, arg);
++ if(n != 0)
++ return(n < 0 ? remain : 0);
++
++ addr += PAGE_SIZE;
++ remain -= PAGE_SIZE;
++ }
++ if(remain == 0)
++ return(0);
++
++ n = do_op(addr, remain, is_write, op, arg);
++ if(n != 0)
++ return(n < 0 ? remain : 0);
++ return(0);
++}
++
++static int copy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++ unsigned long *to_ptr = arg, to = *to_ptr;
++
++ memcpy((void *) to, (void *) from, len);
++ *to_ptr += len;
++ return(0);
++}
++
++int copy_from_user_skas(void *to, const void *from, int n)
++{
++ if(segment_eq(get_fs(), KERNEL_DS)){
++ memcpy(to, from, n);
++ return(0);
++ }
++
++ return(access_ok_skas(VERIFY_READ, from, n) ?
++ buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
++ n);
++}
++
++static int copy_chunk_to_user(unsigned long to, int len, void *arg)
++{
++ unsigned long *from_ptr = arg, from = *from_ptr;
++
++ memcpy((void *) to, (void *) from, len);
++ *from_ptr += len;
++ return(0);
++}
++
++int copy_to_user_skas(void *to, const void *from, int n)
++{
++ if(segment_eq(get_fs(), KERNEL_DS)){
++ memcpy(to, from, n);
++ return(0);
++ }
++
++ return(access_ok_skas(VERIFY_WRITE, to, n) ?
++ buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
++ n);
++}
++
++static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++ char **to_ptr = arg, *to = *to_ptr;
++ int n;
++
++ strncpy(to, (void *) from, len);
++ n = strnlen(to, len);
++ *to_ptr += n;
++
++ if(n < len)
++ return(1);
++ return(0);
++}
++
++int strncpy_from_user_skas(char *dst, const char *src, int count)
++{
++ int n;
++ char *ptr = dst;
++
++ if(segment_eq(get_fs(), KERNEL_DS)){
++ strncpy(dst, src, count);
++ return(strnlen(dst, count));
++ }
++
++ if(!access_ok_skas(VERIFY_READ, src, 1))
++ return(-EFAULT);
++
++ n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
++ &ptr);
++ if(n != 0)
++ return(-EFAULT);
++ return(strnlen(dst, count));
++}
++
++static int clear_chunk(unsigned long addr, int len, void *unused)
++{
++ memset((void *) addr, 0, len);
++ return(0);
++}
++
++int __clear_user_skas(void *mem, int len)
++{
++ return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
++}
++
++int clear_user_skas(void *mem, int len)
++{
++ if(segment_eq(get_fs(), KERNEL_DS)){
++ memset(mem, 0, len);
++ return(0);
++ }
++
++ return(access_ok_skas(VERIFY_WRITE, mem, len) ?
++ buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
++}
++
++static int strnlen_chunk(unsigned long str, int len, void *arg)
++{
++ int *len_ptr = arg, n;
++
++ n = strnlen((void *) str, len);
++ *len_ptr += n;
++
++ if(n < len)
++ return(1);
++ return(0);
++}
++
++int strnlen_user_skas(const void *str, int len)
++{
++ int count = 0, n;
++
++ if(segment_eq(get_fs(), KERNEL_DS))
++ return(strnlen(str, len) + 1);
++
++ n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
++ if(n == 0)
++ return(count + 1);
++ return(-EFAULT);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/util/Makefile um/arch/um/kernel/skas/util/Makefile
+--- orig/arch/um/kernel/skas/util/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/util/Makefile 2003-11-08 02:52:22.000000000 -0500
+@@ -0,0 +1,10 @@
++all: mk_ptregs
++
++mk_ptregs : mk_ptregs.o
++ $(HOSTCC) -o mk_ptregs mk_ptregs.o
++
++mk_ptregs.o : mk_ptregs.c
++ $(HOSTCC) -c $<
++
++clean :
++ $(RM) -f mk_ptregs *.o *~
+diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/util/mk_ptregs.c um/arch/um/kernel/skas/util/mk_ptregs.c
+--- orig/arch/um/kernel/skas/util/mk_ptregs.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/skas/util/mk_ptregs.c 2003-12-22 01:31:11.000000000 -0500
+@@ -0,0 +1,51 @@
++#include <stdio.h>
++#include <asm/ptrace.h>
++#include <asm/user.h>
++
++#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
++
++int main(int argc, char **argv)
++{
++ printf("/* Automatically generated by "
++ "arch/um/kernel/skas/util/mk_ptregs */\n");
++ printf("\n");
++ printf("#ifndef __SKAS_PT_REGS_\n");
++ printf("#define __SKAS_PT_REGS_\n");
++ printf("\n");
++ printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
++ printf("#define HOST_FP_SIZE %d\n",
++ sizeof(struct user_i387_struct) / sizeof(unsigned long));
++ printf("#define HOST_XFP_SIZE %d\n",
++ sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
++
++ PRINT_REG("IP", EIP);
++ PRINT_REG("SP", UESP);
++ PRINT_REG("EFLAGS", EFL);
++ PRINT_REG("EAX", EAX);
++ PRINT_REG("EBX", EBX);
++ PRINT_REG("ECX", ECX);
++ PRINT_REG("EDX", EDX);
++ PRINT_REG("ESI", ESI);
++ PRINT_REG("EDI", EDI);
++ PRINT_REG("EBP", EBP);
++ PRINT_REG("CS", CS);
++ PRINT_REG("SS", SS);
++ PRINT_REG("DS", DS);
++ PRINT_REG("FS", FS);
++ PRINT_REG("ES", ES);
++ PRINT_REG("GS", GS);
++ printf("\n");
++ printf("#endif\n");
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/smp.c um/arch/um/kernel/smp.c
+--- orig/arch/um/kernel/smp.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/smp.c 2003-11-15 02:59:25.000000000 -0500
+@@ -0,0 +1,328 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.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 "asm/tlb.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "kern.h"
++#include "os.h"
++
++/* Total count of live CPUs, set by smp_boot_cpus */
++int smp_num_cpus = 1;
++
++/* The 'big kernel lock' */
++spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED};
++
++/* Per CPU bogomips and other parameters */
++
++/* The only piece used here is the ipi pipe, which is set before SMP is
++ * started and never changed.
++ */
++struct cpuinfo_um cpu_data[NR_CPUS];
++
++/* CPU online map, set by smp_boot_cpus */
++unsigned long cpu_online_map;
++
++atomic_t global_bh_count;
++
++/* Set when the idlers are all forked */
++int smp_threads_ready = 0;
++
++/* Not used by UML */
++unsigned char global_irq_holder = 0;
++unsigned volatile long global_irq_lock;
++
++/* A statistic, can be a little off */
++static int num_reschedules_sent = 0;
++
++mmu_gather_t mmu_gathers[NR_CPUS];
++
++void smp_send_reschedule(int cpu)
++{
++ os_write_file(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)
++{
++ int i;
++
++ printk(KERN_INFO "Stopping all CPUs...");
++ for(i = 0; i < ncpus; i++){
++ if(i == current->processor)
++ continue;
++ os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
++ }
++ printk("done\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 < 0)
++ panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
++
++ activate_ipi(cpu_data[cpu].ipi_pipe[0],
++ current->thread.mode.tt.extern_pid);
++
++ wmb();
++ if (test_and_set_bit(current->processor, &smp_callin_map)) {
++ printk("huh, CPU#%d already present??\n", current->processor);
++ BUG();
++ }
++
++ while (!atomic_read(&smp_commenced))
++ cpu_relax();
++
++ init_idle();
++ cpu_idle();
++ return(0);
++}
++
++static int idle_thread(int (*fn)(void *), 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] = ((struct cpu_task)
++ { .pid = new_task->thread.mode.tt.extern_pid,
++ .task = new_task } );
++ init_tasks[cpu] = new_task;
++ new_task->processor = cpu;
++ new_task->cpus_allowed = 1 << cpu;
++ new_task->cpus_runnable = new_task->cpus_allowed;
++ CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
++ sizeof(c)),
++ ({ panic("skas mode doesn't support SMP"); }));
++ return(new_task->thread.mode.tt.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 < 0)
++ panic("CPU#0 failed to create IPI pipe, err = %d", -err);
++
++ activate_ipi(cpu_data[0].ipi_pipe[0],
++ current->thread.mode.tt.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 (os_read_file(fd, &c, 1) == 1) {
++ switch (c) {
++ case 'C':
++ smp_call_function_slave(cpu);
++ break;
++
++ case 'R':
++ current->need_resched = 1;
++ break;
++
++ case 'S':
++ printk("CPU#%d stopping\n", cpu);
++ while(1)
++ pause();
++ break;
++
++ default:
++ printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
++ break;
++ }
++ }
++}
++
++int hard_smp_processor_id(void)
++{
++ return(pid_to_processor_id(os_getpid()));
++}
++
++static 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))
++ os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
++
++ while (atomic_read(&scf_started) != cpus)
++ barrier();
++
++ if (wait)
++ while (atomic_read(&scf_finished) != cpus)
++ barrier();
++
++ spin_unlock_bh(&call_lock);
++ return 0;
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/syscall_kern.c um/arch/um/kernel/syscall_kern.c
+--- orig/arch/um/kernel/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/syscall_kern.c 2004-01-10 06:37:46.000000000 -0500
+@@ -0,0 +1,343 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/file.h"
++#include "linux/smp_lock.h"
++#include "linux/mm.h"
++#include "linux/utsname.h"
++#include "linux/msg.h"
++#include "linux/shm.h"
++#include "linux/sys.h"
++#include "linux/unistd.h"
++#include "linux/slab.h"
++#include "linux/utime.h"
++#include "asm/mman.h"
++#include "asm/uaccess.h"
++#include "asm/ipc.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "sysdep/syscalls.h"
++#include "mode_kern.h"
++#include "choose-mode.h"
++
++/* Unlocked, I don't care if this is a bit off */
++int nsyscalls = 0;
++
++long 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 */
++long do_mmap2(struct mm_struct *mm, 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(&mm->mmap_sem);
++ error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&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(current->mm, 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(current->mm, 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, sizeof(fd)))
++ 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)));
++}
++
++long execute_syscall(void *r)
++{
++ return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
++}
++
++spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
++
++static int syscall_index = 0;
++
++int next_syscall_index(int limit)
++{
++ int ret;
++
++ spin_lock(&syscall_lock);
++ ret = syscall_index;
++ if(++syscall_index == limit)
++ syscall_index = 0;
++ spin_unlock(&syscall_lock);
++ return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/sys_call_table.c um/arch/um/kernel/sys_call_table.c
+--- orig/arch/um/kernel/sys_call_table.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/sys_call_table.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,496 @@
++/*
++ * 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;
++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 sys_tkill;
++extern syscall_handler_t sys_setxattr;
++extern syscall_handler_t sys_lsetxattr;
++extern syscall_handler_t sys_fsetxattr;
++extern syscall_handler_t sys_getxattr;
++extern syscall_handler_t sys_lgetxattr;
++extern syscall_handler_t sys_fgetxattr;
++extern syscall_handler_t sys_listxattr;
++extern syscall_handler_t sys_llistxattr;
++extern syscall_handler_t sys_flistxattr;
++extern syscall_handler_t sys_removexattr;
++extern syscall_handler_t sys_lremovexattr;
++extern syscall_handler_t sys_fremovexattr;
++extern syscall_handler_t sys_sendfile64;
++
++extern syscall_handler_t um_mount;
++extern syscall_handler_t um_time;
++extern syscall_handler_t um_stime;
++
++#define LAST_GENERIC_SYSCALL __NR_exit_group
++
++#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 ] = 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 ] = 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 *) 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_setxattr,
++ [ __NR_lsetxattr ] = sys_lsetxattr,
++ [ __NR_fsetxattr ] = sys_fsetxattr,
++ [ __NR_getxattr ] = sys_getxattr,
++ [ __NR_lgetxattr ] = sys_lgetxattr,
++ [ __NR_fgetxattr ] = sys_fgetxattr,
++ [ __NR_listxattr ] = sys_listxattr,
++ [ __NR_llistxattr ] = sys_llistxattr,
++ [ __NR_flistxattr ] = sys_flistxattr,
++ [ __NR_removexattr ] = sys_removexattr,
++ [ __NR_lremovexattr ] = sys_lremovexattr,
++ [ __NR_fremovexattr ] = sys_fremovexattr,
++ [ __NR_tkill ] = sys_tkill,
++ [ __NR_sendfile64 ] = sys_sendfile64,
++ [ __NR_futex ] = sys_ni_syscall,
++ [ __NR_sched_setaffinity ] = sys_ni_syscall,
++ [ __NR_sched_getaffinity ] = sys_ni_syscall,
++ [ __NR_set_thread_area ] = sys_ni_syscall,
++ [ __NR_get_thread_area ] = sys_ni_syscall,
++ [ __NR_io_setup ] = sys_ni_syscall,
++ [ __NR_io_destroy ] = sys_ni_syscall,
++ [ __NR_io_getevents ] = sys_ni_syscall,
++ [ __NR_io_submit ] = sys_ni_syscall,
++ [ __NR_io_cancel ] = sys_ni_syscall,
++ [ __NR_alloc_hugepages ] = sys_ni_syscall,
++ [ __NR_free_hugepages ] = sys_ni_syscall,
++ [ __NR_exit_group ] = sys_ni_syscall,
++
++ ARCH_SYSCALLS
++ [ LAST_SYSCALL + 1 ... NR_syscalls ] =
++ (syscall_handler_t *) sys_ni_syscall
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/syscall_user.c um/arch/um/kernel/syscall_user.c
+--- orig/arch/um/kernel/syscall_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/syscall_user.c 2003-12-22 01:32:48.000000000 -0500
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <sys/time.h>
++#include "kern_util.h"
++#include "syscall_user.h"
++
++struct {
++ int syscall;
++ int pid;
++ int result;
++ struct timeval start;
++ struct timeval end;
++} syscall_record[1024];
++
++int record_syscall_start(int syscall)
++{
++ int max, index;
++
++ max = sizeof(syscall_record)/sizeof(syscall_record[0]);
++ index = next_syscall_index(max);
++
++ syscall_record[index].syscall = syscall;
++ syscall_record[index].pid = current_pid();
++ syscall_record[index].result = 0xdeadbeef;
++ gettimeofday(&syscall_record[index].start, NULL);
++ return(index);
++}
++
++void record_syscall_end(int index, int result)
++{
++ syscall_record[index].result = result;
++ gettimeofday(&syscall_record[index].end, NULL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/sysrq.c um/arch/um/kernel/sysrq.c
+--- orig/arch/um/kernel/sysrq.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/sysrq.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tempfile.c um/arch/um/kernel/tempfile.c
+--- orig/arch/um/kernel/tempfile.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tempfile.c 2003-12-22 01:33:38.000000000 -0500
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/param.h>
++#include "init.h"
++
++/* Modified from create_mem_file and start_debugger */
++static char *tempdir = NULL;
++
++static void __init find_tempdir(void)
++{
++ char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
++ int i;
++ char *dir = NULL;
++
++ if(tempdir != NULL) return; /* We've already been called */
++ for(i = 0; dirs[i]; i++){
++ dir = getenv(dirs[i]);
++ if((dir != NULL) && (*dir != '\0'))
++ break;
++ }
++ if((dir == NULL) || (*dir == '\0'))
++ dir = "/tmp";
++
++ tempdir = malloc(strlen(dir) + 2);
++ if(tempdir == NULL){
++ fprintf(stderr, "Failed to malloc tempdir, "
++ "errno = %d\n", errno);
++ return;
++ }
++ strcpy(tempdir, dir);
++ strcat(tempdir, "/");
++}
++
++int make_tempfile(const char *template, char **out_tempname, int do_unlink)
++{
++ char tempname[MAXPATHLEN];
++ int fd;
++
++ find_tempdir();
++ if (*template != '/')
++ strcpy(tempname, tempdir);
++ else
++ *tempname = 0;
++ strcat(tempname, template);
++ fd = mkstemp(tempname);
++ if(fd < 0){
++ fprintf(stderr, "open - cannot create %s: %s\n", tempname,
++ strerror(errno));
++ return -1;
++ }
++ if(do_unlink && (unlink(tempname) < 0)){
++ perror("unlink");
++ return -1;
++ }
++ if(out_tempname){
++ *out_tempname = strdup(tempname);
++ if(*out_tempname == NULL){
++ perror("strdup");
++ return -1;
++ }
++ }
++ return(fd);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/time.c um/arch/um/kernel/time.c
+--- orig/arch/um/kernel/time.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/time.c 2004-02-12 07:09:48.000000000 -0500
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <time.h>
++#include <sys/time.h>
++#include <signal.h>
++#include <errno.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++#include "time_user.h"
++
++extern struct timeval xtime;
++
++struct timeval local_offset = { 0, 0 };
++
++void timer(void)
++{
++ gettimeofday(&xtime, NULL);
++ timeradd(&xtime, &local_offset, &xtime);
++}
++
++void set_interval(int timer_type)
++{
++ int usec = 1000000/hz();
++ struct itimerval interval = ((struct itimerval) { { 0, usec },
++ { 0, usec } });
++
++ if(setitimer(timer_type, &interval, NULL) == -1)
++ panic("setitimer failed - errno = %d\n", errno);
++}
++
++void enable_timer(void)
++{
++ int usec = 1000000/hz();
++ struct itimerval enable = ((struct itimerval) { { 0, usec },
++ { 0, usec }});
++ if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
++ printk("enable_timer - setitimer failed, errno = %d\n",
++ errno);
++}
++
++void switch_timers(int to_real)
++{
++ struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
++ struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
++ { 0, 1000000/hz() }});
++ int old, new;
++
++ if(to_real){
++ old = ITIMER_VIRTUAL;
++ new = ITIMER_REAL;
++ }
++ else {
++ old = ITIMER_REAL;
++ new = ITIMER_VIRTUAL;
++ }
++
++ if((setitimer(old, &disable, NULL) < 0) ||
++ (setitimer(new, &enable, NULL)))
++ printk("switch_timers - setitimer failed, errno = %d\n",
++ errno);
++}
++
++void idle_timer(void)
++{
++ if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
++ panic("Couldn't unset SIGVTALRM handler");
++
++ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
++ SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
++ set_interval(ITIMER_REAL);
++}
++
++static unsigned long long get_host_hz(void)
++{
++ char mhzline[16], *end;
++ unsigned long long mhz;
++ int ret, mult, rest, len;
++
++ ret = cpu_feature("cpu MHz", mhzline,
++ sizeof(mhzline) / sizeof(mhzline[0]));
++ if(!ret)
++ panic ("Could not get host MHZ");
++
++ mhz = strtoul(mhzline, &end, 10);
++
++ /* This business is to parse a floating point number without using
++ * floating types.
++ */
++
++ rest = 0;
++ mult = 0;
++ if(*end == '.'){
++ end++;
++ len = strlen(end);
++ if(len < 6)
++ mult = 6 - len;
++ else if(len > 6)
++ end[6] = '\0';
++ rest = strtoul(end, NULL, 10);
++ while(mult-- > 0)
++ rest *= 10;
++ }
++
++ return(1000000 * mhz + rest);
++}
++
++unsigned long long host_hz = 0;
++
++void time_init(void)
++{
++ /* XXX This is to fill xtime with something real - otherwise by the
++ * time /proc is mounted, no timers have fired, and xtime is still 0,
++ * meaning it shows times of Jan 1 1970. The real fix is to figure
++ * out why no timers have happened by then.
++ */
++ timer();
++
++ host_hz = get_host_hz();
++ if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
++ panic("Couldn't set SIGVTALRM handler");
++ set_interval(ITIMER_VIRTUAL);
++}
++
++void do_gettimeofday(struct timeval *tv)
++{
++ unsigned long flags;
++
++ flags = time_lock();
++ gettimeofday(tv, NULL);
++ timeradd(tv, &local_offset, tv);
++ time_unlock(flags);
++}
++
++void do_settimeofday(struct timeval *tv)
++{
++ struct timeval now;
++ unsigned long flags;
++
++ flags = time_lock();
++ gettimeofday(&now, NULL);
++ timersub(tv, &now, &local_offset);
++ time_unlock(flags);
++}
++
++void idle_sleep(int secs)
++{
++ struct timespec ts;
++
++ ts.tv_sec = secs;
++ ts.tv_nsec = 0;
++ nanosleep(&ts, NULL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/time_kern.c um/arch/um/kernel/time_kern.c
+--- orig/arch/um/kernel/time_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/time_kern.c 2004-02-14 06:51:31.000000000 -0500
+@@ -0,0 +1,205 @@
++/*
++ * 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"
++#include "time_user.h"
++#include "mode.h"
++
++extern rwlock_t xtime_lock;
++
++int hz(void)
++{
++ return(HZ);
++}
++
++/* Changed at early boot */
++int timer_irq_inited = 0;
++
++/* missed_ticks will be 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"))) missed_ticks[NR_CPUS];
++
++static int first_tick;
++static unsigned long long prev_tsc;
++static long long delta; /* Deviation per interval */
++
++extern unsigned long long host_hz;
++
++void timer_irq(union uml_pt_regs *regs)
++{
++ unsigned long long ticks = 0;
++
++ if(!timer_irq_inited){
++ /* This is to ensure that ticks don't pile up when
++ * the timer handler is suspended */
++ first_tick = 0;
++ return;
++ }
++
++ if(first_tick){
++#if defined(CONFIG_UML_REAL_TIME_CLOCK)
++ unsigned long long tsc;
++ /* We've had 1 tick */
++ tsc = time_stamp();
++
++ delta += tsc - prev_tsc;
++ prev_tsc = tsc;
++
++ ticks += (delta * HZ) / host_hz;
++ delta -= (ticks * host_hz) / HZ;
++#else
++ ticks = 1;
++#endif
++ }
++ else {
++ prev_tsc = time_stamp();
++ first_tick = 1;
++ }
++
++ while(ticks > 0){
++ do_IRQ(TIMER_IRQ, regs);
++ ticks--;
++ }
++}
++
++void boot_timer_handler(int sig)
++{
++ struct pt_regs regs;
++
++ CHOOSE_MODE((void)
++ (UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)),
++ (void) (regs.regs.skas.is_user = 0));
++ do_timer(®s);
++}
++
++void um_timer(int irq, void *dev, struct pt_regs *regs)
++{
++ do_timer(regs);
++ write_lock(&xtime_lock);
++ vxtime_lock();
++ timer();
++ vxtime_unlock();
++ 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;
++}
++
++/* XXX Needs to be moved under sys-i386 */
++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++) ;
++}
++
++void timer_handler(int sig, union uml_pt_regs *regs)
++{
++#ifdef CONFIG_SMP
++ update_process_times(user_context(UPT_SP(regs)));
++#endif
++ if(current->processor == 0)
++ timer_irq(regs);
++}
++
++static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED;
++
++unsigned long time_lock(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&timer_spinlock, flags);
++ return(flags);
++}
++
++void time_unlock(unsigned long flags)
++{
++ spin_unlock_irqrestore(&timer_spinlock, flags);
++}
++
++int __init timer_init(void)
++{
++ int err;
++
++ CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
++ err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
++ if(err != 0)
++ printk(KERN_ERR "timer_init : request_irq failed - "
++ "errno = %d\n", -err);
++ timer_irq_inited = 1;
++ return(0);
++}
++
++__initcall(timer_init);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tlb.c um/arch/um/kernel/tlb.c
+--- orig/arch/um/kernel/tlb.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tlb.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,80 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "asm/page.h"
++#include "asm/pgalloc.h"
++#include "choose-mode.h"
++#include "mode_kern.h"
++
++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 flush_tlb_kernel_vm(void)
++{
++ CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas());
++}
++
++void __flush_tlb_one(unsigned long addr)
++{
++ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
++}
++
++void flush_tlb_range(struct mm_struct *mm, unsigned long start,
++ unsigned long end)
++{
++ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, mm, start,
++ end);
++}
++
++void flush_tlb_mm(struct mm_struct *mm)
++{
++ CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
++}
++
++void force_flush_all(void)
++{
++ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
++}
++
++
++pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
++{
++ return(pgd_offset(mm, address));
++}
++
++pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address)
++{
++ return(pmd_offset(pgd, address));
++}
++
++pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
++{
++ return(pte_offset(pmd, address));
++}
++
++pte_t *addr_pte(struct task_struct *task, unsigned long addr)
++{
++ return(pte_offset(pmd_offset(pgd_offset(task->mm, addr), addr), addr));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/trap_kern.c um/arch/um/kernel/trap_kern.c
+--- orig/arch/um/kernel/trap_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/trap_kern.c 2003-12-22 22:48:41.000000000 -0500
+@@ -0,0 +1,220 @@
++/*
++ * 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 "asm/irq.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "chan_kern.h"
++#include "mconsole_kern.h"
++#include "2_5compat.h"
++#include "mem.h"
++#include "mem_kern.h"
++
++unsigned long handle_page_fault(unsigned long address, unsigned long ip,
++ int is_write, int is_user, int *code_out)
++{
++ struct mm_struct *mm = current->mm;
++ struct vm_area_struct *vma;
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ unsigned long page;
++ int handled = 0;
++
++ *code_out = SEGV_MAPERR;
++ down_read(&mm->mmap_sem);
++ vma = find_vma(mm, address);
++ if(!vma)
++ goto out;
++ else if(vma->vm_start <= address)
++ goto good_area;
++ else if(!(vma->vm_flags & VM_GROWSDOWN))
++ goto out;
++ else if(expand_stack(vma, address))
++ goto out;
++
++ good_area:
++ *code_out = SEGV_ACCERR;
++ if(is_write && !(vma->vm_flags & VM_WRITE))
++ goto out;
++ page = address & PAGE_MASK;
++ 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 out;
++ }
++ pte = pte_offset(pmd, page);
++ } while(!pte_present(*pte));
++ handled = 1;
++ *pte = pte_mkyoung(*pte);
++ if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
++ flush_tlb_page(vma, page);
++ out:
++ up_read(&mm->mmap_sem);
++ return(handled);
++}
++
++LIST_HEAD(physmem_remappers);
++
++void register_remapper(struct remapper *info)
++{
++ list_add(&info->list, &physmem_remappers);
++}
++
++static int check_remapped_addr(unsigned long address, int is_write)
++{
++ struct remapper *remapper;
++ struct list_head *ele;
++ __u64 offset;
++ int fd;
++
++ fd = phys_mapping(__pa(address), &offset);
++ if(fd == -1)
++ return(0);
++
++ list_for_each(ele, &physmem_remappers){
++ remapper = list_entry(ele, struct remapper, list);
++ if((*remapper->proc)(fd, address, is_write, offset))
++ return(1);
++ }
++
++ return(0);
++}
++
++unsigned long segv(unsigned long address, unsigned long ip, int is_write,
++ int is_user, void *sc)
++{
++ struct siginfo si;
++ void *catcher;
++ int handled;
++
++ if(!is_user && (address >= start_vm) && (address < end_vm)){
++ flush_tlb_kernel_vm();
++ return(0);
++ }
++ else if(check_remapped_addr(address & PAGE_MASK, is_write))
++ return(0);
++ else if(current->mm == NULL)
++ panic("Segfault with no mm");
++
++ handled = handle_page_fault(address, ip, is_write, is_user,
++ &si.si_code);
++
++ catcher = current->thread.fault_catcher;
++ if(handled)
++ return(0);
++ else if(catcher != NULL){
++ current->thread.fault_addr = (void *) address;
++ do_longjmp(catcher, 1);
++ }
++ else if(current->thread.fault_addr != NULL)
++ panic("fault_addr set but no fault catcher");
++ else if(arch_fixup(ip, sc))
++ return(0);
++
++ if(!is_user)
++ panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
++ address, ip);
++ si.si_signo = SIGSEGV;
++ si.si_addr = (void *) address;
++ current->thread.cr2 = address;
++ current->thread.err = is_write;
++ force_sig_info(SIGSEGV, &si, current);
++ return(0);
++}
++
++void bad_segv(unsigned long address, unsigned long ip, int is_write)
++{
++ struct siginfo si;
++
++ si.si_signo = SIGSEGV;
++ si.si_code = SEGV_ACCERR;
++ si.si_addr = (void *) address;
++ current->thread.cr2 = address;
++ current->thread.err = is_write;
++ force_sig_info(SIGSEGV, &si, current);
++}
++
++void relay_signal(int sig, union uml_pt_regs *regs)
++{
++ if(arch_handle_signal(sig, regs)) return;
++ if(!UPT_IS_USER(regs))
++ panic("Kernel mode signal %d", sig);
++ force_sig(sig, current);
++}
++
++void bus_handler(int sig, union uml_pt_regs *regs)
++{
++ if(current->thread.fault_catcher != NULL)
++ do_longjmp(current->thread.fault_catcher, 1);
++ else relay_signal(sig, regs);
++}
++
++void winch(int sig, union uml_pt_regs *regs)
++{
++ do_IRQ(WINCH_IRQ, regs);
++}
++
++void trap_init(void)
++{
++}
++
++spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
++
++static int trap_index = 0;
++
++int next_trap_index(int limit)
++{
++ int ret;
++
++ spin_lock(&trap_lock);
++ ret = trap_index;
++ if(++trap_index == limit)
++ trap_index = 0;
++ spin_unlock(&trap_lock);
++ return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/trap_user.c um/arch/um/kernel/trap_user.c
+--- orig/arch/um/kernel/trap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/trap_user.c 2004-01-31 02:47:39.000000000 -0500
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <setjmp.h>
++#include <signal.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/wait.h>
++#include <asm/page.h>
++#include <asm/unistd.h>
++#include <asm/ptrace.h>
++#include "init.h"
++#include "sysdep/ptrace.h"
++#include "sigcontext.h"
++#include "sysdep/sigcontext.h"
++#include "irq_user.h"
++#include "frame_user.h"
++#include "signal_user.h"
++#include "time_user.h"
++#include "task.h"
++#include "mode.h"
++#include "choose-mode.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++
++void kill_child_dead(int pid)
++{
++ kill(pid, SIGKILL);
++ kill(pid, SIGCONT);
++ while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
++}
++
++/* Unlocked - don't care if this is a bit off */
++int nsegfaults = 0;
++
++struct {
++ unsigned long address;
++ int is_write;
++ int pid;
++ unsigned long sp;
++ int is_user;
++} segfault_record[1024];
++
++void segv_handler(int sig, union uml_pt_regs *regs)
++{
++ int index, max;
++
++ if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){
++ bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs),
++ UPT_FAULT_WRITE(regs));
++ return;
++ }
++ max = sizeof(segfault_record)/sizeof(segfault_record[0]);
++ index = next_trap_index(max);
++
++ nsegfaults++;
++ segfault_record[index].address = UPT_FAULT_ADDR(regs);
++ segfault_record[index].pid = os_getpid();
++ segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
++ segfault_record[index].sp = UPT_SP(regs);
++ segfault_record[index].is_user = UPT_IS_USER(regs);
++ segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
++ UPT_IS_USER(regs), regs);
++}
++
++void usr2_handler(int sig, union uml_pt_regs *regs)
++{
++ CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
++}
++
++struct signal_info sig_info[] = {
++ [ SIGTRAP ] { .handler = relay_signal,
++ .is_irq = 0 },
++ [ SIGFPE ] { .handler = relay_signal,
++ .is_irq = 0 },
++ [ SIGILL ] { .handler = relay_signal,
++ .is_irq = 0 },
++ [ SIGWINCH ] { .handler = winch,
++ .is_irq = 1 },
++ [ SIGBUS ] { .handler = bus_handler,
++ .is_irq = 0 },
++ [ SIGSEGV] { .handler = segv_handler,
++ .is_irq = 0 },
++ [ SIGIO ] { .handler = sigio_handler,
++ .is_irq = 1 },
++ [ SIGVTALRM ] { .handler = timer_handler,
++ .is_irq = 1 },
++ [ SIGALRM ] { .handler = timer_handler,
++ .is_irq = 1 },
++ [ SIGUSR2 ] { .handler = usr2_handler,
++ .is_irq = 0 },
++};
++
++void sig_handler(int sig, struct sigcontext sc)
++{
++ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
++ sig, &sc);
++}
++
++extern int timer_irq_inited, missed_ticks[];
++
++void alarm_handler(int sig, struct sigcontext sc)
++{
++ if(!timer_irq_inited) return;
++ missed_ticks[cpu()]++;
++
++ if(sig == SIGALRM)
++ switch_timers(0);
++
++ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
++ sig, &sc);
++
++ if(sig == SIGALRM)
++ switch_timers(1);
++}
++
++void do_longjmp(void *b, int val)
++{
++ sigjmp_buf *buf = b;
++
++ siglongjmp(*buf, val);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/exec_kern.c um/arch/um/kernel/tt/exec_kern.c
+--- orig/arch/um/kernel/tt/exec_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/exec_kern.c 2003-11-07 02:23:10.000000000 -0500
+@@ -0,0 +1,84 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/mm.h"
++#include "asm/signal.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/pgalloc.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "time_user.h"
++#include "mem_user.h"
++#include "os.h"
++#include "tlb.h"
++#include "mode.h"
++
++static int exec_tramp(void *sig_stack)
++{
++ init_new_thread_stack(sig_stack, NULL);
++ init_new_thread_signals(1);
++ os_stop_process(os_getpid());
++ return(0);
++}
++
++void flush_thread_tt(void)
++{
++ unsigned long stack;
++ int new_pid;
++
++ stack = alloc_stack(0, 0);
++ if(stack == 0){
++ printk(KERN_ERR
++ "flush_thread : failed to allocate temporary stack\n");
++ do_exit(SIGKILL);
++ }
++
++ new_pid = start_fork_tramp((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->processor == 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());
++
++ enable_timer();
++ free_page(stack);
++ protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
++ task_protections((unsigned long) current);
++ force_flush_all();
++ unblock_signals();
++}
++
++void start_thread_tt(struct pt_regs *regs, unsigned long eip,
++ unsigned long esp)
++{
++ set_fs(USER_DS);
++ flush_tlb_mm(current->mm);
++ PT_REGS_IP(regs) = eip;
++ PT_REGS_SP(regs) = esp;
++ PT_FIX_EXEC_STACK(esp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/exec_user.c um/arch/um/kernel/tt/exec_user.c
+--- orig/arch/um/kernel/tt/exec_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/exec_user.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/gdb.c um/arch/um/kernel/tt/gdb.c
+--- orig/arch/um/kernel/tt/gdb.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/gdb.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,278 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/ptrace.h>
++#include <sys/types.h>
++#include "uml-config.h"
++#include "kern_constants.h"
++#include "chan_user.h"
++#include "init.h"
++#include "user.h"
++#include "debug.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "tt.h"
++#include "sysdep/thread.h"
++
++extern int debugger_pid;
++extern int debugger_fd;
++extern int debugger_parent;
++
++int detach(int pid, int sig)
++{
++ return(ptrace(PTRACE_DETACH, pid, 0, sig));
++}
++
++int attach(int pid)
++{
++ int err;
++
++ err = ptrace(PTRACE_ATTACH, pid, 0, 0);
++ if(err < 0) return(-errno);
++ else return(err);
++}
++
++int cont(int pid)
++{
++ return(ptrace(PTRACE_CONT, pid, 0, 0));
++}
++
++#ifdef UML_CONFIG_PT_PROXY
++
++int debugger_signal(int status, pid_t pid)
++{
++ return(debugger_proxy(status, pid));
++}
++
++void child_signal(pid_t pid, int status)
++{
++ child_proxy(pid, status);
++}
++
++static void gdb_announce(char *dev_name, int dev)
++{
++ printf("gdb assigned device '%s'\n", dev_name);
++}
++
++static struct chan_opts opts = {
++ .announce = gdb_announce,
++ .xterm_title = "UML kernel debugger",
++ .raw = 0,
++ .tramp_stack = 0,
++ .in_kernel = 0,
++};
++
++/* Accessed by the tracing thread, which automatically serializes access */
++static void *xterm_data;
++static int xterm_fd;
++
++extern void *xterm_init(char *, int, struct chan_opts *);
++extern int xterm_open(int, int, int, void *, char **);
++extern void xterm_close(int, void *);
++
++int open_gdb_chan(void)
++{
++ char stack[UM_KERN_PAGE_SIZE], *dummy;
++
++ opts.tramp_stack = (unsigned long) stack;
++ xterm_data = xterm_init("", 0, &opts);
++ xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
++ return(xterm_fd);
++}
++
++static void exit_debugger_cb(void *unused)
++{
++ if(debugger_pid != -1){
++ if(gdb_pid != -1){
++ fake_child_exit();
++ gdb_pid = -1;
++ }
++ else kill_child_dead(debugger_pid);
++ debugger_pid = -1;
++ if(debugger_parent != -1)
++ detach(debugger_parent, SIGINT);
++ }
++ if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
++}
++
++static void exit_debugger(void)
++{
++ initial_thread_cb(exit_debugger_cb, NULL);
++}
++
++__uml_exitcall(exit_debugger);
++
++struct gdb_data {
++ char *str;
++ int err;
++};
++
++static void config_gdb_cb(void *arg)
++{
++ struct gdb_data *data = arg;
++ void *task;
++ int pid;
++
++ data->err = -1;
++ if(debugger_pid != -1) exit_debugger_cb(NULL);
++ if(!strncmp(data->str, "pid,", strlen("pid,"))){
++ data->str += strlen("pid,");
++ pid = strtoul(data->str, NULL, 0);
++ task = cpu_tasks[0].task;
++ debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
++ if(debugger_pid != -1){
++ data->err = 0;
++ gdb_pid = pid;
++ }
++ return;
++ }
++ data->err = 0;
++ debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
++ init_proxy(debugger_pid, 0, 0);
++}
++
++int gdb_config(char *str)
++{
++ struct gdb_data data;
++
++ if(*str++ != '=') return(-1);
++ data.str = str;
++ initial_thread_cb(config_gdb_cb, &data);
++ return(data.err);
++}
++
++void remove_gdb_cb(void *unused)
++{
++ exit_debugger_cb(NULL);
++}
++
++int gdb_remove(char *unused)
++{
++ initial_thread_cb(remove_gdb_cb, NULL);
++ return(0);
++}
++
++void signal_usr1(int sig)
++{
++ if(debugger_pid != -1){
++ printk(UM_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 = 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(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++ kill_child_dead(idle_pid);
++ exit(1);
++}
++
++void signal_usr1(int sig)
++{
++ printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++}
++
++int attach_debugger(int idle_pid, int pid, int stop)
++{
++ printk(UM_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/gdb_kern.c um/arch/um/kernel/tt/gdb_kern.c
+--- orig/arch/um/kernel/tt/gdb_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/gdb_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/config.h"
++#include "mconsole_kern.h"
++
++#ifdef CONFIG_MCONSOLE
++
++extern int gdb_config(char *str);
++extern int gdb_remove(char *unused);
++
++static struct mc_device gdb_mc = {
++ .name = "gdb",
++ .config = gdb_config,
++ .remove = gdb_remove,
++};
++
++int gdb_mc_init(void)
++{
++ mconsole_register_dev(&gdb_mc);
++ return(0);
++}
++
++__initcall(gdb_mc_init);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/debug.h um/arch/um/kernel/tt/include/debug.h
+--- orig/arch/um/kernel/tt/include/debug.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/debug.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
++ * Lars Brinkhoff.
++ * Licensed under the GPL
++ */
++
++#ifndef __DEBUG_H
++#define __DEBUG_H
++
++extern int debugger_proxy(int status, pid_t pid);
++extern void child_proxy(pid_t pid, int status);
++extern void init_proxy (pid_t pid, int waiting, int status);
++extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
++extern void fake_child_exit(void);
++extern int gdb_config(char *str);
++extern int gdb_remove(char *unused);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mmu.h um/arch/um/kernel/tt/include/mmu.h
+--- orig/arch/um/kernel/tt/include/mmu.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/mmu.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,23 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_MMU_H
++#define __TT_MMU_H
++
++struct mmu_context_tt {
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mode.h um/arch/um/kernel/tt/include/mode.h
+--- orig/arch/um/kernel/tt/include/mode.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/mode.h 2003-11-07 01:42:09.000000000 -0500
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_TT_H__
++#define __MODE_TT_H__
++
++#include "sysdep/ptrace.h"
++
++enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
++
++extern int tracing_pid;
++
++extern int tracer(int (*init_proc)(void *), void *sp);
++extern void user_time_init_tt(void);
++extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data);
++extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr,
++ void *data);
++extern void sig_handler_common_tt(int sig, void *sc);
++extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
++extern void reboot_tt(void);
++extern void halt_tt(void);
++extern int is_tracer_winch(int pid, int fd, void *data);
++extern void kill_off_processes_tt(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mode_kern.h um/arch/um/kernel/tt/include/mode_kern.h
+--- orig/arch/um/kernel/tt/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/mode_kern.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_MODE_KERN_H__
++#define __TT_MODE_KERN_H__
++
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++
++extern void *_switch_to_tt(void *prev, void *next);
++extern void flush_thread_tt(void);
++extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
++ unsigned long esp);
++extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct *p,
++ struct pt_regs *regs);
++extern void release_thread_tt(struct task_struct *task);
++extern void exit_thread_tt(void);
++extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
++extern void init_idle_tt(void);
++extern void flush_tlb_kernel_vm_tt(void);
++extern void __flush_tlb_one_tt(unsigned long addr);
++extern void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start,
++ unsigned long end);
++extern void flush_tlb_mm_tt(struct mm_struct *mm);
++extern void force_flush_all_tt(void);
++extern long execute_syscall_tt(void *r);
++extern void before_mem_tt(unsigned long brk_start);
++extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
++ unsigned long *task_size_out);
++extern int start_uml_tt(void);
++extern int external_pid_tt(struct task_struct *task);
++extern int thread_pid_tt(struct thread_struct *thread);
++
++#define kmem_end_tt (host_task_size - ABOVE_KMEM)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/ptrace-tt.h um/arch/um/kernel/tt/include/ptrace-tt.h
+--- orig/arch/um/kernel/tt/include/ptrace-tt.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/ptrace-tt.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_TT_H
++#define __PTRACE_TT_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "sysdep/sc.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/tt.h um/arch/um/kernel/tt/include/tt.h
+--- orig/arch/um/kernel/tt/include/tt.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/tt.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_H__
++#define __TT_H__
++
++#include "sysdep/ptrace.h"
++
++extern int gdb_pid;
++extern int debug;
++extern int debug_stop;
++extern int debug_trace;
++
++extern int honeypot;
++
++extern int fork_tramp(void *sig_stack);
++extern int do_proc_op(void *t, int proc_id);
++extern int tracer(int (*init_proc)(void *), void *sp);
++extern void attach_process(int pid);
++extern void tracer_panic(char *format, ...);
++extern void set_init_pid(int pid);
++extern int set_user_mode(void *task);
++extern void set_tracing(void *t, int tracing);
++extern int is_tracing(void *task);
++extern int singlestepping_tt(void *t);
++extern void clear_singlestep(void *t);
++extern void syscall_handler(int sig, union uml_pt_regs *regs);
++extern void exit_kernel(int pid, void *task);
++extern int do_syscall(void *task, int pid);
++extern int is_valid_pid(int pid);
++extern void remap_data(void *segment_start, void *segment_end, int w);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/uaccess.h um/arch/um/kernel/tt/include/uaccess.h
+--- orig/arch/um/kernel/tt/include/uaccess.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/include/uaccess.h 2003-11-12 08:37:20.000000000 -0500
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_UACCESS_H
++#define __TT_UACCESS_H
++
++#include "linux/string.h"
++#include "linux/sched.h"
++#include "asm/processor.h"
++#include "asm/errno.h"
++#include "asm/current.h"
++#include "asm/a.out.h"
++#include "uml_uaccess.h"
++
++#define ABOVE_KMEM (16 * 1024 * 1024)
++
++extern unsigned long end_vm;
++extern unsigned long uml_physmem;
++
++#define under_task_size(addr, size) \
++ (((unsigned long) (addr) < TASK_SIZE) && \
++ (((unsigned long) (addr) + (size)) < TASK_SIZE))
++
++#define is_stack(addr, size) \
++ (((unsigned long) (addr) < STACK_TOP) && \
++ ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
++ (((unsigned long) (addr) + (size)) <= STACK_TOP))
++
++#define access_ok_tt(type, addr, size) \
++ ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
++ (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
++ (under_task_size(addr, size) || is_stack(addr, size))))
++
++static inline int verify_area_tt(int type, const void * addr,
++ unsigned long size)
++{
++ return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
++}
++
++extern unsigned long get_fault_addr(void);
++
++extern int __do_copy_from_user(void *to, const void *from, int n,
++ void **fault_addr, void **fault_catcher);
++extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
++ void **fault_addr, void **fault_catcher);
++extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
++ void **fault_catcher);
++extern int __do_strnlen_user(const char *str, unsigned long n,
++ void **fault_addr, void **fault_catcher);
++
++extern int copy_from_user_tt(void *to, const void *from, int n);
++extern int copy_to_user_tt(void *to, const void *from, int n);
++extern int strncpy_from_user_tt(char *dst, const char *src, int count);
++extern int __clear_user_tt(void *mem, int len);
++extern int clear_user_tt(void *mem, int len);
++extern int strnlen_user_tt(const void *str, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ksyms.c um/arch/um/kernel/tt/ksyms.c
+--- orig/arch/um/kernel/tt/ksyms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ksyms.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/module.h"
++#include "asm/uaccess.h"
++#include "mode.h"
++
++EXPORT_SYMBOL(__do_copy_from_user);
++EXPORT_SYMBOL(__do_copy_to_user);
++EXPORT_SYMBOL(__do_strncpy_from_user);
++EXPORT_SYMBOL(__do_strnlen_user);
++EXPORT_SYMBOL(__do_clear_user);
++
++EXPORT_SYMBOL(tracing_pid);
++EXPORT_SYMBOL(honeypot);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/Makefile um/arch/um/kernel/tt/Makefile
+--- orig/arch/um/kernel/tt/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/Makefile 2003-11-12 08:34:27.000000000 -0500
+@@ -0,0 +1,39 @@
++#
++# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++# Licensed under the GPL
++#
++
++O_TARGET = tt.o
++
++obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
++ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
++ uaccess.o uaccess_user.o
++
++obj-$(CONFIG_PT_PROXY) += gdb_kern.o
++
++subdir-y = sys-$(SUBARCH)
++subdir-$(CONFIG_PT_PROXY) += ptproxy
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++export-objs = ksyms.o
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o
++
++UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
++UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++$(O_TARGET) : unmap_fin.o
++
++unmap.o: unmap.c
++ $(CC) $(UNMAP_CFLAGS) -c -o $@ $<
++
++unmap_fin.o : unmap.o
++ ld -r -o $@ $< -lc -L/usr/lib
++
++clean :
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/mem.c um/arch/um/kernel/tt/mem.c
+--- orig/arch/um/kernel/tt/mem.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/mem.c 2004-01-31 02:38:28.000000000 -0500
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2002 - 2004 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "asm/uaccess.h"
++#include "mem_user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "kern.h"
++#include "tt.h"
++
++void before_mem_tt(unsigned long brk_start)
++{
++ if(!jail || debug)
++ remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
++ remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
++ remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
++}
++
++#ifdef CONFIG_HOST_2G_2G
++#define TOP 0x80000000
++#else
++#define TOP 0xc0000000
++#endif
++
++#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
++#define START (TOP - SIZE)
++
++unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
++ unsigned long *task_size_out)
++{
++ /* Round up to the nearest 4M */
++ *host_size_out = ROUND_4M((unsigned long) &arg);
++ *task_size_out = START;
++ return(START);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/mem_user.c um/arch/um/kernel/tt/mem_user.c
+--- orig/arch/um/kernel/tt/mem_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/mem_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/mman.h>
++#include "tt.h"
++#include "mem_user.h"
++#include "user_util.h"
++
++void remap_data(void *segment_start, void *segment_end, int w)
++{
++ void *addr;
++ unsigned long size;
++ int data, prot;
++
++ if(w) prot = PROT_WRITE;
++ else prot = 0;
++ prot |= PROT_READ | PROT_EXEC;
++ size = (unsigned long) segment_end -
++ (unsigned long) segment_start;
++ data = create_mem_file(size);
++ addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
++ if(addr == MAP_FAILED){
++ perror("mapping new data segment");
++ exit(1);
++ }
++ memcpy(addr, segment_start, size);
++ if(switcheroo(data, prot, addr, segment_start, size) < 0){
++ printf("switcheroo failed\n");
++ exit(1);
++ }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/process_kern.c um/arch/um/kernel/tt/process_kern.c
+--- orig/arch/um/kernel/tt/process_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/process_kern.c 2004-01-31 02:39:08.000000000 -0500
+@@ -0,0 +1,535 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/signal.h"
++#include "linux/kernel.h"
++#include "asm/system.h"
++#include "asm/pgalloc.h"
++#include "asm/ptrace.h"
++#include "irq_user.h"
++#include "signal_user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "kern.h"
++#include "sigcontext.h"
++#include "time_user.h"
++#include "mem_user.h"
++#include "tlb.h"
++#include "mode.h"
++#include "init.h"
++#include "tt.h"
++
++void *_switch_to_tt(void *prev, void *next)
++{
++ struct task_struct *from, *to;
++ unsigned long flags;
++ int err, vtalrm, alrm, prof, cpu;
++ char c;
++ /* jailing and SMP are incompatible, so this doesn't need to be
++ * made per-cpu
++ */
++ static int reading;
++
++ from = prev;
++ to = next;
++
++ to->thread.prev_sched = from;
++
++ cpu = from->processor;
++ if(cpu == 0)
++ forward_interrupts(to->thread.mode.tt.extern_pid);
++#ifdef CONFIG_SMP
++ forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
++#endif
++ local_irq_save(flags);
++
++ vtalrm = change_sig(SIGVTALRM, 0);
++ alrm = change_sig(SIGALRM, 0);
++ prof = change_sig(SIGPROF, 0);
++
++ c = 0;
++ set_current(to);
++
++ reading = 0;
++ err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
++ if(err != sizeof(c))
++ panic("write of switch_pipe failed, err = %d", -err);
++
++ reading = 1;
++ if(from->state == TASK_ZOMBIE)
++ os_kill_process(os_getpid(), 0);
++
++ err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
++ if(err != sizeof(c))
++ panic("read of switch_pipe failed, errno = %d", -err);
++
++ /* 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 release_thread_tt(struct task_struct *task)
++{
++ os_kill_process(task->thread.mode.tt.extern_pid, 0);
++}
++
++void exit_thread_tt(void)
++{
++ os_close_file(current->thread.mode.tt.switch_pipe[0]);
++ os_close_file(current->thread.mode.tt.switch_pipe[1]);
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++static void new_thread_handler(int sig)
++{
++ unsigned long disable;
++ int (*fn)(void *);
++ void *arg;
++
++ fn = current->thread.request.u.thread.proc;
++ arg = current->thread.request.u.thread.arg;
++
++ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
++ disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
++ (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
++ SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable;
++
++ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
++
++ init_new_thread_signals(1);
++ enable_timer();
++ free_page(current->thread.temp_stack);
++ set_cmdline("(kernel thread)");
++ force_flush_all();
++
++ if(current->thread.prev_sched != NULL)
++ schedule_tail(current->thread.prev_sched);
++ current->thread.prev_sched = NULL;
++
++ change_sig(SIGUSR1, 1);
++ change_sig(SIGVTALRM, 1);
++ change_sig(SIGPROF, 1);
++ sti();
++ if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf))
++ do_exit(0);
++}
++
++static int new_thread_proc(void *stack)
++{
++ /* cli is needed to block out signals until this thread is properly
++ * scheduled. Otherwise, the tracing thread will get mighty upset
++ * about any signals that arrive before that.
++ * This has the complication that it sets the saved signal mask in
++ * the sigcontext to block signals. This gets restored when this
++ * thread (or a descendant, since they get a copy of this sigcontext)
++ * returns to userspace.
++ * So, this is compensated for elsewhere.
++ * XXX There is still a small window until cli() actually finishes
++ * where signals are possible - shouldn't be a problem in practice
++ * since SIGIO hasn't been forwarded here yet, and the cli should
++ * finish before a SIGVTALRM has time to be delivered.
++ */
++ cli();
++ init_new_thread_stack(stack, new_thread_handler);
++ os_usr1_process(os_getpid());
++ return(0);
++}
++
++/* Signal masking - signals are blocked at the start of fork_tramp. They
++ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
++ * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
++ * so it is blocked before it's called. They are re-enabled on sigreturn
++ * despite the fact that they were blocked when the SIGUSR1 was issued because
++ * copy_thread copies the parent's sigcontext, including the signal mask
++ * onto the signal frame.
++ */
++
++static void finish_fork_handler(int sig)
++{
++ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
++ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
++
++ init_new_thread_signals(1);
++ enable_timer();
++ sti();
++ force_flush_all();
++ if(current->mm != current->p_pptr->mm)
++ protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
++ 1, 0, 1);
++ task_protections((unsigned long) current);
++
++ if(current->thread.prev_sched != NULL)
++ schedule_tail(current->thread.prev_sched);
++ current->thread.prev_sched = NULL;
++
++ free_page(current->thread.temp_stack);
++ cli();
++ change_sig(SIGUSR1, 0);
++ set_user_mode(current);
++}
++
++int fork_tramp(void *stack)
++{
++ cli();
++ arch_init_thread();
++ init_new_thread_stack(stack, finish_fork_handler);
++ os_usr1_process(os_getpid());
++ return(0);
++}
++
++int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
++ unsigned long stack_top, struct task_struct * p,
++ struct pt_regs *regs)
++{
++ int (*tramp)(void *);
++ int new_pid, err;
++ unsigned long stack;
++
++ if(current->thread.forking)
++ tramp = fork_tramp;
++ else {
++ tramp = new_thread_proc;
++ p->thread.request.u.thread = current->thread.request.u.thread;
++ }
++
++ err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
++ if(err < 0){
++ printk("copy_thread : pipe failed, err = %d\n", -err);
++ return(err);
++ }
++
++ stack = alloc_stack(0, 0);
++ if(stack == 0){
++ printk(KERN_ERR "copy_thread : failed to allocate "
++ "temporary stack\n");
++ return(-ENOMEM);
++ }
++
++ clone_flags &= CLONE_VM;
++ p->thread.temp_stack = stack;
++ new_pid = start_fork_tramp((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(UPT_SC(&p->thread.regs.regs),
++ UPT_SC(¤t->thread.regs.regs));
++ SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
++ if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
++ }
++ p->thread.mode.tt.extern_pid = new_pid;
++
++ current->thread.request.op = OP_FORK;
++ current->thread.request.u.fork.pid = new_pid;
++ os_usr1_process(os_getpid());
++ return(0);
++}
++
++void reboot_tt(void)
++{
++ current->thread.request.op = OP_REBOOT;
++ os_usr1_process(os_getpid());
++}
++
++void halt_tt(void)
++{
++ current->thread.request.op = OP_HALT;
++ os_usr1_process(os_getpid());
++}
++
++void kill_off_processes_tt(void)
++{
++ struct task_struct *p;
++ int me;
++
++ me = os_getpid();
++ for_each_task(p){
++ int pid = p->thread.mode.tt.extern_pid;
++ if((pid != me) && (pid != -1))
++ os_kill_process(p->thread.mode.tt.extern_pid, 0);
++ }
++ if((init_task.thread.mode.tt.extern_pid != me) &&
++ (init_task.thread.mode.tt.extern_pid != -1))
++ os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
++}
++
++void initial_thread_cb_tt(void (*proc)(void *), void *arg)
++{
++ if(os_getpid() == tracing_pid){
++ (*proc)(arg);
++ }
++ else {
++ current->thread.request.op = OP_CB;
++ current->thread.request.u.cb.proc = proc;
++ current->thread.request.u.cb.arg = arg;
++ os_usr1_process(os_getpid());
++ }
++}
++
++int do_proc_op(void *t, int proc_id)
++{
++ struct task_struct *task;
++ struct thread_struct *thread;
++ int op, pid;
++
++ task = t;
++ thread = &task->thread;
++ op = thread->request.op;
++ switch(op){
++ case OP_NONE:
++ case OP_TRACE_ON:
++ break;
++ case OP_EXEC:
++ pid = thread->request.u.exec.pid;
++ do_exec(thread->mode.tt.extern_pid, pid);
++ thread->mode.tt.extern_pid = pid;
++ cpu_tasks[task->processor].pid = pid;
++ break;
++ case OP_FORK:
++ attach_process(thread->request.u.fork.pid);
++ break;
++ case OP_CB:
++ (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
++ break;
++ case OP_REBOOT:
++ case OP_HALT:
++ break;
++ default:
++ tracer_panic("Bad op in do_proc_op");
++ break;
++ }
++ thread->request.op = OP_NONE;
++ return(op);
++}
++
++void init_idle_tt(void)
++{
++ idle_timer();
++}
++
++/* Changed by jail_setup, which is a setup */
++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;
++ int pages;
++
++ if(!jail || (current == &init_task)) return;
++
++ pages = (1 << CONFIG_KERNEL_STACK_ORDER);
++
++ start = (unsigned long) current + PAGE_SIZE;
++ end = (unsigned long) current + PAGE_SIZE * pages;
++ protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
++ protect_memory(end, high_physmem - end, 1, w, 1, 1);
++
++ start = (unsigned long) UML_ROUND_DOWN(&_stext);
++ end = (unsigned long) UML_ROUND_UP(&_etext);
++ protect_memory(start, end - start, 1, w, 1, 1);
++
++ start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end);
++ end = (unsigned long) UML_ROUND_UP(&_edata);
++ protect_memory(start, end - start, 1, w, 1, 1);
++
++ start = (unsigned long) UML_ROUND_DOWN(&__bss_start);
++ end = (unsigned long) UML_ROUND_UP(&_end);
++ protect_memory(start, end - start, 1, w, 1, 1);
++
++ mprotect_kernel_vm(w);
++}
++
++void unprotect_kernel_mem(void)
++{
++ mprotect_kernel_mem(1);
++}
++
++void protect_kernel_mem(void)
++{
++ mprotect_kernel_mem(0);
++}
++
++extern void start_kernel(void);
++
++static int start_kernel_proc(void *unused)
++{
++ int pid;
++
++ block_signals();
++ pid = os_getpid();
++
++ cpu_tasks[0].pid = pid;
++ cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++ cpu_online_map = 1;
++#endif
++ if(debug) os_stop_process(pid);
++ start_kernel();
++ return(0);
++}
++
++void set_tracing(void *task, int tracing)
++{
++ ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
++}
++
++int is_tracing(void *t)
++{
++ return (((struct task_struct *) t)->thread.mode.tt.tracing);
++}
++
++int set_user_mode(void *t)
++{
++ struct task_struct *task;
++
++ task = t ? t : current;
++ if(task->thread.mode.tt.tracing)
++ return(1);
++ task->thread.request.op = OP_TRACE_ON;
++ os_usr1_process(os_getpid());
++ return(0);
++}
++
++void set_init_pid(int pid)
++{
++ int err;
++
++ init_task.thread.mode.tt.extern_pid = pid;
++ err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
++ if(err)
++ panic("Can't create switch pipe for init_task, errno = %d",
++ -err);
++}
++
++int singlestepping_tt(void *t)
++{
++ struct task_struct *task = t;
++
++ if(task->thread.mode.tt.singlestep_syscall)
++ return(0);
++ return(task->ptrace & PT_DTRACE);
++}
++
++void clear_singlestep(void *t)
++{
++ struct task_struct *task = t;
++
++ task->ptrace &= ~PT_DTRACE;
++}
++
++int start_uml_tt(void)
++{
++ void *sp;
++ int pages;
++
++ pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2;
++ sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE -
++ sizeof(unsigned long);
++ return(tracer(start_kernel_proc, sp));
++}
++
++int external_pid_tt(struct task_struct *task)
++{
++ return(task->thread.mode.tt.extern_pid);
++}
++
++int thread_pid_tt(struct thread_struct *thread)
++{
++ return(thread->mode.tt.extern_pid);
++}
++
++int is_valid_pid(int pid)
++{
++ struct task_struct *task;
++
++ read_lock(&tasklist_lock);
++ for_each_task(task){
++ if(task->thread.mode.tt.extern_pid == pid){
++ read_unlock(&tasklist_lock);
++ return(1);
++ }
++ }
++ read_unlock(&tasklist_lock);
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/Makefile um/arch/um/kernel/tt/ptproxy/Makefile
+--- orig/arch/um/kernel/tt/ptproxy/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/Makefile 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,12 @@
++O_TARGET = ptproxy.o
++
++obj-y = proxy.o ptrace.o sysdep.o wait.o
++
++USER_OBJS = $(obj-y)
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean:
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/proxy.c um/arch/um/kernel/tt/ptproxy/proxy.c
+--- orig/arch/um/kernel/tt/ptproxy/proxy.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/proxy.c 2003-10-21 03:26:07.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 <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"
++#include "tempfile.h"
++
++static int debugger_wait(debugger_state *debugger, int *status, int options,
++ int (*syscall)(debugger_state *debugger, pid_t child),
++ int (*normal_return)(debugger_state *debugger,
++ pid_t unused),
++ int (*wait_return)(debugger_state *debugger,
++ pid_t unused))
++{
++ if(debugger->real_wait){
++ debugger->handle_trace = normal_return;
++ syscall_continue(debugger->pid);
++ debugger->real_wait = 0;
++ return(1);
++ }
++ debugger->wait_status_ptr = status;
++ debugger->wait_options = options;
++ if((debugger->debugee != NULL) && debugger->debugee->event){
++ syscall_continue(debugger->pid);
++ wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
++ NULL);
++ (*wait_return)(debugger, -1);
++ return(0);
++ }
++ else if(debugger->wait_options & WNOHANG){
++ syscall_cancel(debugger->pid, 0);
++ debugger->handle_trace = syscall;
++ return(0);
++ }
++ else {
++ syscall_pause(debugger->pid);
++ debugger->handle_trace = wait_return;
++ debugger->waiting = 1;
++ }
++ return(1);
++}
++
++/*
++ * Handle debugger trap, i.e. syscall.
++ */
++
++int debugger_syscall(debugger_state *debugger, pid_t child)
++{
++ long arg1, arg2, arg3, arg4, arg5, result;
++ int syscall, ret = 0;
++
++ syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
++ &arg5);
++
++ switch(syscall){
++ case __NR_execve:
++ /* execve never returns */
++ debugger->handle_trace = debugger_syscall;
++ break;
++
++ case __NR_ptrace:
++ if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
++ if(!debugger->debugee->in_context)
++ child = debugger->debugee->pid;
++ result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
++ &ret);
++ syscall_cancel(debugger->pid, result);
++ debugger->handle_trace = debugger_syscall;
++ return(ret);
++
++ 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);
++}
++
++/* Used by the tracing thread */
++static debugger_state parent;
++static int parent_syscall(debugger_state *debugger, int pid);
++
++int init_parent_proxy(int pid)
++{
++ parent = ((debugger_state) { .pid = pid,
++ .wait_options = 0,
++ .wait_status_ptr = NULL,
++ .waiting = 0,
++ .real_wait = 0,
++ .expecting_child = 0,
++ .handle_trace = parent_syscall,
++ .debugee = NULL } );
++ return(0);
++}
++
++int parent_normal_return(debugger_state *debugger, pid_t unused)
++{
++ debugger->handle_trace = parent_syscall;
++ syscall_continue(debugger->pid);
++ return(0);
++}
++
++static int parent_syscall(debugger_state *debugger, int pid)
++{
++ long arg1, arg2, arg3, arg4, arg5;
++ int syscall;
++
++ syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
++
++ if((syscall == __NR_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);
++}
++
++/* Used by the tracing thread */
++static debugger_state debugger;
++static debugee_state debugee;
++
++void init_proxy (pid_t debugger_pid, int stopped, int status)
++{
++ debugger.pid = debugger_pid;
++ debugger.handle_trace = debugger_syscall;
++ debugger.debugee = &debugee;
++ debugger.waiting = 0;
++ debugger.real_wait = 0;
++ debugger.expecting_child = 0;
++
++ debugee.pid = 0;
++ debugee.traced = 0;
++ debugee.stopped = stopped;
++ debugee.event = 0;
++ debugee.zombie = 0;
++ debugee.died = 0;
++ debugee.wait_status = status;
++ debugee.in_context = 1;
++}
++
++int debugger_proxy(int status, int pid)
++{
++ int ret = 0, sig;
++
++ if(WIFSTOPPED(status)){
++ sig = WSTOPSIG(status);
++ if (sig == SIGTRAP)
++ ret = (*debugger.handle_trace)(&debugger, pid);
++
++ else if(sig == SIGCHLD){
++ if(debugger.expecting_child){
++ ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++ debugger.expecting_child = 0;
++ }
++ else if(debugger.waiting)
++ real_wait_return(&debugger);
++ else {
++ ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++ debugger.real_wait = 1;
++ }
++ }
++ else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++ }
++ else if(WIFEXITED(status)){
++ tracer_panic("debugger (pid %d) exited with status %d",
++ debugger.pid, WEXITSTATUS(status));
++ }
++ else if(WIFSIGNALED(status)){
++ tracer_panic("debugger (pid %d) exited with signal %d",
++ debugger.pid, WTERMSIG(status));
++ }
++ else {
++ tracer_panic("proxy got unknown status (0x%x) on debugger "
++ "(pid %d)", status, debugger.pid);
++ }
++ return(ret);
++}
++
++void child_proxy(pid_t pid, int status)
++{
++ debugee.event = 1;
++ debugee.wait_status = status;
++
++ if(WIFSTOPPED(status)){
++ debugee.stopped = 1;
++ debugger.expecting_child = 1;
++ kill(debugger.pid, SIGCHLD);
++ }
++ else if(WIFEXITED(status) || WIFSIGNALED(status)){
++ debugee.zombie = 1;
++ debugger.expecting_child = 1;
++ kill(debugger.pid, SIGCHLD);
++ }
++ else panic("proxy got unknown status (0x%x) on child (pid %d)",
++ status, pid);
++}
++
++void debugger_parent_signal(int status, int pid)
++{
++ int sig;
++
++ if(WIFSTOPPED(status)){
++ sig = WSTOPSIG(status);
++ if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
++ else ptrace(PTRACE_SYSCALL, pid, 0, sig);
++ }
++}
++
++void fake_child_exit(void)
++{
++ int status, pid;
++
++ child_proxy(1, W_EXITCODE(0, 0));
++ while(debugger.waiting == 1){
++ 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 \n\
++b panic \n\
++b stop \n\
++handle SIGWINCH nostop noprint pass \n\
++";
++
++int start_debugger(char *prog, int startup, int stop, int *fd_out)
++{
++ int slave, child;
++
++ slave = open_gdb_chan();
++ child = fork();
++ if(child == 0){
++ char *tempname = NULL;
++ int fd;
++
++ if(setsid() < 0) perror("setsid");
++ if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
++ (dup2(slave, 2) < 0)){
++ printk("start_debugger : dup2 failed, errno = %d\n",
++ errno);
++ exit(1);
++ }
++ if(ioctl(0, TIOCSCTTY, 0) < 0){
++ printk("start_debugger : TIOCSCTTY failed, "
++ "errno = %d\n", errno);
++ exit(1);
++ }
++ if(tcsetpgrp (1, os_getpid()) < 0){
++ printk("start_debugger : tcsetpgrp failed, "
++ "errno = %d\n", errno);
++#ifdef notdef
++ exit(1);
++#endif
++ }
++ fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
++ if(fd < 0){
++ printk("start_debugger : make_tempfile failed,"
++ "err = %d\n", -fd);
++ exit(1);
++ }
++ os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
++ if(startup){
++ if(stop){
++ os_write_file(fd, "b start_kernel\n",
++ strlen("b start_kernel\n"));
++ }
++ os_write_file(fd, "c\n", strlen("c\n"));
++ }
++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++ printk("start_debugger : PTRACE_TRACEME failed, "
++ "errno = %d\n", errno);
++ exit(1);
++ }
++ execlp("gdb", "gdb", "--command", tempname, prog, NULL);
++ printk("start_debugger : exec of gdb failed, errno = %d\n",
++ errno);
++ }
++ if(child < 0){
++ printk("start_debugger : fork for gdb failed, errno = %d\n",
++ errno);
++ return(-1);
++ }
++ *fd_out = slave;
++ return(child);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/ptproxy.h um/arch/um/kernel/tt/ptproxy/ptproxy.h
+--- orig/arch/um/kernel/tt/ptproxy/ptproxy.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/ptproxy.h 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/ptrace.c um/arch/um/kernel/tt/ptproxy/ptrace.c
+--- orig/arch/um/kernel/tt/ptproxy/ptrace.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/ptrace.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,239 @@
++/**********************************************************************
++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"
++#include "tt.h"
++
++long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
++ long arg3, long arg4, pid_t child, int *ret)
++{
++ sigset_t relay;
++ long result;
++ int status;
++
++ *ret = 0;
++ if(debugger->debugee->died) return(-ESRCH);
++
++ switch(arg1){
++ case PTRACE_ATTACH:
++ if(debugger->debugee->traced) return(-EPERM);
++
++ debugger->debugee->pid = arg2;
++ debugger->debugee->traced = 1;
++
++ if(is_valid_pid(arg2) && (arg2 != child)){
++ debugger->debugee->in_context = 0;
++ kill(arg2, SIGSTOP);
++ debugger->debugee->event = 1;
++ debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
++ }
++ else {
++ debugger->debugee->in_context = 1;
++ if(debugger->debugee->stopped)
++ child_proxy(child, W_STOPCODE(SIGSTOP));
++ else kill(child, SIGSTOP);
++ }
++
++ return(0);
++
++ case PTRACE_DETACH:
++ if(!debugger->debugee->traced) return(-EPERM);
++
++ debugger->debugee->traced = 0;
++ debugger->debugee->pid = 0;
++ if(!debugger->debugee->in_context)
++ kill(child, SIGCONT);
++
++ return(0);
++
++ case PTRACE_CONT:
++ if(!debugger->debugee->in_context) return(-EPERM);
++ *ret = PTRACE_CONT;
++ return(ptrace(PTRACE_CONT, child, arg3, arg4));
++
++#ifdef UM_HAVE_GETFPREGS
++ case PTRACE_GETFPREGS:
++ {
++ long regs[FP_FRAME_SIZE];
++ int i, result;
++
++ result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
++ if(result == -1) return(-errno);
++
++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++ ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
++ regs[i]);
++ return(result);
++ }
++#endif
++
++#ifdef UM_HAVE_GETFPXREGS
++ case PTRACE_GETFPXREGS:
++ {
++ long regs[FPX_FRAME_SIZE];
++ int i, result;
++
++ result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
++ if(result == -1) return(-errno);
++
++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++ ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
++ regs[i]);
++ return(result);
++ }
++#endif
++
++#ifdef UM_HAVE_GETREGS
++ case PTRACE_GETREGS:
++ {
++ long regs[FRAME_SIZE];
++ int i, result;
++
++ result = ptrace(PTRACE_GETREGS, child, 0, regs);
++ if(result == -1) return(-errno);
++
++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++ ptrace (PTRACE_POKEDATA, debugger->pid,
++ arg4 + 4 * i, regs[i]);
++ return(result);
++ }
++ break;
++#endif
++
++ case PTRACE_KILL:
++ result = ptrace(PTRACE_KILL, child, arg3, arg4);
++ if(result == -1) return(-errno);
++
++ return(result);
++
++ case PTRACE_PEEKDATA:
++ case PTRACE_PEEKTEXT:
++ case PTRACE_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/sysdep.c um/arch/um/kernel/tt/ptproxy/sysdep.c
+--- orig/arch/um/kernel/tt/ptproxy/sysdep.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/sysdep.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,72 @@
++/**********************************************************************
++sysdep.c
++
++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
++terms and conditions.
++**********************************************************************/
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/sysdep.h um/arch/um/kernel/tt/ptproxy/sysdep.h
+--- orig/arch/um/kernel/tt/ptproxy/sysdep.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/sysdep.h 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/wait.c um/arch/um/kernel/tt/ptproxy/wait.c
+--- orig/arch/um/kernel/tt/ptproxy/wait.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/wait.c 2004-01-17 05:27:18.000000000 -0500
+@@ -0,0 +1,88 @@
++/**********************************************************************
++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 pid;
++
++ pid = debugger->pid;
++
++ ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++ IP_RESTART_SYSCALL(ip);
++
++ if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
++ tracer_panic("real_wait_return : Failed to restart system "
++ "call, errno = %d\n", errno);
++
++ if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
++ (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
++ (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
++ debugger_normal_return(debugger, -1))
++ tracer_panic("real_wait_return : gdb failed to wait, "
++ "errno = %d\n", errno);
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/wait.h um/arch/um/kernel/tt/ptproxy/wait.h
+--- orig/arch/um/kernel/tt/ptproxy/wait.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/ptproxy/wait.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/syscall_kern.c um/arch/um/kernel/tt/syscall_kern.c
+--- orig/arch/um/kernel/tt/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/syscall_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,142 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/types.h"
++#include "linux/utime.h"
++#include "linux/sys.h"
++#include "asm/unistd.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++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 *) UPT_SYSCALL_ARG1(®s->regs),
++ UPT_SYSCALL_ARG2(®s->regs)));
++}
++
++static int check_utime(struct pt_regs *regs)
++{
++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs),
++ sizeof(struct utimbuf)));
++}
++
++static int check_oldstat(struct pt_regs *regs)
++{
++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs),
++ sizeof(struct __old_kernel_stat)));
++}
++
++static int check_stat(struct pt_regs *regs)
++{
++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs),
++ sizeof(struct stat)));
++}
++
++static int check_stat64(struct pt_regs *regs)
++{
++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs),
++ 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[UPT_SYSCALL_NR(®s->regs)];
++
++ if(!bogon->kernel_ds) return(0);
++ if(bogon->check_params && (*bogon->check_params)(regs))
++ return(-EFAULT);
++ set_fs(KERNEL_DS);
++ return(0);
++}
++
++extern syscall_handler_t *sys_call_table[];
++
++long execute_syscall_tt(void *r)
++{
++ struct pt_regs *regs = r;
++ long res;
++ int syscall;
++
++ current->thread.nsyscalls++;
++ nsyscalls++;
++ syscall = UPT_SYSCALL_NR(®s->regs);
++
++ 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.mode.tt.singlestep_syscall){
++ current->thread.mode.tt.singlestep_syscall = 0;
++ current->ptrace &= ~PT_DTRACE;
++ force_sig(SIGTRAP, current);
++ }
++
++ return(res);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/syscall_user.c um/arch/um/kernel/tt/syscall_user.c
+--- orig/arch/um/kernel/tt/syscall_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/syscall_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.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"
++#include "syscall_user.h"
++#include "tt.h"
++
++/* XXX Bogus */
++#define ERESTARTSYS 512
++#define ERESTARTNOINTR 513
++#define ERESTARTNOHAND 514
++
++void syscall_handler_tt(int sig, union uml_pt_regs *regs)
++{
++ void *sc;
++ long result;
++ int index, syscall;
++
++ syscall = UPT_SYSCALL_NR(regs);
++ sc = UPT_SC(regs);
++ SC_START_SYSCALL(sc);
++
++ index = record_syscall_start(syscall);
++ 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.
++ */
++ UPT_SC(regs) = sc;
++
++ SC_SET_SYSCALL_RETURN(sc, result);
++ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
++ (result == -ERESTARTNOINTR))
++ do_signal(result);
++
++ syscall_trace();
++ record_syscall_end(index, result);
++}
++
++int do_syscall(void *task, int pid)
++{
++ unsigned long proc_regs[FRAME_SIZE];
++ union uml_pt_regs *regs;
++ int syscall;
++
++ if(ptrace_getregs(pid, proc_regs) < 0)
++ tracer_panic("Couldn't read registers");
++ syscall = PT_SYSCALL_NR(proc_regs);
++
++ regs = TASK_REGS(task);
++ UPT_SYSCALL_NR(regs) = syscall;
++
++ if(syscall < 1) return(0);
++
++ if((syscall != __NR_sigreturn) &&
++ ((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
++ ((unsigned long *) PT_IP(proc_regs) <= &_etext))
++ tracer_panic("I'm tracing myself and I can't get out");
++
++ if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
++ __NR_getpid) < 0)
++ tracer_panic("do_syscall : Nullifying syscall failed, "
++ "errno = %d", errno);
++ return(1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/sys-i386/Makefile um/arch/um/kernel/tt/sys-i386/Makefile
+--- orig/arch/um/kernel/tt/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/sys-i386/Makefile 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,17 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = sys-i386.o
++
++obj-y = sigcontext.o
++
++USER_OBJS = sigcontext.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/sys-i386/sigcontext.c um/arch/um/kernel/tt/sys-i386/sigcontext.c
+--- orig/arch/um/kernel/tt/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/sys-i386/sigcontext.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <asm/sigcontext.h>
++#include "kern_util.h"
++#include "sysdep/frame.h"
++
++int copy_sc_from_user_tt(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->fpstate, &to_fp,
++ sizeof(to->fpstate));
++ err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
++ }
++ return(err);
++}
++
++int copy_sc_to_user_tt(void *to_ptr, void *fp, 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 *)
++ (fp ? (unsigned long) fp : ((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);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/time.c um/arch/um/kernel/tt/time.c
+--- orig/arch/um/kernel/tt/time.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/time.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include <sys/time.h>
++#include <time_user.h>
++#include "process.h"
++#include "user.h"
++
++void user_time_init_tt(void)
++{
++ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++ panic("Couldn't set SIGVTALRM handler");
++ set_interval(ITIMER_VIRTUAL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/tlb.c um/arch/um/kernel/tt/tlb.c
+--- orig/arch/um/kernel/tt/tlb.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/tlb.c 2003-11-13 00:40:57.000000000 -0500
+@@ -0,0 +1,220 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "mem_user.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.mode.tt.extern_pid != -1) &&
++ (current->thread.mode.tt.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 = os_unmap_memory((void *) addr,
++ PAGE_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ if(pte_present(*npte))
++ map_memory(addr,
++ pte_val(*npte) & PAGE_MASK,
++ PAGE_SIZE, r, w, x);
++ }
++ else if(pte_newprot(*npte)){
++ protect_memory(addr, PAGE_SIZE, r, w, x, 1);
++ }
++ *npte = pte_mkuptodate(*npte);
++ addr += PAGE_SIZE;
++ }
++ else {
++ if(force || pmd_newpage(*npmd)){
++ err = os_unmap_memory((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; addr < end;){
++ 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 = os_unmap_memory((void *) addr,
++ PAGE_SIZE);
++ if(err < 0)
++ panic("munmap failed, errno = %d\n",
++ -err);
++ if(pte_present(*pte))
++ map_memory(addr,
++ pte_val(*pte) & PAGE_MASK,
++ PAGE_SIZE, 1, 1, 1);
++ }
++ else if(pte_newprot(*pte)){
++ updated = 1;
++ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
++ }
++ addr += PAGE_SIZE;
++ }
++ else {
++ if(pmd_newpage(*pmd)){
++ updated = 1;
++ err = os_unmap_memory((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_memory(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_tt(void)
++{
++ flush_kernel_vm_range(start_vm, end_vm, 1);
++}
++
++void __flush_tlb_one_tt(unsigned long addr)
++{
++ flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1);
++}
++
++void flush_tlb_range_tt(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_tt(struct mm_struct *mm)
++{
++ unsigned long seq;
++
++ if(mm != current->mm) return;
++
++ fix_range(mm, 0, STACK_TOP, 0);
++
++ seq = atomic_read(&vmchange_seq);
++ if(current->thread.mode.tt.vm_seq == seq) return;
++ current->thread.mode.tt.vm_seq = seq;
++ flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++void force_flush_all_tt(void)
++{
++ fix_range(current->mm, 0, STACK_TOP, 1);
++ flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/tracer.c um/arch/um/kernel/tt/tracer.c
+--- orig/arch/um/kernel/tt/tracer.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/tracer.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,454 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <sched.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/ptrace.h>
++#include <sys/time.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "sysdep/ptrace.h"
++#include "sigcontext.h"
++#include "sysdep/sigcontext.h"
++#include "os.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "process.h"
++#include "kern_util.h"
++#include "frame.h"
++#include "chan_user.h"
++#include "ptrace_user.h"
++#include "mode.h"
++#include "tt.h"
++
++static int tracer_winch[2];
++
++int is_tracer_winch(int pid, int fd, void *data)
++{
++ if(pid != tracing_pid)
++ return(0);
++
++ register_winch_irq(tracer_winch[0], fd, -1, data);
++ return(1);
++}
++
++static void tracer_winch_handler(int sig)
++{
++ int n;
++ char c = 1;
++
++ n = os_write_file(tracer_winch[1], &c, sizeof(c));
++ if(n != sizeof(c))
++ printk("tracer_winch_handler - write failed, err = %d\n", -n);
++}
++
++/* Called only by the tracing thread during initialization */
++
++static void setup_tracer_winch(void)
++{
++ int err;
++
++ err = os_pipe(tracer_winch, 1, 1);
++ if(err < 0){
++ printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
++ return;
++ }
++ signal(SIGWINCH, tracer_winch_handler);
++}
++
++void attach_process(int pid)
++{
++ if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
++ (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
++ tracer_panic("OP_FORK failed to attach pid");
++ wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
++ if(ptrace(PTRACE_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) pause();
++}
++
++static void tracer_segv(int sig, struct sigcontext sc)
++{
++ printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
++ SC_FAULT_ADDR(&sc), SC_IP(&sc));
++ while(1)
++ pause();
++}
++
++/* Changed early in boot, and then only read */
++int debug = 0;
++int debug_stop = 1;
++int debug_parent = 0;
++int honeypot = 0;
++
++static int signal_tramp(void *arg)
++{
++ int (*proc)(void *);
++
++ if(honeypot && munmap((void *) (host_task_size - 0x10000000),
++ 0x10000000))
++ panic("Unmapping stack failed");
++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
++ panic("ptrace PTRACE_TRACEME failed");
++ os_stop_process(os_getpid());
++ change_sig(SIGWINCH, 0);
++ signal(SIGUSR1, SIG_IGN);
++ change_sig(SIGCHLD, 0);
++ signal(SIGSEGV, (__sighandler_t) sig_handler);
++ set_cmdline("(idle thread)");
++ set_init_pid(os_getpid());
++ proc = arg;
++ return((*proc)(NULL));
++}
++
++static void sleeping_process_signal(int pid, int sig)
++{
++ switch(sig){
++ /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
++ * right because the process must be in the kernel already.
++ */
++ case SIGCONT:
++ case SIGTSTP:
++ if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
++ tracer_panic("sleeping_process_signal : Failed to "
++ "continue pid %d, signal = %d, "
++ "errno = %d\n", pid, sig, errno);
++ break;
++
++ /* This happens when the debugger (e.g. strace) is doing system call
++ * tracing on the kernel. During a context switch, the current task
++ * will be set to the incoming process and the outgoing process will
++ * hop into write and then read. Since it's not the current process
++ * any more, the trace of those will land here. So, we need to just
++ * PTRACE_SYSCALL it.
++ */
++ case SIGTRAP:
++ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
++ tracer_panic("sleeping_process_signal : Failed to "
++ "PTRACE_SYSCALL pid %d, errno = %d\n",
++ pid, errno);
++ break;
++ case SIGSTOP:
++ break;
++ default:
++ tracer_panic("sleeping process %d got unexpected "
++ "signal : %d\n", pid, sig);
++ break;
++ }
++}
++
++/* Accessed only by the tracing thread */
++int debugger_pid = -1;
++int debugger_parent = -1;
++int debugger_fd = -1;
++int gdb_pid = -1;
++
++struct {
++ int pid;
++ int signal;
++ unsigned long addr;
++ struct timeval time;
++} signal_record[1024][32];
++
++int signal_index[32];
++int nsignals = 0;
++int debug_trace = 0;
++extern int io_nsignals, io_count, intr_count;
++
++extern void signal_usr1(int sig);
++
++int tracing_pid = -1;
++
++int tracer(int (*init_proc)(void *), void *sp)
++{
++ void *task = NULL;
++ 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();
++ printf("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, (sighandler_t) tracer_segv);
++ signal(SIGUSR1, signal_usr1);
++ if(debug_trace){
++ printf("Tracing thread pausing to be attached\n");
++ stop();
++ }
++ if(debug){
++ if(gdb_pid != -1)
++ debugger_pid = attach_debugger(pid, gdb_pid, 1);
++ else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
++ if(debug_parent){
++ debugger_parent = os_process_parent(debugger_pid);
++ init_parent_proxy(debugger_parent);
++ err = attach(debugger_parent);
++ if(err){
++ printf("Failed to attach debugger parent %d, "
++ "errno = %d\n", debugger_parent, -err);
++ debugger_parent = -1;
++ }
++ else {
++ if(ptrace(PTRACE_SYSCALL, debugger_parent,
++ 0, 0) < 0){
++ printf("Failed to continue debugger "
++ "parent, errno = %d\n", errno);
++ debugger_parent = -1;
++ }
++ }
++ }
++ }
++ set_cmdline("(tracing thread)");
++ while(1){
++ pid = waitpid(-1, &status, WUNTRACED);
++ if(pid <= 0){
++ if(errno != ECHILD){
++ printf("wait failed - errno = %d\n", errno);
++ }
++ continue;
++ }
++ if(pid == debugger_pid){
++ int cont = 0;
++
++ if(WIFEXITED(status) || WIFSIGNALED(status))
++ debugger_pid = -1;
++ /* XXX Figure out how to deal with gdb and SMP */
++ else cont = debugger_signal(status, cpu_tasks[0].pid);
++ if(cont == PTRACE_SYSCALL) strace = 1;
++ continue;
++ }
++ else if(pid == debugger_parent){
++ debugger_parent_signal(status, pid);
++ continue;
++ }
++ nsignals++;
++ if(WIFEXITED(status)) ;
++#ifdef notdef
++ {
++ printf("Child %d exited with status %d\n", pid,
++ WEXITSTATUS(status));
++ }
++#endif
++ else if(WIFSIGNALED(status)){
++ sig = WTERMSIG(status);
++ if(sig != 9){
++ printf("Child %d exited with signal %d\n", pid,
++ sig);
++ }
++ }
++ else if(WIFSTOPPED(status)){
++ proc_id = pid_to_processor_id(pid);
++ sig = WSTOPSIG(status);
++ if(signal_index[proc_id] == 1024){
++ signal_index[proc_id] = 0;
++ last_index = 1023;
++ }
++ else last_index = signal_index[proc_id] - 1;
++ if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
++ (sig == SIGALRM)) &&
++ (signal_record[proc_id][last_index].signal == sig)&&
++ (signal_record[proc_id][last_index].pid == pid))
++ signal_index[proc_id] = last_index;
++ signal_record[proc_id][signal_index[proc_id]].pid = pid;
++ gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
++ eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++ signal_record[proc_id][signal_index[proc_id]].addr = eip;
++ signal_record[proc_id][signal_index[proc_id]++].signal = sig;
++
++ 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:
++ printf("Detaching pid %d\n", pid);
++ detach(pid, SIGSTOP);
++ continue;
++ default:
++ break;
++ }
++ /* OP_EXEC switches host processes on us,
++ * we want to continue the new one.
++ */
++ pid = cpu_tasks[proc_id].pid;
++ break;
++ case SIGTRAP:
++ 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) &&
++ (sig != SIGFPE)){
++ child_signal(pid, status);
++ continue;
++ }
++
++ if(tracing){
++ if(singlestepping_tt(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_debug_setup(char *line, int *add)
++{
++ char *next;
++
++ debug = 1;
++ *add = 0;
++ if(*line != '=') return(0);
++ line++;
++
++ while(line != NULL){
++ next = strchr(line, ',');
++ if(next) *next++ = '\0';
++
++ if(!strcmp(line, "go")) debug_stop = 0;
++ else if(!strcmp(line, "parent")) debug_parent = 1;
++ else printf("Unknown debug option : '%s'\n", line);
++
++ line = next;
++ }
++ return(0);
++}
++
++__uml_setup("debug", uml_debug_setup,
++"debug\n"
++" Starts up the kernel under the control of gdb. See the \n"
++" kernel debugging tutorial and the debugging session pages\n"
++" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
++);
++
++static int __init uml_debugtrace_setup(char *line, int *add)
++{
++ debug_trace = 1;
++ return 0;
++}
++__uml_setup("debugtrace", uml_debugtrace_setup,
++"debugtrace\n"
++" Causes the tracing thread to pause until it is attached by a\n"
++" debugger and continued. This is mostly for debugging crashes\n"
++" early during boot, and should be pretty much obsoleted by\n"
++" the debug switch.\n\n"
++);
++
++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"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/trap_user.c um/arch/um/kernel/tt/trap_user.c
+--- orig/arch/um/kernel/tt/trap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/trap_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "task.h"
++#include "tt.h"
++
++void sig_handler_common_tt(int sig, void *sc_ptr)
++{
++ struct sigcontext *sc = sc_ptr;
++ struct tt_regs save_regs, *r;
++ struct signal_info *info;
++ int save_errno = errno, is_user;
++
++ unprotect_kernel_mem();
++
++ r = &TASK_REGS(get_current())->tt;
++ save_regs = *r;
++ is_user = user_context(SC_SP(sc));
++ r->sc = sc;
++ if(sig != SIGUSR2)
++ r->syscall = -1;
++
++ change_sig(SIGUSR1, 1);
++ info = &sig_info[sig];
++ if(!info->is_irq) unblock_signals();
++
++ (*info->handler)(sig, (union uml_pt_regs *) r);
++
++ if(is_user){
++ interrupt_end();
++ block_signals();
++ change_sig(SIGUSR1, 0);
++ set_user_mode(NULL);
++ }
++ *r = save_regs;
++ errno = save_errno;
++ if(is_user) protect_kernel_mem();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/uaccess.c um/arch/um/kernel/tt/uaccess.c
+--- orig/arch/um/kernel/tt/uaccess.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/uaccess.c 2003-11-13 00:12:45.000000000 -0500
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "asm/uaccess.h"
++
++int copy_from_user_tt(void *to, const void *from, int n)
++{
++ if(!access_ok_tt(VERIFY_READ, from, n))
++ return(n);
++
++ return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
++}
++
++int copy_to_user_tt(void *to, const void *from, int n)
++{
++ if(!access_ok_tt(VERIFY_WRITE, to, n))
++ return(n);
++
++ return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
++}
++
++int strncpy_from_user_tt(char *dst, const char *src, int count)
++{
++ int n;
++
++ if(!access_ok_tt(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);
++}
++
++int __clear_user_tt(void *mem, int len)
++{
++ return(__do_clear_user(mem, len,
++ ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
++}
++
++int clear_user_tt(void *mem, int len)
++{
++ if(!access_ok_tt(VERIFY_WRITE, mem, len))
++ return(len);
++
++ return(__do_clear_user(mem, len, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
++}
++
++int strnlen_user_tt(const void *str, int len)
++{
++ return(__do_strnlen_user(str, len,
++ ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/uaccess_user.c um/arch/um/kernel/tt/uaccess_user.c
+--- orig/arch/um/kernel/tt/uaccess_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/uaccess_user.c 2004-01-31 02:48:29.000000000 -0500
+@@ -0,0 +1,98 @@
++/*
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <setjmp.h>
++#include <string.h>
++#include "user_util.h"
++#include "uml_uaccess.h"
++#include "task.h"
++#include "kern_util.h"
++
++int __do_copy_from_user(void *to, const void *from, int n,
++ void **fault_addr, void **fault_catcher)
++{
++ struct tt_regs save = TASK_REGS(get_current())->tt;
++ unsigned long fault;
++ int faulted;
++
++ fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++ __do_copy, &faulted);
++ TASK_REGS(get_current())->tt = save;
++
++ if(!faulted) return(0);
++ else return(n - (fault - (unsigned long) from));
++}
++
++static void __do_strncpy(void *dst, const void *src, int count)
++{
++ strncpy(dst, src, count);
++}
++
++int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
++ void **fault_addr, void **fault_catcher)
++{
++ struct tt_regs save = TASK_REGS(get_current())->tt;
++ unsigned long fault;
++ int faulted;
++
++ fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
++ __do_strncpy, &faulted);
++ TASK_REGS(get_current())->tt = save;
++
++ if(!faulted) return(strlen(dst));
++ else return(-1);
++}
++
++static void __do_clear(void *to, const void *from, int n)
++{
++ memset(to, 0, n);
++}
++
++int __do_clear_user(void *mem, unsigned long len,
++ void **fault_addr, void **fault_catcher)
++{
++ struct tt_regs save = TASK_REGS(get_current())->tt;
++ unsigned long fault;
++ int faulted;
++
++ fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
++ __do_clear, &faulted);
++ TASK_REGS(get_current())->tt = save;
++
++ if(!faulted) return(0);
++ else return(len - (fault - (unsigned long) mem));
++}
++
++int __do_strnlen_user(const char *str, unsigned long n,
++ void **fault_addr, void **fault_catcher)
++{
++ struct tt_regs save = TASK_REGS(get_current())->tt;
++ int ret;
++ unsigned long *faddrp = (unsigned long *)fault_addr;
++ sigjmp_buf jbuf;
++
++ *fault_catcher = &jbuf;
++ if(sigsetjmp(jbuf, 1) == 0)
++ ret = strlen(str) + 1;
++ else ret = *faddrp - (unsigned long) str;
++
++ *fault_addr = NULL;
++ *fault_catcher = NULL;
++
++ TASK_REGS(get_current())->tt = save;
++ return ret;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/unmap.c um/arch/um/kernel/tt/unmap.c
+--- orig/arch/um/kernel/tt/unmap.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tt/unmap.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <sys/mman.h>
++
++int switcheroo(int fd, int prot, void *from, void *to, int size)
++{
++ if(munmap(to, size) < 0){
++ return(-1);
++ }
++ if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
++ return(-1);
++ }
++ if(munmap(from, size) < 0){
++ return(-1);
++ }
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/tty_log.c um/arch/um/kernel/tty_log.c
+--- orig/arch/um/kernel/tty_log.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/tty_log.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,228 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
++ * geoffrey hing <ghing@net.ohio-state.edu>
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include "init.h"
++#include "user.h"
++#include "kern_util.h"
++#include "os.h"
++
++#define TTY_LOG_DIR "./"
++
++/* Set early in boot and then unchanged */
++static char *tty_log_dir = TTY_LOG_DIR;
++static int tty_log_fd = -1;
++
++#define TTY_LOG_OPEN 1
++#define TTY_LOG_CLOSE 2
++#define TTY_LOG_WRITE 3
++#define TTY_LOG_EXEC 4
++
++#define TTY_READ 1
++#define TTY_WRITE 2
++
++struct tty_log_buf {
++ int what;
++ unsigned long tty;
++ int len;
++ int direction;
++ unsigned long sec;
++ unsigned long usec;
++};
++
++int open_tty_log(void *tty, void *current_tty)
++{
++ struct timeval tv;
++ struct tty_log_buf data;
++ char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
++ int fd;
++
++ gettimeofday(&tv, NULL);
++ if(tty_log_fd != -1){
++ data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN,
++ .tty = (unsigned long) tty,
++ .len = sizeof(current_tty),
++ .direction = 0,
++ .sec = tv.tv_sec,
++ .usec = tv.tv_usec } );
++ os_write_file(tty_log_fd, &data, sizeof(data));
++ os_write_file(tty_log_fd, ¤t_tty, data.len);
++ return(tty_log_fd);
++ }
++
++ sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
++ (unsigned int) tv.tv_usec);
++
++ fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
++ 0644);
++ if(fd < 0){
++ printk("open_tty_log : couldn't open '%s', errno = %d\n",
++ buf, -fd);
++ }
++ return(fd);
++}
++
++void close_tty_log(int fd, void *tty)
++{
++ struct tty_log_buf data;
++ struct timeval tv;
++
++ if(tty_log_fd != -1){
++ gettimeofday(&tv, NULL);
++ data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE,
++ .tty = (unsigned long) tty,
++ .len = 0,
++ .direction = 0,
++ .sec = tv.tv_sec,
++ .usec = tv.tv_usec } );
++ os_write_file(tty_log_fd, &data, sizeof(data));
++ return;
++ }
++ os_close_file(fd);
++}
++
++static int log_chunk(int fd, const char *buf, int len)
++{
++ int total = 0, try, missed, n;
++ char chunk[64];
++
++ while(len > 0){
++ try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
++ missed = copy_from_user_proc(chunk, (char *) buf, try);
++ try -= missed;
++ n = os_write_file(fd, chunk, try);
++ if(n != try) {
++ if(n < 0)
++ return(n);
++ return(-EIO);
++ }
++ if(missed != 0)
++ return(-EFAULT);
++
++ len -= try;
++ total += try;
++ buf += try;
++ }
++
++ return(total);
++}
++
++int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
++{
++ struct timeval tv;
++ struct tty_log_buf data;
++ int direction;
++
++ if(fd == tty_log_fd){
++ gettimeofday(&tv, NULL);
++ direction = is_read ? TTY_READ : TTY_WRITE;
++ data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE,
++ .tty = (unsigned long) tty,
++ .len = len,
++ .direction = direction,
++ .sec = tv.tv_sec,
++ .usec = tv.tv_usec } );
++ os_write_file(tty_log_fd, &data, sizeof(data));
++ }
++
++ return(log_chunk(fd, buf, len));
++}
++
++void log_exec(char **argv, void *tty)
++{
++ struct timeval tv;
++ struct tty_log_buf data;
++ char **ptr,*arg;
++ int len;
++
++ if(tty_log_fd == -1) return;
++
++ gettimeofday(&tv, NULL);
++
++ len = 0;
++ for(ptr = argv; ; ptr++){
++ if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++ return;
++ if(arg == NULL) break;
++ len += strlen_user_proc(arg);
++ }
++
++ data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC,
++ .tty = (unsigned long) tty,
++ .len = len,
++ .direction = 0,
++ .sec = tv.tv_sec,
++ .usec = tv.tv_usec } );
++ os_write_file(tty_log_fd, &data, sizeof(data));
++
++ for(ptr = argv; ; ptr++){
++ if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++ return;
++ if(arg == NULL) break;
++ log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
++ }
++}
++
++extern void register_tty_logger(int (*opener)(void *, void *),
++ int (*writer)(int, const char *, int,
++ void *, int),
++ void (*closer)(int, void *));
++
++static int register_logger(void)
++{
++ register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
++ return(0);
++}
++
++__uml_initcall(register_logger);
++
++static int __init set_tty_log_dir(char *name, int *add)
++{
++ tty_log_dir = name;
++ return 0;
++}
++
++__uml_setup("tty_log_dir=", set_tty_log_dir,
++"tty_log_dir=<directory>\n"
++" This is used to specify the directory where the logs of all pty\n"
++" data from this UML machine will be written.\n\n"
++);
++
++static int __init set_tty_log_fd(char *name, int *add)
++{
++ char *end;
++
++ tty_log_fd = strtoul(name, &end, 0);
++ if((*end != '\0') || (end == name)){
++ printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
++ tty_log_fd = -1;
++ }
++ return 0;
++}
++
++__uml_setup("tty_log_fd=", set_tty_log_fd,
++"tty_log_fd=<fd>\n"
++" This is used to specify a preconfigured file descriptor to which all\n"
++" tty data will be written. Preconfigure the descriptor with something\n"
++" like '10>tty_log tty_log_fd=10'.\n\n"
++);
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/uaccess_user.c um/arch/um/kernel/uaccess_user.c
+--- orig/arch/um/kernel/uaccess_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/uaccess_user.c 2004-01-31 02:48:08.000000000 -0500
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <setjmp.h>
++#include <string.h>
++
++/* These are here rather than tt/uaccess.c because skas mode needs them in
++ * order to do SIGBUS recovery when a tmpfs mount runs out of room.
++ */
++
++unsigned long __do_user_copy(void *to, const void *from, int n,
++ void **fault_addr, void **fault_catcher,
++ void (*op)(void *to, const void *from,
++ int n), int *faulted_out)
++{
++ unsigned long *faddrp = (unsigned long *) fault_addr, ret;
++
++ sigjmp_buf jbuf;
++ *fault_catcher = &jbuf;
++ if(sigsetjmp(jbuf, 1) == 0){
++ (*op)(to, from, n);
++ ret = 0;
++ *faulted_out = 0;
++ }
++ else {
++ ret = *faddrp;
++ *faulted_out = 1;
++ }
++ *fault_addr = NULL;
++ *fault_catcher = NULL;
++ return ret;
++}
++
++void __do_copy(void *to, const void *from, int n)
++{
++ memcpy(to, from, n);
++}
++
++
++int __do_copy_to_user(void *to, const void *from, int n,
++ void **fault_addr, void **fault_catcher)
++{
++ unsigned long fault;
++ int faulted;
++
++ fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++ __do_copy, &faulted);
++ if(!faulted) return(0);
++ else return(n - (fault - (unsigned long) to));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/um_arch.c um/arch/um/kernel/um_arch.c
+--- orig/arch/um/kernel/um_arch.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/um_arch.c 2004-01-10 00:11:09.000000000 -0500
+@@ -0,0 +1,431 @@
++/*
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/notifier.h"
++#include "linux/mm.h"
++#include "linux/types.h"
++#include "linux/tty.h"
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/spinlock.h"
++#include "linux/utsname.h"
++#include "linux/sysrq.h"
++#include "linux/seq_file.h"
++#include "linux/delay.h"
++#include "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"
++#include "choose-mode.h"
++#include "mode_kern.h"
++#include "mode.h"
++
++#define DEFAULT_COMMAND_LINE "root=/dev/ubd0"
++
++struct cpuinfo_um boot_cpu_data = {
++ .loops_per_jiffy = 0,
++ .pgd_quick = NULL,
++ .pmd_quick = NULL,
++ .pte_quick = NULL,
++ .pgtable_cache_sz = 0,
++ .ipi_pipe = { -1, -1 }
++};
++
++unsigned long thread_saved_pc(struct thread_struct *thread)
++{
++ return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
++ thread)));
++}
++
++static int show_cpuinfo(struct seq_file *m, void *v)
++{
++ int index = 0;
++
++#ifdef CONFIG_SMP
++ index = (struct cpuinfo_um *)v - cpu_data;
++ if (!(cpu_online_map & (1 << index)))
++ return 0;
++#endif
++
++ seq_printf(m, "processor\t: %d\n", index);
++ seq_printf(m, "vendor_id\t: User Mode Linux\n");
++ seq_printf(m, "model name\t: UML\n");
++ seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
++ seq_printf(m, "host\t\t: %s\n", host_info);
++ seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
++ loops_per_jiffy/(500000/HZ),
++ (loops_per_jiffy/(5000/HZ)) % 100);
++
++ return(0);
++}
++
++static void *c_start(struct seq_file *m, loff_t *pos)
++{
++ return *pos < NR_CPUS ? cpu_data + *pos : NULL;
++}
++
++static void *c_next(struct seq_file *m, void *v, loff_t *pos)
++{
++ ++*pos;
++ return c_start(m, pos);
++}
++
++static void c_stop(struct seq_file *m, void *v)
++{
++}
++
++struct seq_operations cpuinfo_op = {
++ .start = c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = show_cpuinfo,
++};
++
++pte_t * __bad_pagetable(void)
++{
++ panic("Someone should implement __bad_pagetable");
++ return(NULL);
++}
++
++/* Set in linux_main */
++unsigned long host_task_size;
++unsigned long task_size;
++unsigned long uml_start;
++
++/* Set in early boot */
++unsigned long uml_physmem;
++unsigned long uml_reserved;
++unsigned long start_vm;
++unsigned long end_vm;
++int ncpus = 1;
++
++#ifdef CONFIG_MODE_TT
++/* Pointer set in linux_main, the array itself is private to each thread,
++ * and changed at address space creation time so this poses no concurrency
++ * problems.
++ */
++static char *argv1_begin = NULL;
++static char *argv1_end = NULL;
++#endif
++
++/* Set in early boot */
++static int have_root __initdata = 0;
++long physmem_size = 32 * 1024 * 1024;
++
++void set_cmdline(char *cmd)
++{
++#ifdef CONFIG_MODE_TT
++ char *umid, *ptr;
++
++ if(CHOOSE_MODE(honeypot, 0)) return;
++
++ umid = get_umid(1);
++ if(umid != NULL){
++ snprintf(argv1_begin,
++ (argv1_end - argv1_begin) * sizeof(*ptr),
++ "(%s) ", umid);
++ ptr = &argv1_begin[strlen(argv1_begin)];
++ }
++ else ptr = argv1_begin;
++
++ snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
++ memset(argv1_begin + strlen(argv1_begin), '\0',
++ argv1_end - argv1_begin - strlen(argv1_begin));
++#endif
++}
++
++static char *usage_string =
++"User Mode Linux v%s\n"
++" available at http://user-mode-linux.sourceforge.net/\n\n";
++
++static int __init uml_version_setup(char *line, int *add)
++{
++ printf("%s\n", system_utsname.release);
++ exit(0);
++}
++
++__uml_setup("--version", uml_version_setup,
++"--version\n"
++" Prints the version number of the kernel.\n\n"
++);
++
++static int __init uml_root_setup(char *line, int *add)
++{
++ have_root = 1;
++ return 0;
++}
++
++__uml_setup("root=", uml_root_setup,
++"root=<file containing the root fs>\n"
++" This is actually used by the generic kernel in exactly the same\n"
++" way as in any other kernel. If you configure a number of block\n"
++" devices and want to boot off something other than ubd0, you \n"
++" would use something like:\n"
++" root=/dev/ubd5\n\n"
++);
++
++#ifdef CONFIG_SMP
++static int __init uml_ncpus_setup(char *line, int *add)
++{
++ if (!sscanf(line, "%d", &ncpus)) {
++ printf("Couldn't parse [%s]\n", line);
++ return -1;
++ }
++
++ return 0;
++}
++
++__uml_setup("ncpus=", uml_ncpus_setup,
++"ncpus=<# of desired CPUs>\n"
++" This tells an SMP kernel how many virtual processors to start.\n\n"
++);
++#endif
++
++int force_tt = 0;
++
++#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
++#define DEFAULT_TT 0
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++ force_tt = 1;
++ return(0);
++}
++
++#else
++#ifdef CONFIG_MODE_SKAS
++
++#define DEFAULT_TT 0
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++ printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
++ return(0);
++}
++
++#else
++#ifdef CONFIG_MODE_TT
++
++#define DEFAULT_TT 1
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++ printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
++ return(0);
++}
++
++#else
++
++#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
++
++#endif
++#endif
++#endif
++
++__uml_setup("mode=tt", mode_tt_setup,
++"mode=tt\n"
++" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
++" forces UML to run in tt (tracing thread) mode. It is not the default\n"
++" because it's slower and less secure than skas mode.\n\n"
++);
++
++int mode_tt = DEFAULT_TT;
++
++static int __init Usage(char *line, int *add)
++{
++ const char **p;
++
++ printf(usage_string, system_utsname.release);
++ p = &__uml_help_start;
++ while (p < &__uml_help_end) {
++ printf("%s", *p);
++ p++;
++ }
++ exit(0);
++}
++
++__uml_setup("--help", Usage,
++"--help\n"
++" Prints this message.\n\n"
++);
++
++static int __init uml_checksetup(char *line, int *add)
++{
++ struct uml_param *p;
++
++ p = &__uml_setup_start;
++ while(p < &__uml_setup_end) {
++ int n;
++
++ n = strlen(p->str);
++ if(!strncmp(line, p->str, n)){
++ if (p->setup_func(line + n, add)) return 1;
++ }
++ p++;
++ }
++ return 0;
++}
++
++static void __init uml_postsetup(void)
++{
++ initcall_t *p;
++
++ p = &__uml_postsetup_start;
++ while(p < &__uml_postsetup_end){
++ (*p)();
++ p++;
++ }
++ return;
++}
++
++/* Set during early boot */
++unsigned long brk_start;
++unsigned long end_iomem;
++
++#define MIN_VMALLOC (32 * 1024 * 1024)
++
++int linux_main(int argc, char **argv)
++{
++ unsigned long avail;
++ unsigned long virtmem_size, max_physmem;
++ unsigned int i, add;
++
++ for (i = 1; i < argc; i++){
++ if((i == 1) && (argv[i][0] == ' ')) continue;
++ add = 1;
++ uml_checksetup(argv[i], &add);
++ if(add) add_arg(saved_command_line, argv[i]);
++ }
++ if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
++
++ mode_tt = force_tt ? 1 : !can_do_skas();
++ uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
++ &host_task_size, &task_size);
++
++ brk_start = (unsigned long) sbrk(0);
++ CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
++
++ uml_physmem = uml_start;
++
++ /* Reserve up to 4M after the current brk */
++ uml_reserved = ROUND_4M(brk_start) + (1 << 22);
++
++ setup_machinename(system_utsname.machine);
++
++#ifdef CONFIG_MODE_TT
++ argv1_begin = argv[1];
++ argv1_end = &argv[1][strlen(argv[1])];
++#endif
++
++ highmem = 0;
++ iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
++ max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
++
++ /* Zones have to begin on a 1 << MAX_ORDER page boundary,
++ * so this makes sure that's true for highmem
++ */
++ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
++ if(physmem_size + iomem_size > max_physmem){
++ highmem = physmem_size + iomem_size - max_physmem;
++ physmem_size -= highmem;
++#ifndef CONFIG_HIGHMEM
++ highmem = 0;
++ printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
++ "to %ld bytes\n", physmem_size);
++#endif
++ }
++
++ high_physmem = uml_physmem + physmem_size;
++ end_iomem = high_physmem + iomem_size;
++ high_memory = (void *) end_iomem;
++
++ start_vm = VMALLOC_START;
++
++ setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
++ if(init_maps(physmem_size, iomem_size, highmem)){
++ printf("Failed to allocate mem_map for %ld bytes of physical "
++ "memory and %ld bytes of highmem\n", physmem_size,
++ highmem);
++ exit(1);
++ }
++
++ virtmem_size = physmem_size;
++ avail = get_kmem_end() - start_vm;
++ if(physmem_size > avail) virtmem_size = avail;
++ end_vm = start_vm + virtmem_size;
++
++ if(virtmem_size < physmem_size)
++ printf("Kernel virtual memory size shrunk to %ld bytes\n",
++ virtmem_size);
++
++ uml_postsetup();
++
++ init_task.thread.kernel_stack = (unsigned long) &init_task +
++ 2 * PAGE_SIZE;
++
++ task_protections((unsigned long) &init_task);
++ os_flush_stdout();
++
++ return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
++}
++
++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();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/umid.c um/arch/um/kernel/umid.c
+--- orig/arch/um/kernel/umid.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/umid.c 2004-01-26 10:13:01.000000000 -0500
+@@ -0,0 +1,327 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++#include <dirent.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/param.h>
++#include "user.h"
++#include "umid.h"
++#include "init.h"
++#include "os.h"
++#include "user_util.h"
++#include "choose-mode.h"
++
++#define UMID_LEN 64
++#define UML_DIR "~/.uml/"
++
++/* Changed by set_umid and make_umid, which are run early in boot */
++static char umid[UMID_LEN] = { 0 };
++
++/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
++static char *uml_dir = UML_DIR;
++
++/* Changed by set_umid */
++static int umid_is_random = 1;
++static int umid_inited = 0;
++
++static int make_umid(int (*printer)(const char *fmt, ...));
++
++static int __init set_umid(char *name, int is_random,
++ int (*printer)(const char *fmt, ...))
++{
++ if(umid_inited){
++ (*printer)("Unique machine name can't be set twice\n");
++ return(-1);
++ }
++
++ if(strlen(name) > UMID_LEN - 1)
++ (*printer)("Unique machine name is being truncated to %s "
++ "characters\n", UMID_LEN);
++ strncpy(umid, name, UMID_LEN - 1);
++ umid[UMID_LEN - 1] = '\0';
++
++ umid_is_random = is_random;
++ umid_inited = 1;
++ return 0;
++}
++
++static int __init set_umid_arg(char *name, int *add)
++{
++ return(set_umid(name, 0, printf));
++}
++
++__uml_setup("umid=", set_umid_arg,
++"umid=<name>\n"
++" This is used to assign a unique identity to this UML machine and\n"
++" is used for naming the pid file and management console socket.\n\n"
++);
++
++int __init umid_file_name(char *name, char *buf, int len)
++{
++ int n;
++
++ if(!umid_inited && make_umid(printk)) return(-1);
++
++ n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
++ if(n > len){
++ printk("umid_file_name : buffer too short\n");
++ return(-1);
++ }
++
++ sprintf(buf, "%s%s/%s", uml_dir, umid, name);
++ return(0);
++}
++
++extern int tracing_pid;
++
++static int __init create_pid_file(void)
++{
++ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
++ char pid[sizeof("nnnnn\0")];
++ int fd, n;
++
++ if(umid_file_name("pid", file, sizeof(file))) return 0;
++
++ fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
++ 0644);
++ if(fd < 0){
++ printf("Open of machine pid file \"%s\" failed - "
++ "err = %d\n", file, -fd);
++ return 0;
++ }
++
++ sprintf(pid, "%d\n", os_getpid());
++ n = os_write_file(fd, pid, strlen(pid));
++ if(n != strlen(pid))
++ printf("Write of pid file failed - err = %d\n", -n);
++ os_close_file(fd);
++ return 0;
++}
++
++static int actually_do_remove(char *dir)
++{
++ DIR *directory;
++ struct dirent *ent;
++ int len;
++ char file[256];
++
++ directory = opendir(dir);
++ if(directory == NULL){
++ printk("actually_do_remove : couldn't open directory '%s', "
++ "errno = %d\n", dir, errno);
++ return(1);
++ }
++ while((ent = readdir(directory)) != NULL){
++ if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
++ continue;
++ len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
++ if(len > sizeof(file)){
++ printk("Not deleting '%s' from '%s' - name too long\n",
++ ent->d_name, dir);
++ continue;
++ }
++ sprintf(file, "%s/%s", dir, ent->d_name);
++ if(unlink(file) < 0){
++ printk("actually_do_remove : couldn't remove '%s' "
++ "from '%s', errno = %d\n", ent->d_name, dir,
++ errno);
++ return(1);
++ }
++ }
++ if(rmdir(dir) < 0){
++ printk("actually_do_remove : couldn't rmdir '%s', "
++ "errno = %d\n", dir, errno);
++ return(1);
++ }
++ return(0);
++}
++
++void remove_umid_dir(void)
++{
++ char dir[strlen(uml_dir) + UMID_LEN + 1];
++ if(!umid_inited) return;
++
++ sprintf(dir, "%s%s", uml_dir, umid);
++ actually_do_remove(dir);
++}
++
++char *get_umid(int only_if_set)
++{
++ if(only_if_set && umid_is_random) return(NULL);
++ return(umid);
++}
++
++int not_dead_yet(char *dir)
++{
++ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
++ char pid[sizeof("nnnnn\0")], *end;
++ int dead, fd, p, n;
++
++ sprintf(file, "%s/pid", dir);
++ dead = 0;
++ fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++ if(fd < 0){
++ if(fd != -ENOENT){
++ printk("not_dead_yet : couldn't open pid file '%s', "
++ "err = %d\n", file, -fd);
++ return(1);
++ }
++ dead = 1;
++ }
++ if(fd > 0){
++ n = os_read_file(fd, pid, sizeof(pid));
++ if(n < 0){
++ printk("not_dead_yet : couldn't read pid file '%s', "
++ "err = %d\n", file, -n);
++ return(1);
++ }
++ p = strtoul(pid, &end, 0);
++ if(end == pid){
++ printk("not_dead_yet : couldn't parse pid file '%s', "
++ "errno = %d\n", file, errno);
++ dead = 1;
++ }
++ if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
++ (p == CHOOSE_MODE(tracing_pid, os_getpid())))
++ dead = 1;
++ }
++ if(!dead) return(1);
++ return(actually_do_remove(dir));
++}
++
++static int __init set_uml_dir(char *name, int *add)
++{
++ if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
++ uml_dir = malloc(strlen(name) + 1);
++ if(uml_dir == NULL){
++ printf("Failed to malloc uml_dir - error = %d\n",
++ errno);
++ uml_dir = name;
++ /* Return 0 here because do_initcalls doesn't look at
++ * the return value.
++ */
++ return(0);
++ }
++ sprintf(uml_dir, "%s/", name);
++ }
++ else uml_dir = name;
++ return(0);
++}
++
++static int __init make_uml_dir(void)
++{
++ char dir[MAXPATHLEN + 1] = { '\0' };
++ int len;
++
++ if(*uml_dir == '~'){
++ char *home = getenv("HOME");
++
++ if(home == NULL){
++ printf("make_uml_dir : no value in environment for "
++ "$HOME\n");
++ exit(1);
++ }
++ 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';
++ }
++
++ uml_dir = malloc(strlen(dir) + 1);
++ if(uml_dir == NULL){
++ printf("make_uml_dir : malloc failed, errno = %d\n", errno);
++ exit(1);
++ }
++ strcpy(uml_dir, dir);
++
++ if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
++ printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
++ return(-1);
++ }
++ return 0;
++}
++
++static int __init make_umid(int (*printer)(const char *fmt, ...))
++{
++ int fd, err;
++ char tmp[strlen(uml_dir) + UMID_LEN + 1];
++
++ strncpy(tmp, uml_dir, sizeof(tmp) - 1);
++ tmp[sizeof(tmp) - 1] = '\0';
++
++ if(!umid_inited){
++ strcat(tmp, "XXXXXX");
++ fd = mkstemp(tmp);
++ if(fd < 0){
++ (*printer)("make_umid - mkstemp failed, errno = %d\n",
++ errno);
++ return(1);
++ }
++
++ os_close_file(fd);
++ /* There's a nice tiny little race between this unlink and
++ * the mkdir below. It'd be nice if there were a mkstemp
++ * for directories.
++ */
++ unlink(tmp);
++ set_umid(&tmp[strlen(uml_dir)], 1, printer);
++ }
++
++ sprintf(tmp, "%s%s", uml_dir, umid);
++
++ err = mkdir(tmp, 0777);
++ if(err < 0){
++ if(errno == EEXIST){
++ if(not_dead_yet(tmp)){
++ (*printer)("umid '%s' is in use\n", umid);
++ return(-1);
++ }
++ err = mkdir(tmp, 0777);
++ }
++ }
++ if(err < 0){
++ (*printer)("Failed to create %s - errno = %d\n", umid, errno);
++ return(-1);
++ }
++
++ return(0);
++}
++
++__uml_setup("uml_dir=", set_uml_dir,
++"uml_dir=<directory>\n"
++" The location to place the pid and umid files.\n\n"
++);
++
++__uml_postsetup(make_uml_dir);
++
++static int __init make_umid_setup(void)
++{
++ return(make_umid(printf));
++}
++
++__uml_postsetup(make_umid_setup);
++__uml_postsetup(create_pid_file);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/kernel/user_syms.c um/arch/um/kernel/user_syms.c
+--- orig/arch/um/kernel/user_syms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/user_syms.c 2004-01-23 00:44:09.000000000 -0500
+@@ -0,0 +1,118 @@
++#include <stdio.h>
++#include <unistd.h>
++#include <dirent.h>
++#include <fcntl.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(strlen);
++EXPORT_SYMBOL(printf);
++
++EXPORT_SYMBOL(find_iomem);
+diff -Naur -X ../exclude-files orig/arch/um/kernel/user_util.c um/arch/um/kernel/user_util.c
+--- orig/arch/um/kernel/user_util.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/kernel/user_util.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,164 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <limits.h>
++#include <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"
++#include "uml-config.h"
++
++#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
++
++/* Changed in linux_main and setup_arch, which run before SMP is started */
++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 stop(void)
++{
++ while(1) sleep(1000000);
++}
++
++void stack_protections(unsigned long address)
++{
++ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++
++ if(mprotect((void *) address, page_size(), prot) < 0)
++ panic("protecting stack failed, errno = %d", errno);
++}
++
++void task_protections(unsigned long address)
++{
++ unsigned long guard = address + page_size();
++ unsigned long stack = guard + page_size();
++ int prot = 0, pages;
++#ifdef notdef
++ if(mprotect((void *) guard, page_size(), prot) < 0)
++ panic("protecting guard page failed, errno = %d", errno);
++#endif
++ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
++ prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++ if(mprotect((void *) stack, pages * page_size(), prot) < 0)
++ panic("protecting stack failed, errno = %d", errno);
++}
++
++int wait_for_stop(int pid, int sig, int cont_type, void *relay)
++{
++ sigset_t *relay_signals = relay;
++ int status, ret;
++
++ while(1){
++ ret = waitpid(pid, &status, WUNTRACED);
++ if((ret < 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 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);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/link.ld.in um/arch/um/link.ld.in
+--- orig/arch/um/link.ld.in 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/link.ld.in 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,94 @@
++OUTPUT_FORMAT("ELF_FORMAT")
++OUTPUT_ARCH(ELF_ARCH)
++ENTRY(_start)
++
++SECTIONS
++{
++ . = START() + SIZEOF_HEADERS;
++
++ __binary_start = .;
++ifdef(`MODE_TT', `
++ .thread_private : {
++ __start_thread_private = .;
++ errno = .;
++ . += 4;
++ arch/um/kernel/tt/unmap_fin.o (.data)
++ __end_thread_private = .;
++ }
++ . = ALIGN(4096);
++ .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
++')
++ . = 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*)
++ }
++ .fini : { *(.fini) } =0x9090
++ .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
++ .rodata1 : { *(.rodata1) }
++ _etext = .;
++ PROVIDE (etext = .);
++
++ . = ALIGN(4096);
++ PROVIDE (_sdata = .);
++
++include(`arch/um/common.ld.in')
++
++ .data :
++ {
++ . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
++ *(.data.init_task)
++ *(.data)
++ *(.gnu.linkonce.d*)
++ CONSTRUCTORS
++ }
++ .data1 : { *(.data1) }
++ .ctors :
++ {
++ *(.ctors)
++ }
++ .dtors :
++ {
++ *(.dtors)
++ }
++
++ .got : { *(.got.plt) *(.got) }
++ .dynamic : { *(.dynamic) }
++ /* We want the small data sections together, so single-instruction offsets
++ can access them all, and initialized data all before uninitialized, so
++ we can shorten the on-disk segment size. */
++ .sdata : { *(.sdata) }
++ _edata = .;
++ PROVIDE (edata = .);
++ . = ALIGN(0x1000);
++ .sbss :
++ {
++ __bss_start = .;
++ PROVIDE(_bss_start = .);
++ *(.sbss)
++ *(.scommon)
++ }
++ .bss :
++ {
++ *(.dynbss)
++ *(.bss)
++ *(COMMON)
++ }
++ _end = . ;
++ PROVIDE (end = .);
++ /* Stabs debugging sections. */
++ .stab 0 : { *(.stab) }
++ .stabstr 0 : { *(.stabstr) }
++ .stab.excl 0 : { *(.stab.excl) }
++ .stab.exclstr 0 : { *(.stab.exclstr) }
++ .stab.index 0 : { *(.stab.index) }
++ .stab.indexstr 0 : { *(.stab.indexstr) }
++ .comment 0 : { *(.comment) }
++}
+diff -Naur -X ../exclude-files orig/arch/um/main.c um/arch/um/main.c
+--- orig/arch/um/main.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/main.c 2004-01-29 00:48:42.000000000 -0500
+@@ -0,0 +1,199 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/resource.h>
++#include <sys/mman.h>
++#include <sys/user.h>
++#include <asm/page.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "signal_user.h"
++#include "user.h"
++#include "init.h"
++#include "mode.h"
++#include "choose-mode.h"
++#include "uml-config.h"
++
++/* Set in set_stklim, which is called from main and __wrap_malloc.
++ * __wrap_malloc only calls it if main hasn't started.
++ */
++unsigned long stacksizelim;
++
++/* Set in main */
++char *linux_prog;
++
++#define PGD_BOUND (4 * 1024 * 1024)
++#define STACKSIZE (8 * 1024 * 1024)
++#define THREAD_NAME_LEN (256)
++
++static void set_stklim(void)
++{
++ struct rlimit lim;
++
++ if(getrlimit(RLIMIT_STACK, &lim) < 0){
++ perror("getrlimit");
++ exit(1);
++ }
++ if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
++ lim.rlim_cur = STACKSIZE;
++ if(setrlimit(RLIMIT_STACK, &lim) < 0){
++ perror("setrlimit");
++ exit(1);
++ }
++ }
++ stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
++}
++
++static __init void do_uml_initcalls(void)
++{
++ initcall_t *call;
++
++ call = &__uml_initcall_start;
++ while (call < &__uml_initcall_end){;
++ (*call)();
++ call++;
++ }
++}
++
++static void last_ditch_exit(int sig)
++{
++ CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
++ signal(SIGINT, SIG_DFL);
++ signal(SIGTERM, SIG_DFL);
++ signal(SIGHUP, SIG_DFL);
++ uml_cleanup();
++ exit(1);
++}
++
++extern int uml_exitcode;
++
++int main(int argc, char **argv, char **envp)
++{
++ char **new_argv;
++ sigset_t mask;
++ int ret, i;
++
++ /* Enable all signals except SIGIO - in some environments, we can
++ * enter with some signals blocked
++ */
++
++ sigemptyset(&mask);
++ sigaddset(&mask, SIGIO);
++ if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
++ perror("sigprocmask");
++ exit(1);
++ }
++
++#ifdef UML_CONFIG_MODE_TT
++ /* Allocate memory for thread command lines */
++ if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
++
++ char padding[THREAD_NAME_LEN] = {
++ [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0'
++ };
++
++ new_argv = malloc((argc + 2) * sizeof(char*));
++ if(!new_argv) {
++ perror("Allocating extended argv");
++ exit(1);
++ }
++
++ new_argv[0] = argv[0];
++ new_argv[1] = padding;
++
++ for(i = 2; i <= argc; i++)
++ new_argv[i] = argv[i - 1];
++ new_argv[argc + 1] = NULL;
++
++ execvp(new_argv[0], new_argv);
++ perror("execing with extended args");
++ exit(1);
++ }
++#endif
++
++ linux_prog = argv[0];
++
++ set_stklim();
++
++ new_argv = malloc((argc + 1) * sizeof(char *));
++ if(new_argv == NULL){
++ perror("Mallocing argv");
++ exit(1);
++ }
++ for(i=0;i<argc;i++){
++ new_argv[i] = strdup(argv[i]);
++ if(new_argv[i] == NULL){
++ perror("Mallocing an arg");
++ exit(1);
++ }
++ }
++ new_argv[argc] = NULL;
++
++ set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++ set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++ set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++
++ 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);
++}
++
++#define CAN_KMALLOC() \
++ (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1))
++
++extern void *__real_malloc(int);
++
++void *__wrap_malloc(int size)
++{
++ if(CAN_KMALLOC())
++ 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)
++{
++ if(CAN_KMALLOC()) kfree(ptr);
++ else __real_free(ptr);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/Makefile um/arch/um/Makefile
+--- orig/arch/um/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile 2004-02-14 06:26:41.000000000 -0500
+@@ -0,0 +1,174 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++OS := $(shell uname -s)
++
++ARCH_DIR = arch/um
++
++core-y := kernel sys-$(SUBARCH) os-$(OS)
++drivers-y := fs drivers
++subdir-y := $(core-y) $(drivers-y)
++SUBDIRS += $(foreach dir,$(subdir-y),$(ARCH_DIR)/$(dir))
++
++CORE_FILES += $(foreach dir,$(core-y),$(ARCH_DIR)/$(dir)/built-in.o)
++DRIVERS += $(foreach dir,$(drivers-y),$(ARCH_DIR)/$(dir)/built-in.o)
++
++include $(ARCH_DIR)/Makefile-$(SUBARCH)
++include $(ARCH_DIR)/Makefile-os-$(OS)
++
++MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
++MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
++
++ifneq ($(MAKEFILE-y),)
++ include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
++endif
++
++EXTRAVERSION := $(EXTRAVERSION)-1um
++
++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)
++
++ifeq ($(CONFIG_DEBUGSYM),y)
++CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
++endif
++
++CFLAGS-$(CONFIG_DEBUGSYM) += -g
++
++ARCH_INCLUDE = -I$(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 += $(ARCH_CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
++ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
++ $(MODE_INCLUDE)
++
++LINKFLAGS += -r
++
++LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
++
++# These are needed for clean and mrproper, since in that case .config is not
++# included; the values here are meaningless
++
++CONFIG_NEST_LEVEL ?= 0
++CONFIG_KERNEL_HALF_GIGS ?= 0
++
++SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
++
++# These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT +
++# CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case.
++
++LINK_TT = -static
++LD_SCRIPT_TT := link.ld
++
++ifeq ($(CONFIG_STATIC_LINK),y)
++ LINK-y += $(LINK_TT)
++ LD_SCRIPT-y := $(LD_SCRIPT_TT)
++else
++ifeq ($(CONFIG_MODE_TT),y)
++ LINK-y += $(LINK_TT)
++ LD_SCRIPT-y := $(LD_SCRIPT_TT)
++else
++ifeq ($(CONFIG_MODE_SKAS),y)
++ LINK-y += $(LINK_SKAS)
++ LD_SCRIPT-y := $(LD_SCRIPT_SKAS)
++endif
++endif
++endif
++
++LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y)
++M4_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT)
++
++$(LD_SCRIPT-y): $(LD_SCRIPT-y).in
++ pages=$$(( 1 << $(CONFIG_KERNEL_STACK_ORDER) )) ; \
++ m4 -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
++ -DELF_FORMAT=$(ELF_FORMAT) $(M4_MODE_TT) \
++ -DKERNEL_STACK_SIZE=$$(( 4096 * $$pages )) $< > $@
++
++SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \
++ arch-signal.h
++SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
++
++ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
++ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
++
++ifeq ($(CONFIG_MODE_SKAS), y)
++$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++endif
++
++GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
++
++setup: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
++
++linux: setup $(ARCH_DIR)/main.o vmlinux $(LD_SCRIPT-y)
++ mv vmlinux vmlinux.o
++ $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
++ -o linux $(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)) $(ARCH_INCLUDE) \
++ $(MODE_INCLUDE)
++
++# To get a definition of F_SETSIG
++USER_CFLAGS += -D_GNU_SOURCE
++
++CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(ARCH_DIR)/dyn_link.ld \
++ $(GEN_HEADERS) $(ARCH_DIR)/include/uml-config.h
++
++$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
++ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++archmrproper:
++ rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
++ $(LD_SCRIPT) $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
++
++archclean: sysclean
++ find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
++ -o -name '*.gcov' \) -type f -print | xargs rm -f
++ cd $(ARCH_DIR) ; \
++ for dir in $(subdir-y) util ; do $(MAKE) -C $$dir clean; done
++
++archdep:
++
++$(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)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
++ $< > $@
++
++$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
++ sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@
++
++$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
++ $(ARCH_DIR)/util/mk_task_kern.c $(SYS_HEADERS)
++ $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_task
++
++$(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util/mk_constants_user.c \
++ $(ARCH_DIR)/util/mk_constants_kern.c
++ $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_constants
++
++export SUBARCH USER_CFLAGS OS
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-i386 um/arch/um/Makefile-i386
+--- orig/arch/um/Makefile-i386 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-i386 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,35 @@
++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)
++
++I386_H = $(ARCH_DIR)/include/sysdep-i386
++SYS = $(ARCH_DIR)/sys-i386
++UTIL = $(SYS)/util
++SUBDIRS += $(UTIL)
++
++SYS_HEADERS = $(I386_H)/sc.h $(I386_H)/thread.h
++
++$(I386_H)/sc.h : $(UTIL)/mk_sc
++ $(UTIL)/mk_sc > $@
++
++$(I386_H)/thread.h : $(UTIL)/mk_thread
++ $(UTIL)/mk_thread > $@
++
++$(UTIL)/mk_sc : $(UTIL)/mk_sc.c
++ $(MAKE) -C $(UTIL) mk_sc
++
++$(UTIL)/mk_thread : $(UTIL)/mk_thread_user.c $(UTIL)/mk_thread_kern.c \
++ $(I386_H)/sc.h
++ $(MAKE) -C $(UTIL) mk_thread
++
++sysclean :
++ rm -f $(SYS_HEADERS)
++ $(MAKE) -C $(UTIL) clean
++ $(MAKE) -C $(SYS) clean
++
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-ia64 um/arch/um/Makefile-ia64
+--- orig/arch/um/Makefile-ia64 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-ia64 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1 @@
++START_ADDR = 0x1000000000000000
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-os-Linux um/arch/um/Makefile-os-Linux
+--- orig/arch/um/Makefile-os-Linux 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-os-Linux 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers
++DRIVERS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-ppc um/arch/um/Makefile-ppc
+--- orig/arch/um/Makefile-ppc 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-ppc 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-skas um/arch/um/Makefile-skas
+--- orig/arch/um/Makefile-skas 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-skas 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,20 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++PROFILE += -pg
++
++CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
++CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
++LINK-$(CONFIG_GPROF) += $(PROFILE)
++
++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include
++
++LINK_SKAS = -Wl,-rpath,/lib
++LD_SCRIPT_SKAS = dyn_link.ld
++
++GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++
++$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
++ $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
+diff -Naur -X ../exclude-files orig/arch/um/Makefile-tt um/arch/um/Makefile-tt
+--- orig/arch/um/Makefile-tt 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/Makefile-tt 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/tt/include
++
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/etap.h um/arch/um/os-Linux/drivers/etap.h
+--- orig/arch/um/os-Linux/drivers/etap.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/etap.h 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/ethertap_kern.c um/arch/um/os-Linux/drivers/ethertap_kern.c
+--- orig/arch/um/os-Linux/drivers/ethertap_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/ethertap_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,122 @@
++/*
++ * 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"
++
++struct ethertap_init {
++ char *dev_name;
++ char *gate_addr;
++};
++
++static void etap_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *pri;
++ struct ethertap_data *epri;
++ struct ethertap_init *init = data;
++
++ init_etherdev(dev, 0);
++ pri = dev->priv;
++ epri = (struct ethertap_data *) pri->user;
++ *epri = ((struct ethertap_data)
++ { .dev_name = init->dev_name,
++ .gate_addr = init->gate_addr,
++ .data_fd = -1,
++ .control_fd = -1,
++ .dev = dev });
++
++ printk("ethertap backend - %s", epri->dev_name);
++ if(epri->gate_addr != NULL)
++ printk(", IP = %s", epri->gate_addr);
++ printk("\n");
++}
++
++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 = eth_protocol,
++ .read = etap_read,
++ .write = etap_write,
++};
++
++int ethertap_setup(char *str, char **mac_out, void *data)
++{
++ struct ethertap_init *init = data;
++
++ *init = ((struct ethertap_init)
++ { .dev_name = NULL,
++ .gate_addr = NULL });
++ if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
++ &init->gate_addr))
++ return(0);
++ if(init->dev_name == NULL){
++ printk("ethertap_setup : Missing tap device name\n");
++ return(0);
++ }
++
++ return(1);
++}
++
++static struct transport ethertap_transport = {
++ .list = LIST_HEAD_INIT(ethertap_transport.list),
++ .name = "ethertap",
++ .setup = ethertap_setup,
++ .user = ðertap_user_info,
++ .kern = ðertap_kern_info,
++ .private_size = sizeof(struct ethertap_data),
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/ethertap_user.c um/arch/um/os-Linux/drivers/ethertap_user.c
+--- orig/arch/um/os-Linux/drivers/ethertap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/ethertap_user.c 2003-10-21 03:26:07.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 <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;
++ int n;
++
++ change.what = op;
++ memcpy(change.addr, addr, sizeof(change.addr));
++ memcpy(change.netmask, netmask, sizeof(change.netmask));
++ n = os_write_file(fd, &change, sizeof(change));
++ if(n != sizeof(change))
++ printk("etap_change - request failed, err = %d\n", -n);
++ 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);
++ os_close_file(data->data_me);
++ os_close_file(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, n;
++ 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 = pid;
++ os_close_file(data_remote);
++ os_close_file(control_remote);
++ n = os_read_file(control_me, &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("etap_tramp : read of status failed, err = %d\n", -n);
++ 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 < 0){
++ printk("data os_pipe failed - err = %d\n", -err);
++ return(err);
++ }
++
++ err = os_pipe(control_fds, 1, 0);
++ if(err < 0){
++ printk("control os_pipe failed - err = %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 - err = %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);
++ os_close_file(fd);
++ os_shutdown_socket(pri->data_fd, 1, 1);
++ os_close_file(pri->data_fd);
++ pri->data_fd = -1;
++ os_close_file(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/Makefile um/arch/um/os-Linux/drivers/Makefile
+--- orig/arch/um/os-Linux/drivers/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/Makefile 2003-10-21 03:26:07.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)
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap.h um/arch/um/os-Linux/drivers/tuntap.h
+--- orig/arch/um/os-Linux/drivers/tuntap.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/tuntap.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,32 @@
++/*
++ * 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;
++};
++
++extern struct net_user_info tuntap_user_info;
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap_kern.c um/arch/um/os-Linux/drivers/tuntap_kern.c
+--- orig/arch/um/os-Linux/drivers/tuntap_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/tuntap_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,105 @@
++/*
++ * 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_init {
++ char *dev_name;
++ char *gate_addr;
++};
++
++static void tuntap_init(struct net_device *dev, void *data)
++{
++ struct uml_net_private *pri;
++ struct tuntap_data *tpri;
++ struct tuntap_init *init = data;
++
++ init_etherdev(dev, 0);
++ pri = dev->priv;
++ tpri = (struct tuntap_data *) pri->user;
++ *tpri = ((struct tuntap_data)
++ { .dev_name = init->dev_name,
++ .fixed_config = (init->dev_name != NULL),
++ .gate_addr = init->gate_addr,
++ .fd = -1,
++ .dev = dev });
++ printk("TUN/TAP backend - ");
++ if(tpri->gate_addr != NULL)
++ printk("IP = %s", tpri->gate_addr);
++ printk("\n");
++}
++
++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 = eth_protocol,
++ .read = tuntap_read,
++ .write = tuntap_write,
++};
++
++int tuntap_setup(char *str, char **mac_out, void *data)
++{
++ struct tuntap_init *init = data;
++
++ *init = ((struct tuntap_init)
++ { .dev_name = NULL,
++ .gate_addr = NULL });
++ if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
++ &init->gate_addr))
++ return(0);
++
++ return(1);
++}
++
++static struct transport tuntap_transport = {
++ .list = LIST_HEAD_INIT(tuntap_transport.list),
++ .name = "tuntap",
++ .setup = tuntap_setup,
++ .user = &tuntap_user_info,
++ .kern = &tuntap_kern_info,
++ .private_size = sizeof(struct tuntap_data),
++ .setup_size = sizeof(struct tuntap_init),
++};
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap_user.c um/arch/um/os-Linux/drivers/tuntap_user.c
+--- orig/arch/um/os-Linux/drivers/tuntap_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/drivers/tuntap_user.c 2003-11-12 00:02:30.000000000 -0500
+@@ -0,0 +1,224 @@
++/*
++ * 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 <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);
++ os_close_file(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);
++
++ os_close_file(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 < 0)
++ return(err);
++
++ if(pri->fixed_config){
++ pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
++ if(pri->fd < 0){
++ printk("Failed to open /dev/net/tun, err = %d\n",
++ -pri->fd);
++ return(pri->fd);
++ }
++ memset(&ifr, 0, sizeof(ifr));
++ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
++ 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\n", errno);
++ os_close_file(pri->fd);
++ return(-errno);
++ }
++ }
++ else {
++ err = os_pipe(fds, 0, 0);
++ if(err < 0){
++ printk("tuntap_open : os_pipe failed - err = %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) {
++ printk("%s", output);
++ free_output_buffer(buffer);
++ printk("tuntap_open_tramp failed - err = %d\n", -err);
++ return(err);
++ }
++
++ pri->dev_name = uml_strdup(buffer);
++ output += IFNAMSIZ;
++ printk("%s", output);
++ free_output_buffer(buffer);
++
++ os_close_file(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);
++ os_close_file(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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/file.c um/arch/um/os-Linux/file.c
+--- orig/arch/um/os-Linux/file.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/file.c 2004-01-10 06:52:24.000000000 -0500
+@@ -0,0 +1,668 @@
++/*
++ * 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/types.h>
++#include <sys/stat.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"
++
++static void copy_stat(struct uml_stat *dst, struct stat64 *src)
++{
++ *dst = ((struct uml_stat) {
++ .ust_dev = src->st_dev, /* device */
++ .ust_ino = src->st_ino, /* inode */
++ .ust_mode = src->st_mode, /* protection */
++ .ust_nlink = src->st_nlink, /* number of hard links */
++ .ust_uid = src->st_uid, /* user ID of owner */
++ .ust_gid = src->st_gid, /* group ID of owner */
++ .ust_size = src->st_size, /* total size, in bytes */
++ .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
++ .ust_blocks = src->st_blocks, /* number of blocks allocated */
++ .ust_atime = src->st_atime, /* time of last access */
++ .ust_mtime = src->st_mtime, /* time of last modification */
++ .ust_ctime = src->st_ctime, /* time of last change */
++ });
++}
++
++int os_stat_fd(const int fd, struct uml_stat *ubuf)
++{
++ struct stat64 sbuf;
++ int err;
++
++ do {
++ err = fstat64(fd, &sbuf);
++ } while((err < 0) && (errno == EINTR)) ;
++
++ if(err < 0)
++ return(-errno);
++
++ if(ubuf != NULL)
++ copy_stat(ubuf, &sbuf);
++ return(err);
++}
++
++int os_stat_file(const char *file_name, struct uml_stat *ubuf)
++{
++ struct stat64 sbuf;
++ int err;
++
++ do {
++ err = stat64(file_name, &sbuf);
++ } while((err < 0) && (errno == EINTR)) ;
++
++ if(err < 0)
++ return(-errno);
++
++ if(ubuf != NULL)
++ copy_stat(ubuf, &sbuf);
++ return(err);
++}
++
++int os_access(const char* file, int mode)
++{
++ int amode, err;
++
++ amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
++ (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
++
++ err = access(file, amode);
++ if(err < 0)
++ return(-errno);
++
++ return(0);
++}
++
++void os_print_error(int error, const char* str)
++{
++ errno = error < 0 ? -error : error;
++
++ perror(str);
++}
++
++/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
++int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
++{
++ int err;
++
++ err = ioctl(fd, cmd, arg);
++ if(err < 0)
++ return(-errno);
++
++ return(err);
++}
++
++int os_window_size(int fd, int *rows, int *cols)
++{
++ struct winsize size;
++
++ if(ioctl(fd, TIOCGWINSZ, &size) < 0)
++ return(-errno);
++
++ *rows = size.ws_row;
++ *cols = size.ws_col;
++
++ return(0);
++}
++
++int os_new_tty_pgrp(int fd, int pid)
++{
++ if(ioctl(fd, TIOCSCTTY, 0) < 0){
++ printk("TIOCSCTTY failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ if(tcsetpgrp(fd, pid) < 0){
++ printk("tcsetpgrp failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ return(0);
++}
++
++/* FIXME: ensure namebuf in os_get_if_name is big enough */
++int os_get_ifname(int fd, char* namebuf)
++{
++ if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
++ return(-errno);
++
++ return(0);
++}
++
++int os_set_slip(int fd)
++{
++ int disc, sencap;
++
++ disc = N_SLIP;
++ if(ioctl(fd, TIOCSETD, &disc) < 0){
++ printk("Failed to set slip line discipline - "
++ "errno = %d\n", errno);
++ return(-errno);
++ }
++
++ sencap = 0;
++ if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
++ printk("Failed to set slip encapsulation - "
++ "errno = %d\n", errno);
++ return(-errno);
++ }
++
++ return(0);
++}
++
++int os_set_owner(int fd, int pid)
++{
++ if(fcntl(fd, F_SETOWN, pid) < 0){
++ int save_errno = errno;
++
++ if(fcntl(fd, F_GETOWN, 0) != pid)
++ return(-save_errno);
++ }
++
++ return(0);
++}
++
++/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */
++int os_sigio_async(int master, int slave)
++{
++ int flags;
++
++ flags = fcntl(master, F_GETFL);
++ if(flags < 0) {
++ printk("fcntl F_GETFL failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
++ (fcntl(master, F_SETOWN, os_getpid()) < 0)){
++ printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
++ printk("fcntl F_SETFL failed, errno = %d\n", errno);
++ return(-errno);
++ }
++
++ return(0);
++}
++
++int os_mode_fd(int fd, int mode)
++{
++ int err;
++
++ do {
++ err = fchmod(fd, mode);
++ } while((err < 0) && (errno==EINTR)) ;
++
++ if(err < 0)
++ return(-errno);
++
++ return(0);
++}
++
++int os_file_type(char *file)
++{
++ struct uml_stat buf;
++ int err;
++
++ err = os_stat_file(file, &buf);
++ if(err < 0)
++ return(err);
++
++ if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
++ else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
++ else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
++ else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
++ else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
++ else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
++ else return(OS_TYPE_FILE);
++}
++
++int os_file_mode(char *file, struct openflags *mode_out)
++{
++ int err;
++
++ *mode_out = OPENFLAGS();
++
++ err = os_access(file, OS_ACC_W_OK);
++ if((err < 0) && (err != -EACCES))
++ return(err);
++
++ *mode_out = of_write(*mode_out);
++
++ err = os_access(file, OS_ACC_R_OK);
++ if((err < 0) && (err != -EACCES))
++ return(err);
++
++ *mode_out = of_read(*mode_out);
++
++ 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);
++
++ if(flags.cl && fcntl(fd, F_SETFD, 1)){
++ os_close_file(fd);
++ 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(-errno);
++
++ 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);
++}
++
++static int fault_buffer(void *start, int len,
++ int (*copy_proc)(void *addr, void *buf, int len))
++{
++ int page = getpagesize(), i;
++ char c;
++
++ for(i = 0; i < len; i += page){
++ if((*copy_proc)(start + i, &c, sizeof(c)))
++ return(-EFAULT);
++ }
++ if((len % page) != 0){
++ if((*copy_proc)(start + len - 1, &c, sizeof(c)))
++ return(-EFAULT);
++ }
++ return(0);
++}
++
++static int file_io(int fd, void *buf, int len,
++ int (*io_proc)(int fd, void *buf, int len),
++ int (*copy_user_proc)(void *addr, void *buf, int len))
++{
++ int n, err;
++
++ do {
++ n = (*io_proc)(fd, buf, len);
++ if((n < 0) && (errno == EFAULT)){
++ err = fault_buffer(buf, len, copy_user_proc);
++ if(err)
++ return(err);
++ n = (*io_proc)(fd, buf, len);
++ }
++ } while((n < 0) && (errno == EINTR));
++
++ if(n < 0)
++ return(-errno);
++ return(n);
++}
++
++int os_read_file(int fd, void *buf, int len)
++{
++ return(file_io(fd, buf, len, (int (*)(int, void *, int)) read,
++ copy_from_user_proc));
++}
++
++int os_write_file(int fd, const void *buf, int len)
++{
++ return(file_io(fd, (void *) buf, len,
++ (int (*)(int, void *, int)) write, copy_to_user_proc));
++}
++
++int os_file_size(char *file, long long *size_out)
++{
++ struct uml_stat buf;
++ int err;
++
++ err = os_stat_file(file, &buf);
++ if(err < 0){
++ printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++ return(err);
++ }
++
++ if(S_ISBLK(buf.ust_mode)){
++ int fd, blocks;
++
++ fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++ if(fd < 0){
++ printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
++ return(fd);
++ }
++ if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
++ printk("Couldn't get the block size of \"%s\", "
++ "errno = %d\n", file, errno);
++ err = -errno;
++ os_close_file(fd);
++ return(err);
++ }
++ *size_out = ((long long) blocks) * 512;
++ os_close_file(fd);
++ return(0);
++ }
++ *size_out = buf.ust_size;
++ return(0);
++}
++
++int os_file_modtime(char *file, unsigned long *modtime)
++{
++ struct uml_stat buf;
++ int err;
++
++ err = os_stat_file(file, &buf);
++ if(err < 0){
++ printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++ return(err);
++ }
++
++ *modtime = buf.ust_mtime;
++ return(0);
++}
++
++int os_get_exec_close(int fd, int* close_on_exec)
++{
++ int ret;
++
++ do {
++ ret = fcntl(fd, F_GETFD);
++ } while((ret < 0) && (errno == EINTR)) ;
++
++ if(ret < 0)
++ return(-errno);
++
++ *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
++ return(ret);
++}
++
++int os_set_exec_close(int fd, int close_on_exec)
++{
++ int flag, err;
++
++ if(close_on_exec) flag = FD_CLOEXEC;
++ else flag = 0;
++
++ do {
++ err = fcntl(fd, F_SETFD, flag);
++ } while((err < 0) && (errno == EINTR)) ;
++
++ if(err < 0)
++ return(-errno);
++ return(err);
++}
++
++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 < 0)
++ return(-errno);
++
++ if(!close_on_exec)
++ return(0);
++
++ err = os_set_exec_close(fds[0], 1);
++ if(err < 0)
++ goto error;
++
++ err = os_set_exec_close(fds[1], 1);
++ if(err < 0)
++ goto error;
++
++ return(0);
++
++ error:
++ printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
++ os_close_file(fds[1]);
++ os_close_file(fds[0]);
++ return(err);
++}
++
++int os_set_fd_async(int fd, int owner)
++{
++ /* XXX This should do F_GETFL first */
++ 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 new;
++
++ new = accept(fd, NULL, 0);
++ if(new < 0)
++ return(-errno);
++ return(new);
++}
++
++#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 < 0)
++ 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)
++ return(-errno);
++
++ 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 os_create_unix_socket(char *file, int len, int close_on_exec)
++{
++ 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);
++ }
++
++ if(close_on_exec) {
++ err = os_set_exec_close(sock, 1);
++ if(err < 0)
++ printk("create_unix_socket : close_on_exec failed, "
++ "err = %d", -err);
++ }
++
++ 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 at '%s' - bind failed, "
++ "errno = %d\n", file, errno);
++ return(-errno);
++ }
++
++ return(sock);
++}
++
++void os_flush_stdout(void)
++{
++ fflush(stdout);
++}
++
++int os_lock_file(int fd, int excl)
++{
++ int type = excl ? F_WRLCK : F_RDLCK;
++ struct flock lock = ((struct flock) { .l_type = type,
++ .l_whence = SEEK_SET,
++ .l_start = 0,
++ .l_len = 0 } );
++ int err, save;
++
++ err = fcntl(fd, F_SETLK, &lock);
++ if(!err)
++ goto out;
++
++ save = -errno;
++ err = fcntl(fd, F_GETLK, &lock);
++ if(err){
++ err = -errno;
++ goto out;
++ }
++
++ printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
++ err = save;
++ out:
++ return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/include/file.h um/arch/um/os-Linux/include/file.h
+--- orig/arch/um/os-Linux/include/file.h 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/include/file.h 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/Makefile um/arch/um/os-Linux/Makefile
+--- orig/arch/um/os-Linux/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/Makefile 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,17 @@
++#
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.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:
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/process.c um/arch/um/os-Linux/process.c
+--- orig/arch/um/os-Linux/process.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/process.c 2004-01-10 06:53:44.000000000 -0500
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/mman.h>
++#include <sys/wait.h>
++#include "os.h"
++#include "user.h"
++
++#define ARBITRARY_ADDR -1
++#define FAILURE_PID -1
++
++unsigned long os_process_pc(int pid)
++{
++ char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
++ unsigned long pc;
++ int fd, err;
++
++ 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', err = %d\n",
++ proc_stat, -fd);
++ return(ARBITRARY_ADDR);
++ }
++ err = os_read_file(fd, buf, sizeof(buf));
++ if(err < 0){
++ printk("os_process_pc - couldn't read '%s', err = %d\n",
++ proc_stat, -err);
++ os_close_file(fd);
++ return(ARBITRARY_ADDR);
++ }
++ os_close_file(fd);
++ pc = ARBITRARY_ADDR;
++ 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', err = %d\n", stat, -fd);
++ return(FAILURE_PID);
++ }
++
++ n = os_read_file(fd, data, sizeof(data));
++ os_close_file(fd);
++
++ if(n < 0){
++ printk("Couldn't read '%s', err = %d\n", stat, -n);
++ return(FAILURE_PID);
++ }
++
++ parent = FAILURE_PID;
++ /* 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, int reap_child)
++{
++ kill(pid, SIGKILL);
++ if(reap_child)
++ waitpid(pid, NULL, 0);
++
++}
++
++void os_usr1_process(int pid)
++{
++ kill(pid, SIGUSR1);
++}
++
++int os_getpid(void)
++{
++ return(getpid());
++}
++
++int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
++ int r, int w, int x)
++{
++ void *loc;
++ int prot;
++
++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
++ (x ? PROT_EXEC : 0);
++
++ loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
++ fd, off);
++ if(loc == MAP_FAILED)
++ return(-errno);
++ return(0);
++}
++
++int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
++{
++ int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
++ (x ? PROT_EXEC : 0));
++
++ if(mprotect(addr, len, prot) < 0)
++ return(-errno);
++ return(0);
++}
++
++int os_unmap_memory(void *addr, int len)
++{
++ int err;
++
++ err = munmap(addr, len);
++ if(err < 0)
++ return(-errno);
++ return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/os-Linux/tty.c um/arch/um/os-Linux/tty.c
+--- orig/arch/um/os-Linux/tty.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/os-Linux/tty.c 2003-10-21 03:26:07.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;
++
++ fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
++ if(fd < 0){
++ printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
++ return(fd);
++ }
++
++ info.fd = fd;
++ initial_thread_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/bugs.c um/arch/um/sys-i386/bugs.c
+--- orig/arch/um/sys-i386/bugs.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/bugs.c 2004-01-21 22:42:39.000000000 -0500
+@@ -0,0 +1,222 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/signal.h>
++#include <asm/ldt.h>
++#include "kern_util.h"
++#include "user.h"
++#include "sysdep/ptrace.h"
++#include "task.h"
++#include "os.h"
++
++#define MAXTOKEN 64
++
++/* Set during early boot */
++int host_has_cmov = 1;
++int host_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 = os_read_file(fd, ptr, sizeof(*ptr));
++ c = *ptr++;
++ if(n != sizeof(*ptr)){
++ if(n == 0) return(0);
++ printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
++ if(n < 0)
++ return(n);
++ else
++ return(-EIO);
++ }
++ } 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 find_cpuinfo_line(int fd, char *key, char *scratch, int len)
++{
++ int n;
++ char c;
++
++ scratch[len - 1] = '\0';
++ while(1){
++ c = token(fd, scratch, len - 1, ':');
++ if(c <= 0)
++ return(0);
++ else if(c != ':'){
++ printk("Failed to find ':' in /proc/cpuinfo\n");
++ return(0);
++ }
++
++ if(!strncmp(scratch, key, strlen(key)))
++ return(1);
++
++ do {
++ n = os_read_file(fd, &c, sizeof(c));
++ if(n != sizeof(c)){
++ printk("Failed to find newline in "
++ "/proc/cpuinfo, err = %d\n", -n);
++ return(0);
++ }
++ } while(c != '\n');
++ }
++ return(0);
++}
++
++int cpu_feature(char *what, char *buf, int len)
++{
++ int fd, ret = 0;
++
++ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++ if(fd < 0){
++ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++ return(0);
++ }
++
++ if(!find_cpuinfo_line(fd, what, buf, len)){
++ printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
++ goto out_close;
++ }
++
++ token(fd, buf, len, '\n');
++ ret = 1;
++
++ out_close:
++ os_close_file(fd);
++ return(ret);
++}
++
++static int check_cpu_flag(char *feature, int *have_it)
++{
++ char buf[MAXTOKEN], c;
++ int fd, len = sizeof(buf)/sizeof(buf[0]);
++
++ printk("Checking for host processor %s support...", feature);
++ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++ if(fd < 0){
++ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++ return(0);
++ }
++
++ *have_it = 0;
++ if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
++ goto out;
++
++ 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");
++ os_close_file(fd);
++ return(1);
++}
++
++#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
++ * for some people.
++ */
++static void disable_lcall(void)
++{
++ struct modify_ldt_ldt_s ldt;
++ int err;
++
++ bzero(&ldt, sizeof(ldt));
++ ldt.entry_number = 7;
++ ldt.base_addr = 0;
++ ldt.limit = 0;
++ err = modify_ldt(1, &ldt, sizeof(ldt));
++ if(err)
++ printk("Failed to disable lcall7 - errno = %d\n", errno);
++}
++#endif
++
++void arch_init_thread(void)
++{
++#if 0
++ disable_lcall();
++#endif
++}
++
++void arch_check_bugs(void)
++{
++ int have_it;
++
++ if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
++ printk("/proc/cpuinfo not available - skipping CPU capability "
++ "checks\n");
++ return;
++ }
++ if(check_cpu_flag("cmov", &have_it))
++ host_has_cmov = have_it;
++ if(check_cpu_flag("xmm", &have_it))
++ host_has_xmm = have_it;
++}
++
++int arch_handle_signal(int sig, union uml_pt_regs *regs)
++{
++ unsigned char tmp[2];
++
++ /* This is testing for a cmov (0x0f 0x4x) instruction causing a
++ * SIGILL in init.
++ */
++ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
++
++ if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
++ panic("SIGILL in init, could not read instructions!\n");
++ if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
++ return(0);
++
++ if(host_has_cmov == 0)
++ panic("SIGILL caused by cmov, which this processor doesn't "
++ "implement, boot a filesystem compiled for older "
++ "processors");
++ else if(host_has_cmov == 1)
++ panic("SIGILL caused by cmov, which this processor claims to "
++ "implement");
++ else if(host_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 host_has_cmov (%d)", host_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/checksum.S um/arch/um/sys-i386/checksum.S
+--- orig/arch/um/sys-i386/checksum.S 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/checksum.S 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,460 @@
++/*
++ * INET An implementation of the TCP/IP protocol suite for the LINUX
++ * operating system. INET is implemented using the BSD Socket
++ * interface as the means of communication with the user level.
++ *
++ * IP/TCP/UDP checksumming routines
++ *
++ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
++ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
++ * Tom May, <ftom@netcom.com>
++ * Pentium Pro/II routines:
++ * Alexander Kjeldaas <astor@guardian.no>
++ * Finn Arne Gangstad <finnag@guardian.no>
++ * Lots of code moved from tcp.c and ip.c; see those files
++ * for more names.
++ *
++ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
++ * handling.
++ * Andi Kleen, add zeroing on error
++ * converted to pure assembler
++ *
++ * 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/errno.h>
++
++/*
++ * computes a partial checksum, e.g. for TCP/UDP fragments
++ */
++
++/*
++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
++ */
++
++.text
++.align 4
++.globl arch_csum_partial
++
++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
++
++ /*
++ * Experiments with Ethernet and SLIP connections show that buff
++ * is aligned on either a 2-byte or 4-byte boundary. We get at
++ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
++ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
++ * alignment for the unrolled loop.
++ */
++arch_csum_partial:
++ pushl %esi
++ pushl %ebx
++ movl 20(%esp),%eax # Function arg: unsigned int sum
++ movl 16(%esp),%ecx # Function arg: int len
++ movl 12(%esp),%esi # Function arg: unsigned char *buff
++ testl $2, %esi # Check alignment.
++ jz 2f # Jump if alignment is ok.
++ subl $2, %ecx # Alignment uses up two bytes.
++ jae 1f # Jump if we had at least two bytes.
++ addl $2, %ecx # ecx was < 2. Deal with it.
++ jmp 4f
++1: movw (%esi), %bx
++ addl $2, %esi
++ addw %bx, %ax
++ adcl $0, %eax
++2:
++ movl %ecx, %edx
++ shrl $5, %ecx
++ jz 2f
++ testl %esi, %esi
++1: movl (%esi), %ebx
++ adcl %ebx, %eax
++ movl 4(%esi), %ebx
++ adcl %ebx, %eax
++ movl 8(%esi), %ebx
++ adcl %ebx, %eax
++ movl 12(%esi), %ebx
++ adcl %ebx, %eax
++ movl 16(%esi), %ebx
++ adcl %ebx, %eax
++ movl 20(%esi), %ebx
++ adcl %ebx, %eax
++ movl 24(%esi), %ebx
++ adcl %ebx, %eax
++ movl 28(%esi), %ebx
++ adcl %ebx, %eax
++ lea 32(%esi), %esi
++ dec %ecx
++ jne 1b
++ adcl $0, %eax
++2: movl %edx, %ecx
++ andl $0x1c, %edx
++ je 4f
++ shrl $2, %edx # This clears CF
++3: adcl (%esi), %eax
++ lea 4(%esi), %esi
++ dec %edx
++ jne 3b
++ adcl $0, %eax
++4: andl $3, %ecx
++ jz 7f
++ cmpl $2, %ecx
++ jb 5f
++ movw (%esi),%cx
++ leal 2(%esi),%esi
++ je 6f
++ shll $16,%ecx
++5: movb (%esi),%cl
++6: addl %ecx,%eax
++ adcl $0, %eax
++7:
++ popl %ebx
++ popl %esi
++ ret
++
++#else
++
++/* Version for PentiumII/PPro */
++
++arch_csum_partial:
++ pushl %esi
++ pushl %ebx
++ movl 20(%esp),%eax # Function arg: unsigned int sum
++ movl 16(%esp),%ecx # Function arg: int len
++ movl 12(%esp),%esi # Function arg: const unsigned char *buf
++
++ testl $2, %esi
++ jnz 30f
++10:
++ movl %ecx, %edx
++ movl %ecx, %ebx
++ andl $0x7c, %ebx
++ shrl $7, %ecx
++ addl %ebx,%esi
++ shrl $2, %ebx
++ negl %ebx
++ lea 45f(%ebx,%ebx,2), %ebx
++ testl %esi, %esi
++ jmp *%ebx
++
++ # Handle 2-byte-aligned regions
++20: addw (%esi), %ax
++ lea 2(%esi), %esi
++ adcl $0, %eax
++ jmp 10b
++
++30: subl $2, %ecx
++ ja 20b
++ je 32f
++ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
++ addl %ebx, %eax
++ adcl $0, %eax
++ jmp 80f
++32:
++ addw (%esi), %ax # csumming 2 bytes, 2-aligned
++ adcl $0, %eax
++ jmp 80f
++
++40:
++ addl -128(%esi), %eax
++ adcl -124(%esi), %eax
++ adcl -120(%esi), %eax
++ adcl -116(%esi), %eax
++ adcl -112(%esi), %eax
++ adcl -108(%esi), %eax
++ adcl -104(%esi), %eax
++ adcl -100(%esi), %eax
++ adcl -96(%esi), %eax
++ adcl -92(%esi), %eax
++ adcl -88(%esi), %eax
++ adcl -84(%esi), %eax
++ adcl -80(%esi), %eax
++ adcl -76(%esi), %eax
++ adcl -72(%esi), %eax
++ adcl -68(%esi), %eax
++ adcl -64(%esi), %eax
++ adcl -60(%esi), %eax
++ adcl -56(%esi), %eax
++ adcl -52(%esi), %eax
++ adcl -48(%esi), %eax
++ adcl -44(%esi), %eax
++ adcl -40(%esi), %eax
++ adcl -36(%esi), %eax
++ adcl -32(%esi), %eax
++ adcl -28(%esi), %eax
++ adcl -24(%esi), %eax
++ adcl -20(%esi), %eax
++ adcl -16(%esi), %eax
++ adcl -12(%esi), %eax
++ adcl -8(%esi), %eax
++ adcl -4(%esi), %eax
++45:
++ lea 128(%esi), %esi
++ adcl $0, %eax
++ dec %ecx
++ jge 40b
++ movl %edx, %ecx
++50: andl $3, %ecx
++ jz 80f
++
++ # Handle the last 1-3 bytes without jumping
++ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
++ movl $0xffffff,%ebx # by the shll and shrl instructions
++ shll $3,%ecx
++ shrl %cl,%ebx
++ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
++ addl %ebx,%eax
++ adcl $0,%eax
++80:
++ popl %ebx
++ popl %esi
++ ret
++
++#endif
++
++/*
++unsigned int csum_partial_copy_generic (const char *src, char *dst,
++ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
++ */
++
++/*
++ * Copy from ds while checksumming, otherwise like csum_partial
++ *
++ * The macros SRC and DST specify the type of access for the instruction.
++ * thus we can call a custom exception handler for all access types.
++ *
++ * FIXME: could someone double-check whether I haven't mixed up some SRC and
++ * DST definitions? It's damn hard to trigger all cases. I hope I got
++ * them all but there's no guarantee.
++ */
++
++#define SRC(y...) \
++ 9999: y; \
++ .section __ex_table, "a"; \
++ .long 9999b, 6001f ; \
++ .previous
++
++#define DST(y...) \
++ 9999: y; \
++ .section __ex_table, "a"; \
++ .long 9999b, 6002f ; \
++ .previous
++
++.align 4
++.globl csum_partial_copy_generic_i386
++
++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
++
++#define ARGBASE 16
++#define FP 12
++
++csum_partial_copy_generic_i386:
++ subl $4,%esp
++ pushl %edi
++ pushl %esi
++ pushl %ebx
++ movl ARGBASE+16(%esp),%eax # sum
++ movl ARGBASE+12(%esp),%ecx # len
++ movl ARGBASE+4(%esp),%esi # src
++ movl ARGBASE+8(%esp),%edi # dst
++
++ testl $2, %edi # Check alignment.
++ jz 2f # Jump if alignment is ok.
++ subl $2, %ecx # Alignment uses up two bytes.
++ jae 1f # Jump if we had at least two bytes.
++ addl $2, %ecx # ecx was < 2. Deal with it.
++ jmp 4f
++SRC(1: movw (%esi), %bx )
++ addl $2, %esi
++DST( movw %bx, (%edi) )
++ addl $2, %edi
++ addw %bx, %ax
++ adcl $0, %eax
++2:
++ movl %ecx, FP(%esp)
++ shrl $5, %ecx
++ jz 2f
++ testl %esi, %esi
++SRC(1: movl (%esi), %ebx )
++SRC( movl 4(%esi), %edx )
++ adcl %ebx, %eax
++DST( movl %ebx, (%edi) )
++ adcl %edx, %eax
++DST( movl %edx, 4(%edi) )
++
++SRC( movl 8(%esi), %ebx )
++SRC( movl 12(%esi), %edx )
++ adcl %ebx, %eax
++DST( movl %ebx, 8(%edi) )
++ adcl %edx, %eax
++DST( movl %edx, 12(%edi) )
++
++SRC( movl 16(%esi), %ebx )
++SRC( movl 20(%esi), %edx )
++ adcl %ebx, %eax
++DST( movl %ebx, 16(%edi) )
++ adcl %edx, %eax
++DST( movl %edx, 20(%edi) )
++
++SRC( movl 24(%esi), %ebx )
++SRC( movl 28(%esi), %edx )
++ adcl %ebx, %eax
++DST( movl %ebx, 24(%edi) )
++ adcl %edx, %eax
++DST( movl %edx, 28(%edi) )
++
++ lea 32(%esi), %esi
++ lea 32(%edi), %edi
++ dec %ecx
++ jne 1b
++ adcl $0, %eax
++2: movl FP(%esp), %edx
++ movl %edx, %ecx
++ andl $0x1c, %edx
++ je 4f
++ shrl $2, %edx # This clears CF
++SRC(3: movl (%esi), %ebx )
++ adcl %ebx, %eax
++DST( movl %ebx, (%edi) )
++ lea 4(%esi), %esi
++ lea 4(%edi), %edi
++ dec %edx
++ jne 3b
++ adcl $0, %eax
++4: andl $3, %ecx
++ jz 7f
++ cmpl $2, %ecx
++ jb 5f
++SRC( movw (%esi), %cx )
++ leal 2(%esi), %esi
++DST( movw %cx, (%edi) )
++ leal 2(%edi), %edi
++ je 6f
++ shll $16,%ecx
++SRC(5: movb (%esi), %cl )
++DST( movb %cl, (%edi) )
++6: addl %ecx, %eax
++ adcl $0, %eax
++7:
++5000:
++
++# Exception handler:
++.section .fixup, "ax"
++
++6001:
++ movl ARGBASE+20(%esp), %ebx # src_err_ptr
++ movl $-EFAULT, (%ebx)
++
++ # zero the complete destination - computing the rest
++ # is too much work
++ movl ARGBASE+8(%esp), %edi # dst
++ movl ARGBASE+12(%esp), %ecx # len
++ xorl %eax,%eax
++ rep ; stosb
++
++ jmp 5000b
++
++6002:
++ movl ARGBASE+24(%esp), %ebx # dst_err_ptr
++ movl $-EFAULT,(%ebx)
++ jmp 5000b
++
++.previous
++
++ popl %ebx
++ popl %esi
++ popl %edi
++ popl %ecx # equivalent to addl $4,%esp
++ ret
++
++#else
++
++/* Version for PentiumII/PPro */
++
++#define ROUND1(x) \
++ SRC(movl x(%esi), %ebx ) ; \
++ addl %ebx, %eax ; \
++ DST(movl %ebx, x(%edi) ) ;
++
++#define ROUND(x) \
++ SRC(movl x(%esi), %ebx ) ; \
++ adcl %ebx, %eax ; \
++ DST(movl %ebx, x(%edi) ) ;
++
++#define ARGBASE 12
++
++csum_partial_copy_generic_i386:
++ pushl %ebx
++ pushl %edi
++ pushl %esi
++ movl ARGBASE+4(%esp),%esi #src
++ movl ARGBASE+8(%esp),%edi #dst
++ movl ARGBASE+12(%esp),%ecx #len
++ movl ARGBASE+16(%esp),%eax #sum
++# movl %ecx, %edx
++ movl %ecx, %ebx
++ movl %esi, %edx
++ shrl $6, %ecx
++ andl $0x3c, %ebx
++ negl %ebx
++ subl %ebx, %esi
++ subl %ebx, %edi
++ lea -1(%esi),%edx
++ andl $-32,%edx
++ lea 3f(%ebx,%ebx), %ebx
++ testl %esi, %esi
++ jmp *%ebx
++1: addl $64,%esi
++ addl $64,%edi
++ SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
++ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
++ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
++ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
++ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
++3: adcl $0,%eax
++ addl $64, %edx
++ dec %ecx
++ jge 1b
++4: movl ARGBASE+12(%esp),%edx #len
++ andl $3, %edx
++ jz 7f
++ cmpl $2, %edx
++ jb 5f
++SRC( movw (%esi), %dx )
++ leal 2(%esi), %esi
++DST( movw %dx, (%edi) )
++ leal 2(%edi), %edi
++ je 6f
++ shll $16,%edx
++5:
++SRC( movb (%esi), %dl )
++DST( movb %dl, (%edi) )
++6: addl %edx, %eax
++ adcl $0, %eax
++7:
++.section .fixup, "ax"
++6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
++ movl $-EFAULT, (%ebx)
++ # zero the complete destination (computing the rest is too much work)
++ movl ARGBASE+8(%esp),%edi # dst
++ movl ARGBASE+12(%esp),%ecx # len
++ xorl %eax,%eax
++ rep; stosb
++ jmp 7b
++6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
++ movl $-EFAULT, (%ebx)
++ jmp 7b
++.previous
++
++ popl %esi
++ popl %edi
++ popl %ebx
++ ret
++
++#undef ROUND
++#undef ROUND1
++
++#endif
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/fault.c um/arch/um/sys-i386/fault.c
+--- orig/arch/um/sys-i386/fault.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/fault.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ksyms.c um/arch/um/sys-i386/ksyms.c
+--- orig/arch/um/sys-i386/ksyms.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/ksyms.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,17 @@
++#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_from);
++EXPORT_SYMBOL(csum_partial_copy_to);
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ldt.c um/arch/um/sys-i386/ldt.c
+--- orig/arch/um/sys-i386/ldt.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/ldt.c 2004-01-19 04:01:11.000000000 -0500
+@@ -0,0 +1,94 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/slab.h"
++#include "asm/uaccess.h"
++#include "asm/ptrace.h"
++#include "choose-mode.h"
++#include "kern.h"
++
++#ifdef CONFIG_MODE_TT
++extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
++
++/* XXX this needs copy_to_user and copy_from_user */
++
++int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
++{
++ if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
++ return(modify_ldt(func, ptr, bytecount));
++}
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++extern int userspace_pid;
++
++int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
++{
++ struct ptrace_ldt ldt;
++ void *buf;
++ int res, n;
++
++ buf = kmalloc(bytecount, GFP_KERNEL);
++ if(buf == NULL)
++ return(-ENOMEM);
++
++ res = 0;
++
++ switch(func){
++ case 1:
++ case 0x11:
++ res = copy_from_user(buf, ptr, bytecount);
++ break;
++ }
++
++ if(res != 0){
++ res = -EFAULT;
++ goto out;
++ }
++
++ ldt = ((struct ptrace_ldt) { .func = func,
++ .ptr = buf,
++ .bytecount = bytecount });
++ res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
++ if(res < 0)
++ goto out;
++
++ switch(func){
++ case 0:
++ case 2:
++ n = res;
++ res = copy_to_user(ptr, buf, n);
++ if(res != 0)
++ res = -EFAULT;
++ else
++ res = n;
++ break;
++ }
++
++ out:
++ kfree(buf);
++ return(res);
++}
++#endif
++
++int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++{
++ return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
++ ptr, bytecount));
++}
++
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/Makefile um/arch/um/sys-i386/Makefile
+--- orig/arch/um/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/Makefile 2003-11-09 11:55:24.000000000 -0500
+@@ -0,0 +1,46 @@
++#
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.o
++
++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o ptrace.o \
++ ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o time.o
++export-objs = ksyms.o
++
++USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o
++
++SYMLINKS = semaphore.c extable.c
++
++semaphore.c-dir = kernel
++extable.c-dir = mm
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++define make_link
++ -rm -f $1
++ ln -sf $(TOPDIR)/arch/i386/$($1-dir)/$1 $1
++endef
++
++$(SYMLINKS):
++ $(call make_link,$@)
++
++clean:
++ $(MAKE) -C util clean
++ rm -f $(SYMLINKS)
++
++fastdep:
++
++dep:
++
++archmrproper:
++
++archclean:
++
++archdep:
++
++modules:
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ptrace.c um/arch/um/sys-i386/ptrace.c
+--- orig/arch/um/sys-i386/ptrace.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/ptrace.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,365 @@
++/*
++ * 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;
++}
++
++/*
++ * FXSR floating point environment conversions.
++ */
++
++#ifdef CONFIG_MODE_TT
++static inline int convert_fxsr_to_user_tt(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;
++}
++#endif
++
++static inline int convert_fxsr_to_user(struct _fpstate *buf,
++ struct pt_regs *regs)
++{
++ return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
++}
++
++#ifdef CONFIG_MODE_TT
++static inline int convert_fxsr_from_user_tt(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;
++}
++#endif
++
++static inline int convert_fxsr_from_user(struct pt_regs *regs,
++ struct _fpstate *buf)
++{
++ return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 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);
++}
++
++#ifdef CONFIG_MODE_TT
++int get_fpxregs_tt(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;
++}
++#endif
++
++int get_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++ return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
++}
++
++#ifdef CONFIG_MODE_TT
++int set_fpxregs_tt(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;
++}
++#endif
++
++int set_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++ return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 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
++
++#ifdef CONFIG_MODE_TT
++static inline void copy_fpu_fxsave_tt(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) );
++ }
++}
++#endif
++
++static inline void copy_fpu_fxsave(struct pt_regs *regs,
++ struct user_i387_struct *buf)
++{
++ (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
++}
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ptrace_user.c um/arch/um/sys-i386/ptrace_user.c
+--- orig/arch/um/sys-i386/ptrace_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/ptrace_user.c 2003-12-17 01:33:17.000000000 -0500
+@@ -0,0 +1,117 @@
++/*
++ * 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_POKEUSER, pid, &dummy->u_debugreg[i],
++ regs[i]) < 0)
++ printk("write_debugregs - ptrace failed on "
++ "register %d, 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_PEEKUSER, pid,
++ &dummy->u_debugreg[i], 0);
++ }
++}
++
++/* Accessed only by the tracing thread */
++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();
++ initial_thread_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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/sigcontext.c um/arch/um/sys-i386/sigcontext.c
+--- orig/arch/um/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/sigcontext.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,80 @@
++/*
++ * 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);
++}
++
++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.common.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/syscalls.c um/arch/um/sys-i386/syscalls.c
+--- orig/arch/um/sys-i386/syscalls.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/syscalls.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/sysrq.c um/arch/um/sys-i386/sysrq.c
+--- orig/arch/um/sys-i386/sysrq.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/sysrq.c 2003-10-21 03:26:07.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);
++}
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/time.c um/arch/um/sys-i386/time.c
+--- orig/arch/um/sys-i386/time.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/time.c 2003-11-10 01:46:49.000000000 -0500
+@@ -0,0 +1,24 @@
++/*
++ * sys-i386/time.c
++ * Created 25.9.2002 Sapan Bhatia
++ *
++ */
++
++unsigned long long time_stamp(void)
++{
++ unsigned long low, high;
++
++ asm("rdtsc" : "=a" (low), "=d" (high));
++ return((((unsigned long long) high) << 32) + low);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/Makefile um/arch/um/sys-i386/util/Makefile
+--- orig/arch/um/sys-i386/util/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/util/Makefile 2003-11-08 08:26:40.000000000 -0500
+@@ -0,0 +1,28 @@
++EXE = mk_sc mk_thread
++
++include $(TOPDIR)/Rules.make
++
++all : $(EXE)
++
++mk_sc : mk_sc.o
++ $(HOSTCC) -o mk_sc mk_sc.o
++
++mk_sc.o : mk_sc.c
++ $(HOSTCC) -c $<
++
++mk_thread : mk_thread_user.o mk_thread_kern.o
++ $(HOSTCC) -o mk_thread mk_thread_user.o mk_thread_kern.o
++
++mk_thread_user.o : mk_thread_user.c
++ $(HOSTCC) -c $<
++
++mk_thread_kern.o : mk_thread_kern.c
++ $(HOSTCC) $(CFLAGS) -c $<
++
++clean :
++ $(RM) $(EXE) *.o
++
++archmrproper : clean
++
++fastdep :
++
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_sc.c um/arch/um/sys-i386/util/mk_sc.c
+--- orig/arch/um/sys-i386/util/mk_sc.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/util/mk_sc.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,52 @@
++#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_OFFSET("SC_SIGMASK", oldmask);
++ 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);
++}
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_thread_kern.c um/arch/um/sys-i386/util/mk_thread_kern.c
+--- orig/arch/um/sys-i386/util/mk_thread_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/util/mk_thread_kern.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,22 @@
++#include "linux/config.h"
++#include "linux/stddef.h"
++#include "linux/sched.h"
++
++extern void print_head(void);
++extern void print_constant_ptr(char *name, int value);
++extern void print_constant(char *name, char *type, int value);
++extern void print_tail(void);
++
++#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
++
++int main(int argc, char **argv)
++{
++ print_head();
++ print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
++#ifdef CONFIG_MODE_TT
++ print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
++#endif
++ print_tail();
++ return(0);
++}
++
+diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_thread_user.c um/arch/um/sys-i386/util/mk_thread_user.c
+--- orig/arch/um/sys-i386/util/mk_thread_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-i386/util/mk_thread_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,30 @@
++#include <stdio.h>
++
++void print_head(void)
++{
++ printf("/*\n");
++ printf(" * Generated by mk_thread\n");
++ printf(" */\n");
++ printf("\n");
++ printf("#ifndef __UM_THREAD_H\n");
++ printf("#define __UM_THREAD_H\n");
++ printf("\n");
++}
++
++void print_constant_ptr(char *name, int value)
++{
++ printf("#define %s(task) ((unsigned long *) "
++ "&(((char *) (task))[%d]))\n", name, value);
++}
++
++void print_constant(char *name, char *type, int value)
++{
++ printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
++ value);
++}
++
++void print_tail(void)
++{
++ printf("\n");
++ printf("#endif\n");
++}
+diff -Naur -X ../exclude-files orig/arch/um/sys-ia64/Makefile um/arch/um/sys-ia64/Makefile
+--- orig/arch/um/sys-ia64/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ia64/Makefile 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/Makefile um/arch/um/sys-ppc/Makefile
+--- orig/arch/um/sys-ppc/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/Makefile 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/misc.S um/arch/um/sys-ppc/misc.S
+--- orig/arch/um/sys-ppc/misc.S 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/misc.S 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/miscthings.c um/arch/um/sys-ppc/miscthings.c
+--- orig/arch/um/sys-ppc/miscthings.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/miscthings.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,53 @@
++#include "linux/threads.h"
++#include "linux/stddef.h" // for NULL
++#include "linux/elf.h" // for AT_NULL
++
++/* The following function nicked from arch/ppc/kernel/process.c and
++ * adapted slightly */
++/*
++ * XXX ld.so expects the auxiliary table to start on
++ * a 16-byte boundary, so we have to find it and
++ * move it up. :-(
++ */
++void shove_aux_table(unsigned long sp)
++{
++ int argc;
++ char *p;
++ unsigned long e;
++ unsigned long aux_start, offset;
++
++ argc = *(int *)sp;
++ sp += sizeof(int) + (argc + 1) * sizeof(char *);
++ /* skip over the environment pointers */
++ do {
++ p = *(char **)sp;
++ sp += sizeof(char *);
++ } while (p != NULL);
++ aux_start = sp;
++ /* skip to the end of the auxiliary table */
++ do {
++ e = *(unsigned long *)sp;
++ sp += 2 * sizeof(unsigned long);
++ } while (e != AT_NULL);
++ offset = ((aux_start + 15) & ~15) - aux_start;
++ if (offset != 0) {
++ do {
++ sp -= sizeof(unsigned long);
++ e = *(unsigned long *)sp;
++ *(unsigned long *)(sp + offset) = e;
++ } while (sp > aux_start);
++ }
++}
++/* END stuff taken from arch/ppc/kernel/process.c */
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/ptrace.c um/arch/um/sys-ppc/ptrace.c
+--- orig/arch/um/sys-ppc/ptrace.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/ptrace.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/ptrace_user.c um/arch/um/sys-ppc/ptrace_user.c
+--- orig/arch/um/sys-ppc/ptrace_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/ptrace_user.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/sigcontext.c um/arch/um/sys-ppc/sigcontext.c
+--- orig/arch/um/sys-ppc/sigcontext.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/sigcontext.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/sysrq.c um/arch/um/sys-ppc/sysrq.c
+--- orig/arch/um/sys-ppc/sysrq.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/sys-ppc/sysrq.c 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/arch/um/util/Makefile um/arch/um/util/Makefile
+--- orig/arch/um/util/Makefile 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/util/Makefile 2003-11-08 02:51:30.000000000 -0500
+@@ -0,0 +1,26 @@
++ALL = mk_task mk_constants
++
++all : $(ALL)
++
++mk_task : mk_task_user.o mk_task_kern.o
++ $(HOSTCC) -o mk_task mk_task_user.o mk_task_kern.o
++
++mk_task_user.o : mk_task_user.c
++ $(HOSTCC) -c $<
++
++mk_task_kern.o : mk_task_kern.c
++ $(HOSTCC) $(CFLAGS) -c $<
++
++mk_constants : mk_constants_user.o mk_constants_kern.o
++ $(HOSTCC) -o mk_constants mk_constants_user.o mk_constants_kern.o
++
++mk_constants_user.o : mk_constants_user.c
++ $(HOSTCC) -c $<
++
++mk_constants_kern.o : mk_constants_kern.c
++ $(HOSTCC) $(CFLAGS) -c $<
++
++clean :
++ $(RM) $(ALL) *.o *~
++
++archmrproper : clean
+diff -Naur -X ../exclude-files orig/arch/um/util/mk_constants_kern.c um/arch/um/util/mk_constants_kern.c
+--- orig/arch/um/util/mk_constants_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/util/mk_constants_kern.c 2004-01-10 06:54:51.000000000 -0500
+@@ -0,0 +1,25 @@
++#include "linux/kernel.h"
++#include "linux/stringify.h"
++#include "asm/page.h"
++
++extern void print_head(void);
++extern void print_constant_str(char *name, char *value);
++extern void print_constant_int(char *name, int value);
++extern void print_tail(void);
++
++int main(int argc, char **argv)
++{
++ print_head();
++ print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
++
++ print_constant_str("UM_KERN_EMERG", KERN_EMERG);
++ print_constant_str("UM_KERN_ALERT", KERN_ALERT);
++ print_constant_str("UM_KERN_CRIT", KERN_CRIT);
++ print_constant_str("UM_KERN_ERR", KERN_ERR);
++ print_constant_str("UM_KERN_WARNING", KERN_WARNING);
++ print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
++ print_constant_str("UM_KERN_INFO", KERN_INFO);
++ print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
++ print_tail();
++ return(0);
++}
+diff -Naur -X ../exclude-files orig/arch/um/util/mk_constants_user.c um/arch/um/util/mk_constants_user.c
+--- orig/arch/um/util/mk_constants_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/util/mk_constants_user.c 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,28 @@
++#include <stdio.h>
++
++void print_head(void)
++{
++ printf("/*\n");
++ printf(" * Generated by mk_constants\n");
++ printf(" */\n");
++ printf("\n");
++ printf("#ifndef __UM_CONSTANTS_H\n");
++ printf("#define __UM_CONSTANTS_H\n");
++ printf("\n");
++}
++
++void print_constant_str(char *name, char *value)
++{
++ printf("#define %s \"%s\"\n", name, value);
++}
++
++void print_constant_int(char *name, int value)
++{
++ printf("#define %s %d\n", name, value);
++}
++
++void print_tail(void)
++{
++ printf("\n");
++ printf("#endif\n");
++}
+diff -Naur -X ../exclude-files orig/arch/um/util/mk_task_kern.c um/arch/um/util/mk_task_kern.c
+--- orig/arch/um/util/mk_task_kern.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/util/mk_task_kern.c 2003-10-21 03:26:07.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", "union uml_pt_regs",
++ offsetof(struct task_struct, thread.regs));
++ print("TASK_PID", "int", offsetof(struct task_struct, pid));
++ print_tail();
++ return(0);
++}
+diff -Naur -X ../exclude-files orig/arch/um/util/mk_task_user.c um/arch/um/util/mk_task_user.c
+--- orig/arch/um/util/mk_task_user.c 1969-12-31 19:00:00.000000000 -0500
++++ um/arch/um/util/mk_task_user.c 2003-10-21 03:26:07.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");
++}
+diff -Naur -X ../exclude-files orig/CREDITS um/CREDITS
+--- orig/CREDITS 2003-12-16 22:16:23.000000000 -0500
++++ um/CREDITS 2003-12-16 22:17:22.000000000 -0500
+@@ -434,6 +434,7 @@
+ E: lars@nocrew.org
+ W: http://lars.nocrew.org/
+ D: dsp56k device driver
++D: ptrace proxy in user mode kernel port
+ S: Kopmansg 2
+ S: 411 13 Goteborg
+ S: Sweden
+@@ -719,7 +720,7 @@
+ E: jdike@karaya.com
+ W: http://user-mode-linux.sourceforge.net
+ D: User mode kernel port
+-S: RR1 Box 67C
++S: 375 Tubbs Hill Rd
+ S: Deering NH 03244
+ S: USA
+
+diff -Naur -X ../exclude-files orig/Documentation/Configure.help um/Documentation/Configure.help
+--- orig/Documentation/Configure.help 2003-12-16 22:16:23.000000000 -0500
++++ um/Documentation/Configure.help 2003-12-16 22:17:22.000000000 -0500
+@@ -15821,6 +15821,63 @@
+ The module will be called speedtch.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
++Support for /proc/mm
++CONFIG_PROC_MM
++ Enables support for address space separation through /proc/mm.
++ A host kernel needs to have this enabled in order for UML to
++ run in skas mode. UML kernels do not need to have this option
++ unless they will host sub-UMLs.
++
++ If you don't know what this does just say Y.
++
++Separate Kernel Address Space support
++CONFIG_MODE_SKAS
++ This option controls whether skas (separate kernel address space)
++ support is compiled in. If you have applied the skas patch to the
++ host and enabled support for /proc/mm in the host kernel, then you
++ certainly want to say Y here (and consider saying N to
++ CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this
++ option will shrink the UML binary slightly.
++
++Tracing thread support
++CONFIG_MODE_TT
++ This option controls whether tracing thread support is compiled
++ into UML. Normally, this should be set to Y. If you intend to
++ use only skas mode (and the host has the skas patch applied to it),
++ then it is OK to say N here.
++
++Force a static link
++CONFIG_STATIC_LINK
++ If CONFIG_MODE_TT is disabled, then this option gives you the ability
++ to force a static link of UML. Normally, if only skas mode is built
++ in to UML, it will be linked as a shared binary. This is inconvenient
++ for use in a chroot jail. So, if you intend to run UML inside a
++ chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
++ here.
++
++2G/2G host address space split
++CONFIG_HOST_2G_2G
++ Most Linux machines are configured so that the kernel occupies the
++ upper 1G of the 4G address space and processes use the lower 3G.
++ However, some machine are configured with a 2G/2G split, with the
++ kernel occupying the upper 2G and processes using the lower 2G.
++
++ To allow UML to run on a such host you have to say Y here. N should be
++ a safe choice most of the time.
++
++Kernel stack size order
++CONFIG_KERNEL_STACK_ORDER
++ This option determines the size of UML kernel stacks. They will
++ be 1 << order pages. The default is OK unless you're running Valgrind
++ on UML, in which case, set this to 3.
++
++UML ubd block driver
++CONFIG_BLK_DEV_UBD
++ The User-Mode Linux port includes a driver called UBD which will let
++ you access arbitrary files on the host computer as block devices.
++ Unless you know that you do not need such virtual block devices say
++ Y here.
++
+ CONFIG_USB_GADGET
+ USB is a master/slave protocol, organized with one master
+ host (such as a PC) controlling up to 127 peripheral devices.
+@@ -15905,17 +15962,15 @@
+
+ Always do synchronous disk IO for UBD
+ CONFIG_BLK_DEV_UBD_SYNC
+- The User-Mode Linux port includes a driver called UBD which will let
+- you access arbitrary files on the host computer as block devices.
+- Writes to such a block device are not immediately written to the
+- host's disk; this may cause problems if, for example, the User-Mode
+- Linux 'Virtual Machine' uses a journalling file system and the host
+- computer crashes.
++ Writes to the virtual block device are not immediately written to the host's
++ disk; this may cause problems if, for example, the User-Mode Linux
++ 'Virtual Machine' uses a journalling filesystem and the host computer
++ crashes.
+
+ Synchronous operation (i.e. always writing data to the host's disk
+ immediately) is configurable on a per-UBD basis by using a special
+ kernel command line option. Alternatively, you can say Y here to
+- turn on synchronous operation by default for all block.
++ turn on synchronous operation by default for all block devices.
+
+ If you're running a journalling file system (like reiserfs, for
+ example) in your virtual machine, you will want to say Y here. If
+@@ -15927,6 +15982,7 @@
+ CONFIG_PT_PROXY
+ This option enables a debugging interface which allows gdb to debug
+ the kernel without needing to actually attach to kernel threads.
++ CONFIG_XTERM_CHAN must be enabled in order to enable CONFIG_PT_PROXY.
+ If you want to do kernel debugging, say Y here; otherwise say N.
+
+ Management console
+@@ -15959,7 +16015,7 @@
+ This option allows developers to retrieve coverage data from a UML
+ session.
+
+- See <http://user-mode-linux.sourceforge.net/gcov.html> for more
++ See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+ details.
+
+ If you're involved in UML kernel development and want to use gcov,
+@@ -15996,6 +16052,19 @@
+ If you'd like to be able to work with files stored on the host,
+ say Y or M here; otherwise say N.
+
++HoneyPot ProcFS
++CONFIG_HPPFS
++ hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
++ entries to be overridden, removed, or fabricated from the host.
++ Its purpose is to allow a UML to appear to be a physical machine
++ by removing or changing anything in /proc which gives away the
++ identity of a UML.
++
++ See <http://user-mode-linux.sf.net/hppfs.html> for more information.
++
++ You only need this if you are setting up a UML honeypot. Otherwise,
++ it is safe to say 'N' here.
++
+ Example IO Memory driver
+ CONFIG_MMAPPER
+ The User-Mode Linux port can provide support for IO Memory
+@@ -16011,6 +16080,21 @@
+ If you'd like to be able to provide a simulated IO port space for
+ User-Mode Linux processes, say Y. If unsure, say N.
+
++Anonymous Memory support
++CONFIG_DEV_ANON
++ Don't ask. Just say Y.
++
++Support for software watchdog inside UML
++CONFIG_UML_WATCHDOG
++ Support for a virtual hardware watchdog. It's safe to say N here.
++
++COW block device
++CONFIG_COW
++ This is a layered driver which sits above two other block devices.
++ One is read-only, and the other is a read-write layer which stores
++ all changes. This provides the illusion that the read-only layer
++ can be mounted read-write and changed.
++
+ Virtual Serial Line
+ CONFIG_SSL
+ The User-Mode Linux environment allows you to create virtual serial
+@@ -16121,26 +16205,197 @@
+
+ SLIP transport
+ CONFIG_UML_NET_SLIP
+- The Slip User-Mode Linux network transport allows a running UML to
++ The slip User-Mode Linux network transport allows a running UML to
+ network with its host over a point-to-point link. Unlike Ethertap,
+ which can carry any Ethernet frame (and hence even non-IP packets),
+- the Slip transport can only carry IP packets.
++ the slip transport can only carry IP packets.
+
+- To use this, your host must support Slip devices.
++ To use this, your host must support slip devices.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html>. That site
+- has examples of the UML command line to use to enable Slip
++ has examples of the UML command line to use to enable slip
+ networking, and details of a few quirks with it.
+
+- The Ethertap Transport is preferred over Slip because of its
+- limitation. If you prefer Slip, however, say Y here. Otherwise
++ The Ethertap Transport is preferred over slip because of its
++ limitations. If you prefer slip, however, say Y here. Otherwise
+ choose the Multicast transport (to network multiple UMLs on
+ multiple hosts), Ethertap (to network with the host and the
+ outside world), and/or the Daemon transport (to network multiple
+ UMLs on a single host). You may choose more than one without
+ conflict. If you don't need UML networking, say N.
+
++SLiRP transport
++CONFIG_UML_NET_SLIRP
++ The SLiRP User-Mode Linux network transport allows a running UML
++ to network by invoking a program that can handle SLIP encapsulated
++ packets. This is commonly (but not limited to) the application
++ known as SLiRP, a program that can re-socket IP packets back onto
++ the host on which it is run. Only IP packets are supported,
++ unlike other network transports that can handle all Ethernet
++ frames. In general, slirp allows the UML the same IP connectivity
++ to the outside world that the host user is permitted, and unlike
++ other transports, SLiRP works without the need of root level
++ privleges, setuid binaries, or SLIP devices on the host. This
++ also means not every type of connection is possible, but most
++ situations can be accomodated with carefully crafted slirp
++ commands that can be passed along as part of the network device's
++ setup string. The effect of this transport on the UML is similar
++ that of a host behind a firewall that masquerades all network
++ connections passing through it (but is less secure).
++
++ To use this you should first have slirp compiled somewhere
++ accessible on the host, and have read its documentation. If you
++ don't need UML networking, say N.
++
++ Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
++
++pcap transport
++CONFIG_UML_NET_PCAP
++ The pcap transport makes a pcap packet stream on the host look
++ like an ethernet device inside UML. This is useful for making
++ UML act as a network monitor for the host. You must have libcap
++ installed in order to build the pcap transport into UML.
++
++ For more information, see
++ <http://user-mode-linux.sourceforge.net/networking.html> That site
++ has examples of the UML command line to use to enable this option.
++
++ If you intend to use UML as a network monitor for the host, say
++ Y here. Otherwise, say N.
++
++Default main console channel initialization
++CONFIG_CON_ZERO_CHAN
++ This is the string describing the channel to which the main console
++ will be attached by default. This value can be overridden from the
++ command line. The default value is "fd:0,fd:1", which attaches the
++ main console to stdin and stdout.
++ It is safe to leave this unchanged.
++
++Default console channel initialization
++CONFIG_CON_CHAN
++ This is the string describing the channel to which all consoles
++ except the main console will be attached by default. This value can
++ be overridden from the command line. The default value is "xterm",
++ which brings them up in xterms.
++ It is safe to leave this unchanged, although you may wish to change
++ this if you expect the UML that you build to be run in environments
++ which don't have X or xterm available.
++
++Default serial line channel initialization
++CONFIG_SSL_CHAN
++ This is the string describing the channel to which the serial lines
++ will be attached by default. This value can be overridden from the
++ command line. The default value is "pty", which attaches them to
++ traditional pseudo-terminals.
++ It is safe to leave this unchanged, although you may wish to change
++ this if you expect the UML that you build to be run in environments
++ which don't have a set of /dev/pty* devices.
++
++Nesting level
++CONFIG_NEST_LEVEL
++ This is set to the number of layers of UMLs that this UML will be run
++ in. Normally, this is zero, meaning that it will run directly on the
++ host. Setting it to one will build a UML that can run inside a UML
++ that is running on the host. Generally, if you intend this UML to run
++ inside another UML, set CONFIG_NEST_LEVEL to one more than the host UML.
++ Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to
++ greater than one, then the guest UML should have its CONFIG_NEST_LEVEL
++ set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS.
++ Only change this if you are running nested UMLs.
++
++Kernel address space size (in .5G units)
++CONFIG_KERNEL_HALF_GIGS
++ This determines the amount of address space that UML will allocate for
++ its own, measured in half Gigabyte units. The default is 1.
++ Change this only if you need to boot UML with an unusually large amount
++ of physical memory.
++
++UML sound support
++CONFIG_UML_SOUND
++ This option enables UML sound support. If enabled, it will pull in
++ soundcore and the UML hostaudio relay, which acts as a intermediary
++ between the host's dsp and mixer devices and the UML sound system.
++ It is safe to say 'Y' here.
++
++UML SMP support
++CONFIG_UML_SMP
++ This option enables UML SMP support. UML implements virtual SMP by
++ allowing as many processes to run simultaneously on the host as
++ there are virtual processors configured. Obviously, if the host is
++ a uniprocessor, those processes will timeshare, but, inside UML,
++ will appear to be running simultaneously. If the host is a
++ multiprocessor, then UML processes may run simultaneously, depending
++ on the host scheduler.
++ CONFIG_SMP will be set to whatever this option is set to.
++ It is safe to leave this unchanged.
++
++file descriptor channel support
++CONFIG_FD_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to already set up file descriptors. Generally, the main
++ console is attached to file descriptors 0 and 1 (stdin and stdout),
++ so it would be wise to leave this enabled unless you intend to
++ attach it to some other host device.
++
++null device channel support
++CONFIG_NULL_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to a device similar to /dev/null. Data written to it disappears
++ and there is never any data to be read.
++
++port channel support
++CONFIG_PORT_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to host portals. They may be accessed with 'telnet <host>
++ <port number>'. Any number of consoles and serial lines may be
++ attached to a single portal, although what UML device you get when
++ you telnet to that portal will be unpredictable.
++ It is safe to say 'Y' here.
++
++pty channel support
++CONFIG_PTY_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to host pseudo-terminals. Access to both traditional
++ pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
++ with this option. The assignment of UML devices to host devices
++ will be announced in the kernel message log.
++ It is safe to say 'Y' here.
++
++tty channel support
++CONFIG_TTY_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to host terminals. Access to both virtual consoles
++ (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
++ /dev/pts/*) are controlled by this option.
++ It is safe to say 'Y' here.
++
++xterm channel support
++CONFIG_XTERM_CHAN
++ This option enables support for attaching UML consoles and serial
++ lines to xterms. Each UML device so assigned will be brought up in
++ its own xterm.
++ If you disable this option, then CONFIG_PT_PROXY will be disabled as
++ well, since UML's gdb currently requires an xterm.
++ It is safe to say 'Y' here.
++
++tty logging
++CONFIG_TTY_LOG
++ This option enables logging of all data going through pseudo-terminals
++ to the host. This is primarily useful for honeypots, where you want
++ secure keystroke logging that can't be detected or disabled by root.
++ Say 'N' unless you are setting up a UML honeypot or otherwise know that
++ you want this option.
++
++UML real-time clock support
++CONFIG_UML_REAL_TIME_CLOCK
++ This option ties the UML clock to the host clock, so that time passes at
++ the same rate as on the host, regardless of how much CPU time the UML is
++ getting. This should normally be enabled. The exception would be if you're
++ debugging UML. In this case, time spent staring at the debugger with UML
++ stopped will cause lots of timer ticks to be backed up, and UML will spent
++ lots of time calling the timer when it is finally continued.
++
+ Microtek USB scanner support
+ CONFIG_USB_MICROTEK
+ Say Y here if you want support for the Microtek X6USB and
+diff -Naur -X ../exclude-files orig/drivers/char/Makefile um/drivers/char/Makefile
+--- orig/drivers/char/Makefile 2003-12-16 22:16:26.000000000 -0500
++++ um/drivers/char/Makefile 2003-12-16 22:17:25.000000000 -0500
+@@ -109,6 +109,12 @@
+ endif
+ endif
+
++ifeq ($(ARCH),um)
++ KEYMAP =
++ KEYBD =
++ CONSOLE =
++endif
++
+ ifeq ($(ARCH),sh)
+ KEYMAP =
+ KEYBD =
+diff -Naur -X ../exclude-files orig/drivers/char/mem.c um/drivers/char/mem.c
+--- orig/drivers/char/mem.c 2003-12-16 22:16:27.000000000 -0500
++++ um/drivers/char/mem.c 2004-01-05 11:23:32.000000000 -0500
+@@ -220,7 +220,8 @@
+ ssize_t read = 0;
+ ssize_t virtr = 0;
+ char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
+-
++
++ p = (unsigned long) __va(p);
+ if (p < (unsigned long) high_memory) {
+ read = count;
+ if (count > (unsigned long) high_memory - p)
+@@ -269,7 +270,7 @@
+ }
+ free_page((unsigned long)kbuf);
+ }
+- *ppos = p;
++ *ppos = __pa((void *) p);
+ return virtr + read;
+ }
+
+@@ -664,6 +665,8 @@
+ write: write_full,
+ };
+
++extern struct file_operations anon_file_operations;
++
+ static int memory_open(struct inode * inode, struct file * filp)
+ {
+ switch (MINOR(inode->i_rdev)) {
+@@ -693,6 +696,9 @@
+ case 9:
+ filp->f_op = &urandom_fops;
+ break;
++ case 10:
++ filp->f_op = &anon_file_operations;
++ break;
+ default:
+ return -ENXIO;
+ }
+@@ -719,7 +725,8 @@
+ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
+ {7, "full", S_IRUGO | S_IWUGO, &full_fops},
+ {8, "random", S_IRUGO | S_IWUSR, &random_fops},
+- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}
++ {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
++ {10, "anon", S_IRUGO | S_IWUSR, &anon_file_operations},
+ };
+ int i;
+
+diff -Naur -X ../exclude-files orig/drivers/char/tty_io.c um/drivers/char/tty_io.c
+--- orig/drivers/char/tty_io.c 2003-12-16 22:16:27.000000000 -0500
++++ um/drivers/char/tty_io.c 2003-12-16 22:17:25.000000000 -0500
+@@ -649,6 +649,23 @@
+ wake_up_interruptible(&tty->write_wait);
+ }
+
++#ifdef CONFIG_TTY_LOG
++
++int (*open_log)(void *, void *) = NULL;
++int (*write_log)(int, const char *, int, void *, int) = NULL;
++void (*close_log)(int, void *) = NULL;
++
++void register_tty_logger(int (*opener)(void *, void *),
++ int (*writer)(int, const char *, int, void *, int),
++ void (*closer)(int, void *))
++{
++ open_log = opener;
++ write_log = writer;
++ close_log = closer;
++}
++
++#endif
++
+ static ssize_t tty_read(struct file * file, char * buf, size_t count,
+ loff_t *ppos)
+ {
+@@ -689,8 +706,13 @@
+ else
+ i = -EIO;
+ unlock_kernel();
+- if (i > 0)
++ if (i > 0){
+ inode->i_atime = CURRENT_TIME;
++#ifdef CONFIG_TTY_LOG
++ if((tty->log_fd >= 0) && (write_log != NULL))
++ (*write_log)(tty->log_fd, buf, i, tty, 1);
++#endif
++ }
+ return i;
+ }
+
+@@ -744,6 +766,10 @@
+ if (written) {
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ ret = written;
++#ifdef CONFIG_TTY_LOG
++ if((tty->log_fd >= 0) && (write_log != NULL))
++ (*write_log)(tty->log_fd, buf - ret, ret, tty, 0);
++#endif
+ }
+ up(&tty->atomic_write);
+ return ret;
+@@ -971,6 +997,7 @@
+ goto release_mem_out;
+ }
+ }
++
+ goto success;
+
+ /*
+@@ -1290,6 +1317,11 @@
+ run_task_queue(&tq_timer);
+ flush_scheduled_tasks();
+
++#ifdef CONFIG_TTY_LOG
++ if((tty->log_fd >= 0) && (close_log != NULL))
++ (*close_log)(tty->log_fd, tty);
++#endif
++
+ /*
+ * The release_mem function takes care of the details of clearing
+ * the slots and preserving the termios structure.
+@@ -1448,6 +1480,11 @@
+ nr_warns++;
+ }
+ }
++
++#ifdef CONFIG_TTY_LOG
++ if((tty->log_fd < 0) && (open_log != NULL))
++ tty->log_fd = (*open_log)(tty, current->tty);
++#endif
+ return 0;
+ }
+
+@@ -2047,6 +2084,9 @@
+ spin_lock_init(&tty->read_lock);
+ INIT_LIST_HEAD(&tty->tty_files);
+ INIT_TQUEUE(&tty->SAK_tq, 0, 0);
++#ifdef CONFIG_TTY_LOG
++ tty->log_fd = -1;
++#endif
+ }
+
+ /*
+diff -Naur -X ../exclude-files orig/drivers/net/setup.c um/drivers/net/setup.c
+--- orig/drivers/net/setup.c 2002-09-15 12:13:19.000000000 -0400
++++ um/drivers/net/setup.c 2003-10-21 03:26:07.000000000 -0400
+@@ -28,7 +28,6 @@
+ extern int lmc_setup(void);
+
+ extern int madgemc_probe(void);
+-extern int uml_net_probe(void);
+
+ /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
+ #define __PAD6 "\0\0\0\0\0\0\0\0\0"
+@@ -103,9 +102,6 @@
+ #ifdef CONFIG_MADGEMC
+ {madgemc_probe, 0},
+ #endif
+-#ifdef CONFIG_UML_NET
+- {uml_net_probe, 0},
+-#endif
+
+ {NULL, 0},
+ };
+diff -Naur -X ../exclude-files orig/fs/bad_inode.c um/fs/bad_inode.c
+--- orig/fs/bad_inode.c 2002-08-21 11:47:27.000000000 -0400
++++ um/fs/bad_inode.c 2003-10-21 03:26:07.000000000 -0400
+@@ -83,6 +83,7 @@
+
+ void make_bad_inode(struct inode * inode)
+ {
++ inode->i_state = 0;
+ inode->i_mode = S_IFREG;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &bad_inode_ops;
+diff -Naur -X ../exclude-files orig/include/asm-i386/hardirq.h um/include/asm-i386/hardirq.h
+--- orig/include/asm-i386/hardirq.h 2004-01-11 22:46:12.000000000 -0500
++++ um/include/asm-i386/hardirq.h 2004-02-14 06:28:59.000000000 -0500
+@@ -4,6 +4,7 @@
+ #include <linux/config.h>
+ #include <linux/threads.h>
+ #include <linux/irq.h>
++#include <asm/processor.h> /* for cpu_relax */
+
+ /* assembly code in softirq.h is sensitive to the offsets of these fields */
+ typedef struct {
+diff -Naur -X ../exclude-files orig/include/asm-um/a.out.h um/include/asm-um/a.out.h
+--- orig/include/asm-um/a.out.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/a.out.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,20 @@
++#ifndef __UM_A_OUT_H
++#define __UM_A_OUT_H
++
++#include "linux/config.h"
++#include "asm/arch/a.out.h"
++#include "choose-mode.h"
++
++#undef STACK_TOP
++
++extern unsigned long stacksizelim;
++
++extern unsigned long host_task_size;
++
++#define STACK_ROOM (stacksizelim)
++
++extern int honeypot;
++#define STACK_TOP \
++ CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/archparam-i386.h um/include/asm-um/archparam-i386.h
+--- orig/include/asm-um/archparam-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/archparam-i386.h 2003-12-16 08:50:39.000000000 -0500
+@@ -0,0 +1,80 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.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, load_addr) 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] = PT_REGS_SYSCALL_NR(regs); \
++ pr_reg[12] = PT_REGS_IP(regs); \
++ pr_reg[13] = PT_REGS_CS(regs); \
++ pr_reg[14] = PT_REGS_EFLAGS(regs); \
++ pr_reg[15] = PT_REGS_SP(regs); \
++ pr_reg[16] = PT_REGS_SS(regs); \
++} while(0);
++
++/********* Bits for asm-um/delay.h **********/
++
++typedef unsigned long um_udelay_t;
++
++/********* Nothing for asm-um/hardirq.h **********/
++
++/********* Nothing for asm-um/hw_irq.h **********/
++
++/********* Nothing for asm-um/string.h **********/
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/archparam-ppc.h um/include/asm-um/archparam-ppc.h
+--- orig/include/asm-um/archparam-ppc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/archparam-ppc.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/include/asm-um/arch-signal-i386.h um/include/asm-um/arch-signal-i386.h
+--- orig/include/asm-um/arch-signal-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/arch-signal-i386.h 2003-10-21 03:26:07.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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/atomic.h um/include/asm-um/atomic.h
+--- orig/include/asm-um/atomic.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/atomic.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_ATOMIC_H
++#define __UM_ATOMIC_H
++
++#include "asm/arch/atomic.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/bitops.h um/include/asm-um/bitops.h
+--- orig/include/asm-um/bitops.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/bitops.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_BITOPS_H
++#define __UM_BITOPS_H
++
++#include "asm/arch/bitops.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/boot.h um/include/asm-um/boot.h
+--- orig/include/asm-um/boot.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/boot.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BOOT_H
++#define __UM_BOOT_H
++
++#include "asm/arch/boot.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/bugs.h um/include/asm-um/bugs.h
+--- orig/include/asm-um/bugs.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/bugs.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_BUGS_H
++#define __UM_BUGS_H
++
++void check_bugs(void);
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/byteorder.h um/include/asm-um/byteorder.h
+--- orig/include/asm-um/byteorder.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/byteorder.h 2004-01-16 03:32:58.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_BYTEORDER_H
++#define __UM_BYTEORDER_H
++
++#include "asm/arch/byteorder.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/cache.h um/include/asm-um/cache.h
+--- orig/include/asm-um/cache.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/cache.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_CACHE_H
++#define __UM_CACHE_H
++
++#define L1_CACHE_BYTES 32
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/checksum.h um/include/asm-um/checksum.h
+--- orig/include/asm-um/checksum.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/checksum.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_CHECKSUM_H
++#define __UM_CHECKSUM_H
++
++#include "sysdep/checksum.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/cobalt.h um/include/asm-um/cobalt.h
+--- orig/include/asm-um/cobalt.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/cobalt.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_COBALT_H
++#define __UM_COBALT_H
++
++#include "asm/arch/cobalt.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/current.h um/include/asm-um/current.h
+--- orig/include/asm-um/current.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/current.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,34 @@
++/*
++ * 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 << CONFIG_KERNEL_STACK_ORDER))
++
++#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); })
++
++#endif /* __ASSEMBLY__ */
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/delay.h um/include/asm-um/delay.h
+--- orig/include/asm-um/delay.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/delay.h 2003-12-16 22:26:58.000000000 -0500
+@@ -0,0 +1,7 @@
++#ifndef __UM_DELAY_H
++#define __UM_DELAY_H
++
++#include "asm/arch/delay.h"
++#include "asm/archparam.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/desc.h um/include/asm-um/desc.h
+--- orig/include/asm-um/desc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/desc.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_DESC_H
++#define __UM_DESC_H
++
++#include "asm/arch/desc.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/div64.h um/include/asm-um/div64.h
+--- orig/include/asm-um/div64.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/div64.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef _UM_DIV64_H
++#define _UM_DIV64_H
++
++#include "asm/arch/div64.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/dma.h um/include/asm-um/dma.h
+--- orig/include/asm-um/dma.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/dma.h 2004-01-16 03:32:59.000000000 -0500
+@@ -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
+diff -Naur -X ../exclude-files orig/include/asm-um/elf.h um/include/asm-um/elf.h
+--- orig/include/asm-um/elf.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/elf.h 2003-12-16 22:29:20.000000000 -0500
+@@ -0,0 +1,18 @@
++#ifndef __UM_ELF_H
++#define __UM_ELF_H
++
++#include "asm/archparam.h"
++
++#define ELF_HWCAP (0)
++
++#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
++
++#define ELF_EXEC_PAGESIZE 4096
++
++#define elf_check_arch(x) (1)
++
++#define ELF_CLASS ELFCLASS32
++
++#define USE_ELF_CORE_DUMP
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/errno.h um/include/asm-um/errno.h
+--- orig/include/asm-um/errno.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/errno.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_ERRNO_H
++#define __UM_ERRNO_H
++
++#include "asm/arch/errno.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/fcntl.h um/include/asm-um/fcntl.h
+--- orig/include/asm-um/fcntl.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/fcntl.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_FCNTL_H
++#define __UM_FCNTL_H
++
++#include "asm/arch/fcntl.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/fixmap.h um/include/asm-um/fixmap.h
+--- orig/include/asm-um/fixmap.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/fixmap.h 2004-02-14 06:29:00.000000000 -0500
+@@ -0,0 +1,89 @@
++#ifndef __UM_FIXMAP_H
++#define __UM_FIXMAP_H
++
++#include <linux/config.h>
++#include <asm/kmap_types.h>
++
++/*
++ * Here we define all the compile-time 'special' virtual
++ * addresses. The point is to have a constant address at
++ * compile time, but to set the physical address only
++ * in the boot process. We allocate these special addresses
++ * from the end of virtual memory (0xfffff000) backwards.
++ * Also this lets us do fail-safe vmalloc(), we
++ * can guarantee that these special addresses and
++ * vmalloc()-ed addresses never overlap.
++ *
++ * these 'compile-time allocated' memory buffers are
++ * fixed-size 4k pages. (or larger if used with an increment
++ * highger than 1) use fixmap_set(idx,phys) to associate
++ * physical memory with fixmap indices.
++ *
++ * TLB entries of such buffers will not be flushed across
++ * task switches.
++ */
++
++/*
++ * on UP currently we will have no trace of the fixmap mechanizm,
++ * no page table allocations, etc. This might change in the
++ * future, say framebuffers for the console driver(s) could be
++ * fix-mapped?
++ */
++enum fixed_addresses {
++#ifdef CONFIG_HIGHMEM
++ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
++ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
++#endif
++ __end_of_fixed_addresses
++};
++
++extern void __set_fixmap (enum fixed_addresses idx,
++ unsigned long phys, pgprot_t flags);
++
++#define set_fixmap(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL)
++/*
++ * Some hardware wants to get fixmapped without caching.
++ */
++#define set_fixmap_nocache(idx, phys) \
++ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
++/*
++ * used by vmalloc.c.
++ *
++ * Leave one empty page between vmalloc'ed areas and
++ * the start of the fixmap, and leave one page empty
++ * at the top of mem..
++ */
++extern unsigned long get_kmem_end(void);
++
++#define FIXADDR_TOP (get_kmem_end() - 0x2000)
++#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
++
++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
++
++extern void __this_fixmap_does_not_exist(void);
++
++/*
++ * 'index to address' translation. If anyone tries to use the idx
++ * directly without tranlation, we catch the bug with a NULL-deference
++ * kernel oops. Illegal ranges of incoming indices are caught too.
++ */
++static inline unsigned long fix_to_virt(const unsigned int idx)
++{
++ /*
++ * this branch gets completely eliminated after inlining,
++ * except when someone tries to use fixaddr indices in an
++ * illegal way. (such as mixing up address types or using
++ * out-of-range indices).
++ *
++ * If it doesn't get removed, the linker will complain
++ * loudly with a reasonably clear error message..
++ */
++ if (idx >= __end_of_fixed_addresses)
++ __this_fixmap_does_not_exist();
++
++ return __fix_to_virt(idx);
++}
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/floppy.h um/include/asm-um/floppy.h
+--- orig/include/asm-um/floppy.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/floppy.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_FLOPPY_H
++#define __UM_FLOPPY_H
++
++#include "asm/arch/floppy.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/hardirq.h um/include/asm-um/hardirq.h
+--- orig/include/asm-um/hardirq.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/hardirq.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_HARDIRQ_H
++#define __UM_HARDIRQ_H
++
++#include "asm/arch/hardirq.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/hdreg.h um/include/asm-um/hdreg.h
+--- orig/include/asm-um/hdreg.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/hdreg.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_HDREG_H
++#define __UM_HDREG_H
++
++#include "asm/arch/hdreg.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/highmem.h um/include/asm-um/highmem.h
+--- orig/include/asm-um/highmem.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/highmem.h 2004-02-14 06:29:00.000000000 -0500
+@@ -0,0 +1,12 @@
++#ifndef __UM_HIGHMEM_H
++#define __UM_HIGHMEM_H
++
++#include "asm/page.h"
++#include "asm/fixmap.h"
++#include "asm/arch/highmem.h"
++
++#undef PKMAP_BASE
++
++#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/hw_irq.h um/include/asm-um/hw_irq.h
+--- orig/include/asm-um/hw_irq.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/hw_irq.h 2003-12-16 22:26:55.000000000 -0500
+@@ -0,0 +1,10 @@
++#ifndef _ASM_UM_HW_IRQ_H
++#define _ASM_UM_HW_IRQ_H
++
++#include "asm/irq.h"
++#include "asm/archparam.h"
++
++static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
++{}
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/ide.h um/include/asm-um/ide.h
+--- orig/include/asm-um/ide.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ide.h 2004-01-16 23:40:52.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_IDE_H
++#define __UM_IDE_H
++
++#include "asm/arch/ide.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/init.h um/include/asm-um/init.h
+--- orig/include/asm-um/init.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/init.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/include/asm-um/ioctl.h um/include/asm-um/ioctl.h
+--- orig/include/asm-um/ioctl.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ioctl.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTL_H
++#define __UM_IOCTL_H
++
++#include "asm/arch/ioctl.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/ioctls.h um/include/asm-um/ioctls.h
+--- orig/include/asm-um/ioctls.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ioctls.h 2003-11-07 02:10:43.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTLS_H
++#define __UM_IOCTLS_H
++
++#include "asm/arch/ioctls.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/io.h um/include/asm-um/io.h
+--- orig/include/asm-um/io.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/io.h 2004-01-16 03:32:59.000000000 -0500
+@@ -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
+diff -Naur -X ../exclude-files orig/include/asm-um/ipcbuf.h um/include/asm-um/ipcbuf.h
+--- orig/include/asm-um/ipcbuf.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ipcbuf.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPCBUF_H
++#define __UM_IPCBUF_H
++
++#include "asm/arch/ipcbuf.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/ipc.h um/include/asm-um/ipc.h
+--- orig/include/asm-um/ipc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ipc.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPC_H
++#define __UM_IPC_H
++
++#include "asm/arch/ipc.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/irq.h um/include/asm-um/irq.h
+--- orig/include/asm-um/irq.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/irq.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,22 @@
++#ifndef __UM_IRQ_H
++#define __UM_IRQ_H
++
++#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 XTERM_IRQ 13
++
++#define LAST_IRQ XTERM_IRQ
++#define NR_IRQS (LAST_IRQ + 1)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/keyboard.h um/include/asm-um/keyboard.h
+--- orig/include/asm-um/keyboard.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/keyboard.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_KEYBOARD_H
++#define __UM_KEYBOARD_H
++
++#include "asm/arch/keyboard.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/kmap_types.h um/include/asm-um/kmap_types.h
+--- orig/include/asm-um/kmap_types.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/kmap_types.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,11 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_KMAP_TYPES_H
++#define __UM_KMAP_TYPES_H
++
++#include "asm/arch/kmap_types.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/linux_logo.h um/include/asm-um/linux_logo.h
+--- orig/include/asm-um/linux_logo.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/linux_logo.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_LINUX_LOGO_H
++#define __UM_LINUX_LOGO_H
++
++#include "asm/arch/linux_logo.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/locks.h um/include/asm-um/locks.h
+--- orig/include/asm-um/locks.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/locks.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_LOCKS_H
++#define __UM_LOCKS_H
++
++#include "asm/arch/locks.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/mca_dma.h um/include/asm-um/mca_dma.h
+--- orig/include/asm-um/mca_dma.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/mca_dma.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef mca___UM_DMA_H
++#define mca___UM_DMA_H
++
++#include "asm/arch/mca_dma.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/mman.h um/include/asm-um/mman.h
+--- orig/include/asm-um/mman.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/mman.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MMAN_H
++#define __UM_MMAN_H
++
++#include "asm/arch/mman.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/mmu_context.h um/include/asm-um/mmu_context.h
+--- orig/include/asm-um/mmu_context.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/mmu_context.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,72 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_MMU_CONTEXT_H
++#define __UM_MMU_CONTEXT_H
++
++#include "linux/sched.h"
++#include "choose-mode.h"
++
++#define get_mmu_context(task) do ; while(0)
++#define activate_context(tsk) do ; while(0)
++
++static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
++{
++}
++
++extern void switch_mm_skas(int mm_fd);
++
++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
++ struct task_struct *tsk, unsigned cpu)
++{
++ if(prev != next){
++ clear_bit(cpu, &prev->cpu_vm_mask);
++ set_bit(cpu, &next->cpu_vm_mask);
++ if(next != &init_mm)
++ CHOOSE_MODE((void) 0,
++ switch_mm_skas(next->context.skas.mm_fd));
++ }
++}
++
++static inline void enter_lazy_tlb(struct mm_struct *mm,
++ struct task_struct *tsk, unsigned cpu)
++{
++}
++
++extern int init_new_context_skas(struct task_struct *task,
++ struct mm_struct *mm);
++
++static inline int init_new_context_tt(struct task_struct *task,
++ struct mm_struct *mm)
++{
++ return(0);
++}
++
++static inline int init_new_context(struct task_struct *task,
++ struct mm_struct *mm)
++{
++ return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas,
++ task, mm));
++}
++
++extern void destroy_context_skas(struct mm_struct *mm);
++
++static inline void destroy_context(struct mm_struct *mm)
++{
++ CHOOSE_MODE((void) 0, destroy_context_skas(mm));
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/mmu.h um/include/asm-um/mmu.h
+--- orig/include/asm-um/mmu.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/mmu.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MMU_H
++#define __MMU_H
++
++#include "um_mmu.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/module.h um/include/asm-um/module.h
+--- orig/include/asm-um/module.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/module.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MODULE_H
++#define __UM_MODULE_H
++
++#include "asm/arch/module.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/msgbuf.h um/include/asm-um/msgbuf.h
+--- orig/include/asm-um/msgbuf.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/msgbuf.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_MSGBUF_H
++#define __UM_MSGBUF_H
++
++#include "asm/arch/msgbuf.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/mtrr.h um/include/asm-um/mtrr.h
+--- orig/include/asm-um/mtrr.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/mtrr.h 2004-02-12 05:46:29.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_MTRR_H
++#define __UM_MTRR_H
++
++#include "asm/arch/mtrr.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/namei.h um/include/asm-um/namei.h
+--- orig/include/asm-um/namei.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/namei.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_NAMEI_H
++#define __UM_NAMEI_H
++
++#include "asm/arch/namei.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/page.h um/include/asm-um/page.h
+--- orig/include/asm-um/page.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/page.h 2004-01-16 03:32:58.000000000 -0500
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#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
++
++extern unsigned long uml_physmem;
++
++#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 to_phys(void *virt);
++extern void *to_virt(unsigned long phys);
++
++#define __pa(virt) to_phys((void *) virt)
++#define __va(phys) to_virt((unsigned long) phys)
++
++#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
++
++extern struct page *arch_validate(struct page *page, int mask, int order);
++#define HAVE_ARCH_VALIDATE
++
++extern void arch_free_page(struct page *page, int order);
++#define HAVE_ARCH_FREE_PAGE
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/page_offset.h um/include/asm-um/page_offset.h
+--- orig/include/asm-um/page_offset.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/page_offset.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1 @@
++#define PAGE_OFFSET_RAW (uml_physmem)
+diff -Naur -X ../exclude-files orig/include/asm-um/param.h um/include/asm-um/param.h
+--- orig/include/asm-um/param.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/param.h 2004-02-13 02:26:52.000000000 -0500
+@@ -0,0 +1,22 @@
++#ifndef _UM_PARAM_H
++#define _UM_PARAM_H
++
++#define HZ 100
++
++#define EXEC_PAGESIZE 4096
++
++#ifndef NGROUPS
++#define NGROUPS 32
++#endif
++
++#ifndef NOGROUP
++#define NOGROUP (-1)
++#endif
++
++#define MAXHOSTNAMELEN 64 /* max length of hostname */
++
++#ifdef __KERNEL__
++# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */
++#endif
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/pci.h um/include/asm-um/pci.h
+--- orig/include/asm-um/pci.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/pci.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_PCI_H
++#define __UM_PCI_H
++
++#define PCI_DMA_BUS_IS_PHYS (1)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/pgalloc.h um/include/asm-um/pgalloc.h
+--- orig/include/asm-um/pgalloc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/pgalloc.h 2004-02-14 06:29:00.000000000 -0500
+@@ -0,0 +1,164 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 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/config.h"
++#include "linux/mm.h"
++#include "asm/fixmap.h"
++#include "choose-mode.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 + __pa(pte)))
++
++/*
++ * Allocate and free page tables.
++ */
++
++static inline pgd_t *get_pgd_slow_tt(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_slow_skas(void)
++{
++ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
++
++ if (pgd)
++ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
++ return pgd;
++}
++
++static inline pgd_t *get_pgd_slow(void)
++{
++ return(CHOOSE_MODE(get_pgd_slow_tt(), get_pgd_slow_skas()));
++}
++
++static inline pgd_t *get_pgd_fast(void)
++{
++ unsigned long *ret;
++
++ ret = pgd_quicklist;
++ if (ret != 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;
++
++ ret = (unsigned long *)pte_quicklist;
++ if (ret != NULL) {
++ pte_quicklist = (unsigned long *)(*ret);
++ ret[0] = ret[1];
++ pgtable_cache_size--;
++ }
++ return (pte_t *)ret;
++}
++
++static inline void pte_free_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_fast(pte)
++#define pgd_free(pgd) free_pgd_slow(pgd)
++#define pgd_alloc(mm) get_pgd_fast()
++
++/*
++ * allocating and freeing a pmd is trivial: the 1-entry pmd is
++ * inside the pgd, so has no extra memory associated with it.
++ */
++
++#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); })
++#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
++#define pmd_free_slow(x) do { } while (0)
++#define pmd_free_fast(x) do { } while (0)
++#define pmd_free(x) do { } while (0)
++#define pgd_populate(mm, pmd, pte) BUG()
++
++/*
++ * TLB flushing:
++ *
++ * - flush_tlb() flushes the current mm struct TLBs
++ * - flush_tlb_all() flushes all processes TLBs
++ * - flush_tlb_mm(mm) flushes the specified mm context TLB's
++ * - flush_tlb_page(vma, vmaddr) flushes one page
++ * - flush_tlb_kernel_vm() flushes the kernel vm area
++ * - flush_tlb_range(mm, start, end) flushes a range of pages
++ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ */
++
++extern void flush_tlb_all(void);
++extern void flush_tlb_mm(struct mm_struct *mm);
++extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
++ unsigned long end);
++extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
++extern void flush_tlb_kernel_vm(void);
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++ unsigned long start, unsigned long end)
++{
++}
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/pgtable.h um/include/asm-um/pgtable.h
+--- orig/include/asm-um/pgtable.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/pgtable.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,413 @@
++/*
++ * 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)
++#define flush_icache_user_range(vma,pg,adr,len) do ; while (0)
++
++extern void __flush_tlb_one(unsigned long addr);
++
++extern void pte_free(pte_t *pte);
++
++extern void pgd_free(pgd_t *pgd);
++
++extern int do_check_pgt_cache(int, int);
++
++extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
++ pte_t *pte_out);
++
++/* 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 end_iomem;
++
++#define VMALLOC_OFFSET (__va_space)
++#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++
++#if CONFIG_HIGHMEM
++# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
++#else
++# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
++#endif
++
++#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 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) { }
++
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++#define pte_page(pte) virt_to_page(__va(pte_val(pte)))
++#define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++
++extern struct page *phys_to_page(const unsigned long phys);
++extern struct page *__virt_to_page(const unsigned long virt);
++#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
++
++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) &&
++ !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++static inline int pte_exec(pte_t pte){
++ return((pte_val(pte) & _PAGE_USER) &&
++ !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++static inline int pte_write(pte_t pte)
++{
++ return((pte_val(pte) & _PAGE_RW) &&
++ !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++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_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.
++ */
++
++extern pte_t mk_pte(struct page *page, pgprot_t pgprot);
++
++/* This takes a physical page address that is used by the remapping
++ * functions
++ */
++#define mk_pte_phys(phys, pgprot) \
++ (pte_mknewpage(mk_pte(virt_to_page(__va(phys)), 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;
++}
++
++/* to find an entry in a page-table-directory. */
++#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define __pgd_offset(address) pgd_index(address)
++
++/* 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)
++
++#define __pmd_offset(address) \
++ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
++
++/* Find an entry in the second-level page table.. */
++static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
++{
++ return (pmd_t *) dir;
++}
++
++/* Find an entry in the third-level page table.. */
++#define pte_offset(pmd, address) \
++ ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
++
++#define update_mmu_cache(vma,address,pte) do ; while (0)
++
++/* Encode and de-code a swap entry */
++#define SWP_TYPE(x) (((x).val >> 3) & 0x7f)
++#define SWP_OFFSET(x) ((x).val >> 10)
++
++#define SWP_ENTRY(type, offset) \
++ ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
++#define pte_to_swp_entry(pte) \
++ ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
++#define swp_entry_to_pte(x) ((pte_t) { (x).val })
++
++#define PageSkip(x) (0)
++#define kern_addr_valid(addr) (1)
++
++#include <asm-generic/pgtable.h>
++
++#endif
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/poll.h um/include/asm-um/poll.h
+--- orig/include/asm-um/poll.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/poll.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_POLL_H
++#define __UM_POLL_H
++
++#include "asm/arch/poll.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/posix_types.h um/include/asm-um/posix_types.h
+--- orig/include/asm-um/posix_types.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/posix_types.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_POSIX_TYPES_H
++#define __UM_POSIX_TYPES_H
++
++#include "asm/arch/posix_types.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/processor-generic.h um/include/asm-um/processor-generic.h
+--- orig/include/asm-um/processor-generic.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/processor-generic.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,177 @@
++/*
++ * 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/ptrace.h"
++#include "asm/siginfo.h"
++#include "choose-mode.h"
++
++struct mm_struct;
++
++#define current_text_addr() ((void *) 0)
++
++#define cpu_relax() do ; while (0)
++
++struct thread_struct {
++ int forking;
++ unsigned long kernel_stack;
++ int nsyscalls;
++ struct pt_regs regs;
++ unsigned long cr2;
++ int err;
++ unsigned long trap_no;
++ void *fault_addr;
++ void *fault_catcher;
++ struct task_struct *prev_sched;
++ unsigned long temp_stack;
++ void *exec_buf;
++ struct arch_thread arch;
++ union {
++#ifdef CONFIG_MODE_TT
++ struct {
++ int extern_pid;
++ int tracing;
++ int switch_pipe[2];
++ int singlestep_syscall;
++ int vm_seq;
++ } tt;
++#endif
++#ifdef CONFIG_MODE_SKAS
++ struct {
++ void *switch_buf;
++ void *fork_buf;
++ int mm_count;
++ } skas;
++#endif
++ } mode;
++ 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 \
++{ \
++ .forking = 0, \
++ .kernel_stack = 0, \
++ .nsyscalls = 0, \
++ .regs = EMPTY_REGS, \
++ .cr2 = 0, \
++ .err = 0, \
++ .fault_addr = NULL, \
++ .prev_sched = NULL, \
++ .temp_stack = 0, \
++ .exec_buf = NULL, \
++ .arch = INIT_ARCH_THREAD, \
++ .request = { 0 } \
++}
++
++#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++
++typedef struct {
++ unsigned long seg;
++} mm_segment_t;
++
++extern struct task_struct *alloc_task_struct(void);
++extern void free_task_struct(struct task_struct *task);
++
++#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)
++
++extern void release_thread(struct task_struct *);
++extern int arch_kernel_thread(int (*fn)(void *), void * arg,
++ unsigned long flags);
++extern void dump_thread(struct pt_regs *regs, struct user *u);
++
++extern unsigned long thread_saved_pc(struct thread_struct *t);
++
++static inline void mm_copy_segments(struct mm_struct *from_mm,
++ struct mm_struct *new_mm)
++{
++}
++
++static inline void copy_segments(struct task_struct *p,
++ struct mm_struct *new_mm)
++{
++}
++
++static inline void release_segments(struct mm_struct *mm)
++{
++}
++
++#define init_task (init_task_union.task)
++#define init_stack (init_task_union.stack)
++
++/*
++ * User space process size: 3GB (default).
++ */
++extern unsigned long task_size;
++
++#define TASK_SIZE (task_size)
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE (0x40000000)
++
++extern void start_thread(struct pt_regs *regs, unsigned long entry,
++ unsigned long stack);
++
++struct cpuinfo_um {
++ unsigned long loops_per_jiffy;
++ unsigned long *pgd_quick;
++ unsigned long *pmd_quick;
++ unsigned long *pte_quick;
++ unsigned long pgtable_cache_sz;
++ int ipi_pipe[2];
++};
++
++extern struct cpuinfo_um boot_cpu_data;
++
++#define my_cpu_data cpu_data[smp_processor_id()]
++
++#ifdef CONFIG_SMP
++extern struct cpuinfo_um cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++#define KSTK_EIP(tsk) (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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/processor-i386.h um/include/asm-um/processor-i386.h
+--- orig/include/asm-um/processor-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/processor-i386.h 2004-02-14 06:28:59.000000000 -0500
+@@ -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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/processor-ppc.h um/include/asm-um/processor-ppc.h
+--- orig/include/asm-um/processor-ppc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/processor-ppc.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/include/asm-um/ptrace-generic.h um/include/asm-um/ptrace-generic.h
+--- orig/include/asm-um/ptrace-generic.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ptrace-generic.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,74 @@
++/*
++ * 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 "linux/config.h"
++
++#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"
++#include "skas_ptrace.h"
++
++struct pt_regs {
++ union 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 ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/ptrace-i386.h um/include/asm-um/ptrace-i386.h
+--- orig/include/asm-um/ptrace-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ptrace-i386.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,46 @@
++/*
++ * 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 "sysdep/ptrace.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) UPT_IS_USER(&(r)->regs)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/resource.h um/include/asm-um/resource.h
+--- orig/include/asm-um/resource.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/resource.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_RESOURCE_H
++#define __UM_RESOURCE_H
++
++#include "asm/arch/resource.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/rwlock.h um/include/asm-um/rwlock.h
+--- orig/include/asm-um/rwlock.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/rwlock.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_RWLOCK_H
++#define __UM_RWLOCK_H
++
++#include "asm/arch/rwlock.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/rwsem.h um/include/asm-um/rwsem.h
+--- orig/include/asm-um/rwsem.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/rwsem.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,10 @@
++#ifndef __UM_RWSEM_H__
++#define __UM_RWSEM_H__
++
++#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
++#define __builtin_expect(exp,c) (exp)
++#endif
++
++#include "asm/arch/rwsem.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/scatterlist.h um/include/asm-um/scatterlist.h
+--- orig/include/asm-um/scatterlist.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/scatterlist.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SCATTERLIST_H
++#define __UM_SCATTERLIST_H
++
++#include "asm/arch/scatterlist.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/segment.h um/include/asm-um/segment.h
+--- orig/include/asm-um/segment.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/segment.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,4 @@
++#ifndef __UM_SEGMENT_H
++#define __UM_SEGMENT_H
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/semaphore.h um/include/asm-um/semaphore.h
+--- orig/include/asm-um/semaphore.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/semaphore.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMAPHORE_H
++#define __UM_SEMAPHORE_H
++
++#include "asm/arch/semaphore.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/sembuf.h um/include/asm-um/sembuf.h
+--- orig/include/asm-um/sembuf.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/sembuf.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMBUF_H
++#define __UM_SEMBUF_H
++
++#include "asm/arch/sembuf.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/serial.h um/include/asm-um/serial.h
+--- orig/include/asm-um/serial.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/serial.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SERIAL_H
++#define __UM_SERIAL_H
++
++#include "asm/arch/serial.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/shmbuf.h um/include/asm-um/shmbuf.h
+--- orig/include/asm-um/shmbuf.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/shmbuf.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMBUF_H
++#define __UM_SHMBUF_H
++
++#include "asm/arch/shmbuf.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/shmparam.h um/include/asm-um/shmparam.h
+--- orig/include/asm-um/shmparam.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/shmparam.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMPARAM_H
++#define __UM_SHMPARAM_H
++
++#include "asm/arch/shmparam.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-generic.h um/include/asm-um/sigcontext-generic.h
+--- orig/include/asm-um/sigcontext-generic.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/sigcontext-generic.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_GENERIC_H
++#define __UM_SIGCONTEXT_GENERIC_H
++
++#include "asm/arch/sigcontext.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-i386.h um/include/asm-um/sigcontext-i386.h
+--- orig/include/asm-um/sigcontext-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/sigcontext-i386.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_I386_H
++#define __UM_SIGCONTEXT_I386_H
++
++#include "asm/sigcontext-generic.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-ppc.h um/include/asm-um/sigcontext-ppc.h
+--- orig/include/asm-um/sigcontext-ppc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/sigcontext-ppc.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/include/asm-um/siginfo.h um/include/asm-um/siginfo.h
+--- orig/include/asm-um/siginfo.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/siginfo.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGINFO_H
++#define __UM_SIGINFO_H
++
++#include "asm/arch/siginfo.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/signal.h um/include/asm-um/signal.h
+--- orig/include/asm-um/signal.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/signal.h 2004-02-14 06:28:59.000000000 -0500
+@@ -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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/smp.h um/include/asm-um/smp.h
+--- orig/include/asm-um/smp.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/smp.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,19 @@
++#ifndef __UM_SMP_H
++#define __UM_SMP_H
++
++#ifdef CONFIG_SMP
++
++#include "linux/config.h"
++#include "asm/current.h"
++
++#define smp_processor_id() (current->processor)
++#define cpu_logical_map(n) (n)
++#define cpu_number_map(n) (n)
++#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */
++extern int hard_smp_processor_id(void);
++extern unsigned long cpu_online_map;
++#define NO_PROC_ID -1
++
++#endif
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/smplock.h um/include/asm-um/smplock.h
+--- orig/include/asm-um/smplock.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/smplock.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_SMPLOCK_H
++#define __UM_SMPLOCK_H
++
++#include "asm/arch/smplock.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/socket.h um/include/asm-um/socket.h
+--- orig/include/asm-um/socket.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/socket.h 2003-11-07 02:10:43.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKET_H
++#define __UM_SOCKET_H
++
++#include "asm/arch/socket.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/sockios.h um/include/asm-um/sockios.h
+--- orig/include/asm-um/sockios.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/sockios.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKIOS_H
++#define __UM_SOCKIOS_H
++
++#include "asm/arch/sockios.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/softirq.h um/include/asm-um/softirq.h
+--- orig/include/asm-um/softirq.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/softirq.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,13 @@
++#ifndef __UM_SOFTIRQ_H
++#define __UM_SOFTIRQ_H
++
++#include "linux/smp.h"
++#include "asm/system.h"
++#include "asm/processor.h"
++
++/* A gratuitous name change */
++#define i386_bh_lock um_bh_lock
++#include "asm/arch/softirq.h"
++#undef i386_bh_lock
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/spinlock.h um/include/asm-um/spinlock.h
+--- orig/include/asm-um/spinlock.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/spinlock.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,10 @@
++#ifndef __UM_SPINLOCK_H
++#define __UM_SPINLOCK_H
++
++#include "linux/config.h"
++
++#ifdef CONFIG_SMP
++#include "asm/arch/spinlock.h"
++#endif
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/statfs.h um/include/asm-um/statfs.h
+--- orig/include/asm-um/statfs.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/statfs.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef _UM_STATFS_H
++#define _UM_STATFS_H
++
++#include "asm/arch/statfs.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/stat.h um/include/asm-um/stat.h
+--- orig/include/asm-um/stat.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/stat.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_STAT_H
++#define __UM_STAT_H
++
++#include "asm/arch/stat.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/string.h um/include/asm-um/string.h
+--- orig/include/asm-um/string.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/string.h 2004-01-16 03:32:58.000000000 -0500
+@@ -0,0 +1,7 @@
++#ifndef __UM_STRING_H
++#define __UM_STRING_H
++
++#include "asm/arch/string.h"
++#include "asm/archparam.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/system-generic.h um/include/asm-um/system-generic.h
+--- orig/include/asm-um/system-generic.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/system-generic.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,50 @@
++#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 get_signals(void);
++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) do { (x) = get_signals(); } while(0)
++#define save_flags(x) __save_flags(x)
++
++#define __restore_flags(x) local_irq_restore(x)
++#define restore_flags(x) __restore_flags(x)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/system-i386.h um/include/asm-um/system-i386.h
+--- orig/include/asm-um/system-i386.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/system-i386.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,39 @@
++#ifndef __UM_SYSTEM_I386_H
++#define __UM_SYSTEM_I386_H
++
++#include "asm/system-generic.h"
++
++#define __HAVE_ARCH_CMPXCHG 1
++
++static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
++ unsigned long new, int size)
++{
++ unsigned long prev;
++ switch (size) {
++ case 1:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 2:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ case 4:
++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
++ : "=a"(prev)
++ : "q"(new), "m"(*__xg(ptr)), "0"(old)
++ : "memory");
++ return prev;
++ }
++ return old;
++}
++
++#define cmpxchg(ptr,o,n)\
++ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
++ (unsigned long)(n),sizeof(*(ptr))))
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/system-ppc.h um/include/asm-um/system-ppc.h
+--- orig/include/asm-um/system-ppc.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/system-ppc.h 2003-10-21 03:26:07.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
+diff -Naur -X ../exclude-files orig/include/asm-um/termbits.h um/include/asm-um/termbits.h
+--- orig/include/asm-um/termbits.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/termbits.h 2003-11-07 02:10:43.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMBITS_H
++#define __UM_TERMBITS_H
++
++#include "asm/arch/termbits.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/termios.h um/include/asm-um/termios.h
+--- orig/include/asm-um/termios.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/termios.h 2003-12-16 22:26:55.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMIOS_H
++#define __UM_TERMIOS_H
++
++#include "asm/arch/termios.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/timex.h um/include/asm-um/timex.h
+--- orig/include/asm-um/timex.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/timex.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,18 @@
++#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;
++}
++
++#define vxtime_lock() do ; while (0)
++#define vxtime_unlock() do ; while (0)
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/tlb.h um/include/asm-um/tlb.h
+--- orig/include/asm-um/tlb.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/tlb.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1 @@
++#include <asm-generic/tlb.h>
+diff -Naur -X ../exclude-files orig/include/asm-um/types.h um/include/asm-um/types.h
+--- orig/include/asm-um/types.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/types.h 2004-01-16 03:32:58.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_TYPES_H
++#define __UM_TYPES_H
++
++#include "asm/arch/types.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/uaccess.h um/include/asm-um/uaccess.h
+--- orig/include/asm-um/uaccess.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/uaccess.h 2004-02-14 06:28:59.000000000 -0500
+@@ -0,0 +1,99 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_UACCESS_H
++#define __UM_UACCESS_H
++
++#include "linux/sched.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 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))
++
++#define segment_eq(a, b) ((a).seg == (b).seg)
++
++#include "um_uaccess.h"
++
++#define __copy_from_user(to, from, n) copy_from_user(to, from, 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); \
++})
++
++#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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/ucontext.h um/include/asm-um/ucontext.h
+--- orig/include/asm-um/ucontext.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/ucontext.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef _ASM_UM_UCONTEXT_H
++#define _ASM_UM_UCONTEXT_H
++
++#include "asm/arch/ucontext.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/unaligned.h um/include/asm-um/unaligned.h
+--- orig/include/asm-um/unaligned.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/unaligned.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_UNALIGNED_H
++#define __UM_UNALIGNED_H
++
++#include "asm/arch/unaligned.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/unistd.h um/include/asm-um/unistd.h
+--- orig/include/asm-um/unistd.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/unistd.h 2004-02-14 06:29:00.000000000 -0500
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef _UM_UNISTD_H_
++#define _UM_UNISTD_H_
++
++#include "linux/resource.h"
++#include "asm/uaccess.h"
++
++extern long sys_open(const char *filename, int flags, int mode);
++extern long sys_dup(unsigned int fildes);
++extern long sys_close(unsigned int fd);
++extern 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 long sys_read(unsigned int fildes, char *buf, int len);
++extern long sys_write(unsigned int fildes, char *buf, int len);
++
++#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); \
++ if (ret >= 0) \
++ return ret; \
++ errno = -(long)ret; \
++ return -1;
++
++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:
++ */
+diff -Naur -X ../exclude-files orig/include/asm-um/user.h um/include/asm-um/user.h
+--- orig/include/asm-um/user.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/user.h 2004-02-14 06:31:38.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_USER_H
++#define __UM_USER_H
++
++#include "asm/arch/user.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/vga.h um/include/asm-um/vga.h
+--- orig/include/asm-um/vga.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/vga.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_VGA_H
++#define __UM_VGA_H
++
++#include "asm/arch/vga.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/asm-um/xor.h um/include/asm-um/xor.h
+--- orig/include/asm-um/xor.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/asm-um/xor.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,6 @@
++#ifndef __UM_XOR_H
++#define __UM_XOR_H
++
++#include "asm-generic/xor.h"
++
++#endif
+diff -Naur -X ../exclude-files orig/include/linux/blk.h um/include/linux/blk.h
+--- orig/include/linux/blk.h 2004-01-11 22:46:30.000000000 -0500
++++ um/include/linux/blk.h 2004-02-14 06:29:18.000000000 -0500
+@@ -320,6 +320,24 @@
+ #define DEVICE_REQUEST do_ida_request
+ #define DEVICE_NR(device) (MINOR(device) >> 4)
+
++#elif (MAJOR_NR == UBD_MAJOR)
++
++#define DEVICE_NAME "User-mode block device"
++#define DEVICE_INTR do_ubd
++#define DEVICE_REQUEST do_ubd_request
++#define DEVICE_NR(device) (MINOR(device) >> UBD_SHIFT)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++
++#elif (MAJOR_NR == COW_MAJOR)
++
++#define DEVICE_NAME "COW device"
++#define DEVICE_INTR do_cow
++#define DEVICE_REQUEST do_cow_request
++#define DEVICE_NR(device) (MINOR(device) >> COW_SHIFT)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++
+ #endif /* MAJOR_NR == whatever */
+
+ /* provide DEVICE_xxx defaults, if not explicitly defined
+diff -Naur -X ../exclude-files orig/include/linux/fs.h um/include/linux/fs.h
+--- orig/include/linux/fs.h 2003-12-16 22:16:36.000000000 -0500
++++ um/include/linux/fs.h 2004-02-14 06:28:59.000000000 -0500
+@@ -320,6 +320,8 @@
+ #include <linux/ncp_fs_i.h>
+ #include <linux/proc_fs_i.h>
+ #include <linux/usbdev_fs_i.h>
++#include <linux/hostfs_fs_i.h>
++#include <linux/hppfs_fs_i.h>
+ #include <linux/jffs2_fs_i.h>
+ #include <linux/cramfs_fs_sb.h>
+
+@@ -516,7 +518,9 @@
+ struct proc_inode_info proc_i;
+ struct socket socket_i;
+ struct usbdev_inode_info usbdev_i;
+- struct jffs2_inode_info jffs2_i;
++ struct hostfs_inode_info hostfs_i;
++ struct hppfs_inode_info hppfs_i;
++ struct jffs2_inode_info jffs2_i;
+ void *generic_ip;
+ } u;
+ };
+@@ -864,6 +868,8 @@
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+ int (*mmap) (struct file *, struct vm_area_struct *);
++ void (*munmap) (struct file *, struct vm_area_struct *,
++ unsigned long start, unsigned long len);
+ int (*open) (struct inode *, struct file *);
+ int (*flush) (struct file *);
+ int (*release) (struct inode *, struct file *);
+diff -Naur -X ../exclude-files orig/include/linux/ghash.h um/include/linux/ghash.h
+--- orig/include/linux/ghash.h 1997-07-07 11:24:28.000000000 -0400
++++ um/include/linux/ghash.h 2003-10-21 03:26:07.000000000 -0400
+@@ -153,6 +153,26 @@
+ return NULL;\
+ }
+
++/* LINKAGE - empty or "static", depending on whether you want the definitions to
++ * be public or not
++ * NAME - a string to stick in names to make this hash table type distinct from
++ * any others
++ * HASHSIZE - number of buckets
++ * TYPE - type of data contained in the buckets - must be a structure, one
++ * field is of type NAME_ptrs, another is the hash key
++ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
++ * field
++ * KEYTYPE - type of the key field within TYPE
++ * KEY - name of the key field within TYPE
++ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
++ * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal,
++ * non-zero for not equal
++ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
++ * it returns a number in the range 0 ... HASHSIZE - 1
++ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
++ * DEF_HASH.
++ */
++
+ #define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+ \
+ struct NAME##_table {\
+@@ -165,7 +185,7 @@
+ TYPE * prev_hash;\
+ };
+
+-#define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
++#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
+ \
+ LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+ {\
+@@ -206,12 +226,10 @@
+ \
+ LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+ {\
+- int ix = hashfn(pos);\
++ int ix = HASHFN(pos);\
+ TYPE * ptr = tbl->hashtable[ix];\
+ while(ptr && KEYCMP(ptr->KEY, pos))\
+ ptr = ptr->PTRS.next_hash;\
+- if(ptr && !KEYEQ(ptr->KEY, pos))\
+- ptr = NULL;\
+ return ptr;\
+ }
+
+diff -Naur -X ../exclude-files orig/include/linux/hostfs_fs_i.h um/include/linux/hostfs_fs_i.h
+--- orig/include/linux/hostfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/linux/hostfs_fs_i.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,21 @@
++#ifndef _HOSTFS_FS_I
++#define _HOSTFS_FS_I
++
++struct hostfs_inode_info {
++ char *host_filename;
++ int fd;
++ int mode;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/linux/hppfs_fs_i.h um/include/linux/hppfs_fs_i.h
+--- orig/include/linux/hppfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/linux/hppfs_fs_i.h 2003-10-21 03:26:07.000000000 -0400
+@@ -0,0 +1,19 @@
++#ifndef _HPPFS_FS_I
++#define _HPPFS_FS_I
++
++struct hppfs_inode_info {
++ struct dentry *proc_dentry;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/include/linux/kernel.h um/include/linux/kernel.h
+--- orig/include/linux/kernel.h 2004-01-11 22:46:12.000000000 -0500
++++ um/include/linux/kernel.h 2004-02-14 06:28:59.000000000 -0500
+@@ -49,7 +49,7 @@
+ # define ATTRIB_NORET __attribute__((noreturn))
+ # define NORET_AND noreturn,
+
+-#ifdef __i386__
++#if defined(__i386__) || defined(UM_FASTCALL)
+ #define FASTCALL(x) x __attribute__((regparm(3)))
+ #else
+ #define FASTCALL(x) x
+diff -Naur -X ../exclude-files orig/include/linux/kernel_stat.h um/include/linux/kernel_stat.h
+--- orig/include/linux/kernel_stat.h 2004-01-11 22:46:12.000000000 -0500
++++ um/include/linux/kernel_stat.h 2004-02-14 06:28:59.000000000 -0500
+@@ -12,7 +12,7 @@
+ * used by rstatd/perfmeter
+ */
+
+-#define DK_MAX_MAJOR 16
++#define DK_MAX_MAJOR 99
+ #define DK_MAX_DISK 16
+
+ struct kernel_stat {
+diff -Naur -X ../exclude-files orig/include/linux/mm.h um/include/linux/mm.h
+--- orig/include/linux/mm.h 2003-12-16 22:16:36.000000000 -0500
++++ um/include/linux/mm.h 2004-02-14 06:28:59.000000000 -0500
+@@ -438,6 +438,18 @@
+ extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist));
+ extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
+
++#ifndef HAVE_ARCH_VALIDATE
++static inline struct page *arch_validate(struct page *page,
++ unsigned int gfp_mask, int order)
++{
++ return(page);
++}
++#endif
++
++#ifndef HAVE_ARCH_FREE_PAGE
++static inline void arch_free_page(struct page *page, int order) { }
++#endif
++
+ static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
+ {
+ /*
+@@ -445,7 +457,7 @@
+ */
+ if (order >= MAX_ORDER)
+ return NULL;
+- return _alloc_pages(gfp_mask, order);
++ return arch_validate(_alloc_pages(gfp_mask, order), gfp_mask, order);
+ }
+
+ #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
+@@ -505,6 +517,9 @@
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc() that does all
+@@ -552,9 +567,10 @@
+
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+- unsigned long len, unsigned long prot,
+- unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++ unsigned long addr, unsigned long len,
++ unsigned long prot, unsigned long flag,
++ unsigned long pgoff);
+
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long prot,
+@@ -564,7 +580,8 @@
+ if ((offset + PAGE_ALIGN(len)) < offset)
+ goto out;
+ if (!(offset & ~PAGE_MASK))
+- ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++ ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag,
++ offset >> PAGE_SHIFT);
+ out:
+ return ret;
+ }
+diff -Naur -X ../exclude-files orig/include/linux/proc_mm.h um/include/linux/proc_mm.h
+--- orig/include/linux/proc_mm.h 1969-12-31 19:00:00.000000000 -0500
++++ um/include/linux/proc_mm.h 2004-02-14 06:30:22.000000000 -0500
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++ unsigned long addr;
++ unsigned long len;
++ unsigned long prot;
++ unsigned long flags;
++ unsigned long fd;
++ unsigned long offset;
++};
++
++struct mm_munmap {
++ unsigned long addr;
++ unsigned long len;
++};
++
++struct mm_mprotect {
++ unsigned long addr;
++ unsigned long len;
++ unsigned int prot;
++};
++
++struct proc_mm_op {
++ int op;
++ union {
++ struct mm_mmap mmap;
++ struct mm_munmap munmap;
++ struct mm_mprotect mprotect;
++ int copy_segments;
++ } u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+diff -Naur -X ../exclude-files orig/include/linux/shmem_fs.h um/include/linux/shmem_fs.h
+--- orig/include/linux/shmem_fs.h 2003-09-02 15:44:03.000000000 -0400
++++ um/include/linux/shmem_fs.h 2003-12-09 00:03:31.000000000 -0500
+@@ -22,6 +22,8 @@
+ unsigned long next_index;
+ swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
+ void **i_indirect; /* indirect blocks */
++ unsigned long map_direct[SHMEM_NR_DIRECT];
++ void **map_indirect;
+ unsigned long swapped; /* data pages assigned to swap */
+ unsigned long flags;
+ struct list_head list;
+diff -Naur -X ../exclude-files orig/include/linux/tty.h um/include/linux/tty.h
+--- orig/include/linux/tty.h 2004-01-11 22:46:12.000000000 -0500
++++ um/include/linux/tty.h 2004-02-14 06:28:59.000000000 -0500
+@@ -309,6 +309,9 @@
+ spinlock_t read_lock;
+ /* If the tty has a pending do_SAK, queue it here - akpm */
+ struct tq_struct SAK_tq;
++#ifdef CONFIG_TTY_LOG
++ int log_fd;
++#endif
+ };
+
+ /* tty magic number */
+@@ -365,6 +368,7 @@
+ extern int specialix_init(void);
+ extern int espserial_init(void);
+ extern int macserial_init(void);
++extern int stdio_init(void);
+ extern int a2232board_init(void);
+
+ extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
+@@ -420,5 +424,7 @@
+ extern int vt_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+
++extern void stdio_console_init(void);
++
+ #endif /* __KERNEL__ */
+ #endif
+diff -Naur -X ../exclude-files orig/init/do_mounts.c um/init/do_mounts.c
+--- orig/init/do_mounts.c 2003-12-16 22:16:36.000000000 -0500
++++ um/init/do_mounts.c 2003-12-16 22:17:32.000000000 -0500
+@@ -154,6 +154,22 @@
+ { "pf", 0x2f00 },
+ { "apblock", APBLOCK_MAJOR << 8},
+ { "ddv", DDV_MAJOR << 8},
++ { "ubd0", UBD_MAJOR << 8 | 0 << 4},
++ { "ubda", UBD_MAJOR << 8 | 0 << 4},
++ { "ubd1", UBD_MAJOR << 8 | 1 << 4},
++ { "ubdb", UBD_MAJOR << 8 | 1 << 4},
++ { "ubd2", UBD_MAJOR << 8 | 2 << 4},
++ { "ubdc", UBD_MAJOR << 8 | 2 << 4},
++ { "ubd3", UBD_MAJOR << 8 | 3 << 4},
++ { "ubdd", UBD_MAJOR << 8 | 3 << 4},
++ { "ubd4", UBD_MAJOR << 8 | 4 << 4},
++ { "ubde", UBD_MAJOR << 8 | 4 << 4},
++ { "ubd5", UBD_MAJOR << 8 | 5 << 4},
++ { "ubdf", UBD_MAJOR << 8 | 5 << 4},
++ { "ubd6", UBD_MAJOR << 8 | 6 << 4},
++ { "ubdg", UBD_MAJOR << 8 | 6 << 4},
++ { "ubd7", UBD_MAJOR << 8 | 7 << 4},
++ { "ubdh", UBD_MAJOR << 8 | 7 << 4},
+ { "jsfd", JSFD_MAJOR << 8},
+ #if defined(CONFIG_ARCH_S390)
+ { "dasda", (DASD_MAJOR << MINORBITS) },
+diff -Naur -X ../exclude-files orig/kernel/panic.c um/kernel/panic.c
+--- orig/kernel/panic.c 2003-12-16 22:16:36.000000000 -0500
++++ um/kernel/panic.c 2003-12-16 22:17:32.000000000 -0500
+@@ -74,7 +74,7 @@
+ smp_send_stop();
+ #endif
+
+- notifier_call_chain(&panic_notifier_list, 0, NULL);
++ notifier_call_chain(&panic_notifier_list, 0, buf);
+
+ if (panic_timeout > 0)
+ {
+diff -Naur -X ../exclude-files orig/MAINTAINERS um/MAINTAINERS
+--- orig/MAINTAINERS 2003-12-16 22:16:23.000000000 -0500
++++ um/MAINTAINERS 2003-12-16 22:17:22.000000000 -0500
+@@ -2055,6 +2055,14 @@
+ L: linux-usb-devel@lists.sourceforge.net
+ W: http://usb.in.tum.de
+ S: Maintained
++
++USER-MODE PORT
++P: Jeff Dike
++M: jdike@karaya.com
++L: user-mode-linux-devel@lists.sourceforge.net
++L: user-mode-linux-user@lists.sourceforge.net
++W: http://user-mode-linux.sourceforge.net
++S: Maintained
+
+ USB "USBNET" DRIVER
+ P: David Brownell
+diff -Naur -X ../exclude-files orig/Makefile um/Makefile
+--- orig/Makefile 2004-02-14 06:26:12.000000000 -0500
++++ um/Makefile 2004-02-14 06:26:19.000000000 -0500
+@@ -5,7 +5,15 @@
+
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
+-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++# SUBARCH tells the usermode build what the underlying arch is. That is set
++# first, and if a usermode build is happening, the "ARCH=um" on the command
++# line overrides the setting of ARCH below. If a native build is happening,
++# then ARCH is assigned, getting whatever value it gets normally, and
++# SUBARCH is subsequently ignored.
++
++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++ARCH := $(SUBARCH)
++
+ KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+
+ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+diff -Naur -X ../exclude-files orig/mm/Makefile um/mm/Makefile
+--- orig/mm/Makefile 2002-08-21 11:47:43.000000000 -0400
++++ um/mm/Makefile 2003-10-21 03:26:08.000000000 -0400
+@@ -17,5 +17,6 @@
+ shmem.o
+
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+
+ include $(TOPDIR)/Rules.make
+diff -Naur -X ../exclude-files orig/mm/mmap.c um/mm/mmap.c
+--- orig/mm/mmap.c 2003-12-16 22:16:36.000000000 -0500
++++ um/mm/mmap.c 2003-12-16 22:17:32.000000000 -0500
+@@ -390,10 +390,11 @@
+ return 0;
+ }
+
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++ unsigned long addr, unsigned long len,
++ unsigned long prot, unsigned long flags,
++ unsigned long pgoff)
+ {
+- struct mm_struct * mm = current->mm;
+ struct vm_area_struct * vma, * prev;
+ unsigned int vm_flags;
+ int correct_wcount = 0;
+@@ -994,6 +995,11 @@
+ remove_shared_vm_struct(mpnt);
+ mm->map_count--;
+
++ if((mpnt->vm_file != NULL) && (mpnt->vm_file->f_op != NULL) &&
++ (mpnt->vm_file->f_op->munmap != NULL))
++ mpnt->vm_file->f_op->munmap(mpnt->vm_file, mpnt, st,
++ size);
++
+ zap_page_range(mm, st, size);
+
+ /*
+diff -Naur -X ../exclude-files orig/mm/mprotect.c um/mm/mprotect.c
+--- orig/mm/mprotect.c 2003-12-16 22:16:36.000000000 -0500
++++ um/mm/mprotect.c 2003-12-16 22:17:32.000000000 -0500
+@@ -264,7 +264,8 @@
+ return 0;
+ }
+
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++ unsigned long prot)
+ {
+ unsigned long nstart, end, tmp;
+ struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +282,9 @@
+ if (end == start)
+ return 0;
+
+- down_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
+
+- vma = find_vma_prev(current->mm, start, &prev);
++ vma = find_vma_prev(mm, start, &prev);
+ error = -ENOMEM;
+ if (!vma || vma->vm_start > start)
+ goto out;
+@@ -332,6 +333,11 @@
+ prev->vm_mm->map_count--;
+ }
+ out:
+- up_write(¤t->mm->mmap_sem);
++ up_write(&mm->mmap_sem);
+ return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++ return(do_mprotect(current->mm, start, len, prot));
++}
+diff -Naur -X ../exclude-files orig/mm/page_alloc.c um/mm/page_alloc.c
+--- orig/mm/page_alloc.c 2003-12-16 22:16:36.000000000 -0500
++++ um/mm/page_alloc.c 2003-12-16 22:17:32.000000000 -0500
+@@ -89,6 +89,7 @@
+ struct page *base;
+ zone_t *zone;
+
++ arch_free_page(page, order);
+ /*
+ * Yes, think what happens when other parts of the kernel take
+ * a reference to a page in order to pin it for io. -ben
+diff -Naur -X ../exclude-files orig/mm/proc_mm.c um/mm/proc_mm.c
+--- orig/mm/proc_mm.c 1969-12-31 19:00:00.000000000 -0500
++++ um/mm/proc_mm.c 2003-10-21 03:26:08.000000000 -0400
+@@ -0,0 +1,173 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++ struct mm_struct *ret = ERR_PTR(-EBADF);
++ struct file *file;
++
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ ret = ERR_PTR(-EINVAL);
++ if(file->f_op != &proc_mm_fops)
++ goto out_fput;
++
++ ret = file->private_data;
++ out_fput:
++ fput(file);
++ out:
++ return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct mm_struct *mm = file->private_data;
++ struct proc_mm_op req;
++ int n, ret;
++
++ if(count > sizeof(req))
++ return(-EINVAL);
++
++ n = copy_from_user(&req, buffer, count);
++ if(n != 0)
++ return(-EFAULT);
++
++ ret = count;
++ switch(req.op){
++ case MM_MMAP: {
++ struct mm_mmap *map = &req.u.mmap;
++
++ ret = do_mmap2(mm, map->addr, map->len, map->prot,
++ map->flags, map->fd, map->offset >> PAGE_SHIFT);
++ if((ret & ~PAGE_MASK) == 0)
++ ret = count;
++
++ break;
++ }
++ case MM_MUNMAP: {
++ struct mm_munmap *unmap = &req.u.munmap;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, unmap->addr, unmap->len);
++ up_write(&mm->mmap_sem);
++
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++ case MM_MPROTECT: {
++ struct mm_mprotect *protect = &req.u.mprotect;
++
++ ret = do_mprotect(mm, protect->addr, protect->len,
++ protect->prot);
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++
++ case MM_COPY_SEGMENTS: {
++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++ if(IS_ERR(from)){
++ ret = PTR_ERR(from);
++ break;
++ }
++
++ mm_copy_segments(from, mm);
++ break;
++ }
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++ struct mm_struct *mm = mm_alloc();
++ int ret;
++
++ ret = -ENOMEM;
++ if(mm == NULL)
++ goto out_mem;
++
++ ret = init_new_context(current, mm);
++ if(ret)
++ goto out_free;
++
++ spin_lock(&mmlist_lock);
++ list_add(&mm->mmlist, ¤t->mm->mmlist);
++ mmlist_nr++;
++ spin_unlock(&mmlist_lock);
++
++ file->private_data = mm;
++
++ return(0);
++
++ out_free:
++ mmput(mm);
++ out_mem:
++ return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++ struct mm_struct *mm = file->private_data;
++
++ mmput(mm);
++ return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++ .open = open_proc_mm,
++ .release = release_proc_mm,
++ .write = write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++ struct proc_dir_entry *ent;
++
++ ent = create_proc_entry("mm", 0222, &proc_root);
++ if(ent == NULL){
++ printk("make_proc_mm : Failed to register /proc/mm\n");
++ return(0);
++ }
++ ent->proc_fops = &proc_mm_fops;
++
++ return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur -X ../exclude-files orig/mm/shmem.c um/mm/shmem.c
+--- orig/mm/shmem.c 2003-12-16 22:16:36.000000000 -0500
++++ um/mm/shmem.c 2003-12-16 22:17:32.000000000 -0500
+@@ -128,16 +128,17 @@
+ * +-> 48-51
+ * +-> 52-55
+ */
+-static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page)
++static void *shmem_block(unsigned long index, unsigned long *page,
++ unsigned long *direct, void ***indirect)
+ {
+ unsigned long offset;
+ void **dir;
+
+ if (index < SHMEM_NR_DIRECT)
+- return info->i_direct+index;
+- if (!info->i_indirect) {
++ return direct+index;
++ if (!*indirect) {
+ if (page) {
+- info->i_indirect = (void **) *page;
++ *indirect = (void **) *page;
+ *page = 0;
+ }
+ return NULL; /* need another page */
+@@ -146,7 +147,7 @@
+ index -= SHMEM_NR_DIRECT;
+ offset = index % ENTRIES_PER_PAGE;
+ index /= ENTRIES_PER_PAGE;
+- dir = info->i_indirect;
++ dir = *indirect;
+
+ if (index >= ENTRIES_PER_PAGE/2) {
+ index -= ENTRIES_PER_PAGE/2;
+@@ -169,7 +170,21 @@
+ *dir = (void *) *page;
+ *page = 0;
+ }
+- return (swp_entry_t *) *dir + offset;
++ return (unsigned long **) *dir + offset;
++}
++
++static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page)
++{
++ return((swp_entry_t *) shmem_block(index, page,
++ (unsigned long *) info->i_direct,
++ &info->i_indirect));
++}
++
++static unsigned long *shmem_map_count(struct shmem_inode_info *info,
++ unsigned long index, unsigned long *page)
++{
++ return((unsigned long *) shmem_block(index, page, info->map_direct,
++ &info->map_indirect));
+ }
+
+ /*
+@@ -838,6 +853,7 @@
+ ops = &shmem_vm_ops;
+ if (!S_ISREG(inode->i_mode))
+ return -EACCES;
++
+ UPDATE_ATIME(inode);
+ vma->vm_ops = ops;
+ return 0;
+@@ -1723,4 +1739,125 @@
+ return 0;
+ }
+
++static int adjust_map_counts(struct shmem_inode_info *info,
++ unsigned long offset, unsigned long len,
++ int adjust)
++{
++ unsigned long idx, i, *count, page = 0;
++
++ spin_lock(&info->lock);
++ offset >>= PAGE_SHIFT;
++ len >>= PAGE_SHIFT;
++ for(i = 0; i < len; i++){
++ idx = (i + offset) >> (PAGE_CACHE_SHIFT - PAGE_SHIFT);
++
++ while((count = shmem_map_count(info, idx, &page)) == NULL){
++ spin_unlock(&info->lock);
++ page = get_zeroed_page(GFP_KERNEL);
++ if(page == 0)
++ return(-ENOMEM);
++ spin_lock(&info->lock);
++ }
++
++ if(page != 0)
++ free_page(page);
++
++ *count += adjust;
++ }
++ spin_unlock(&info->lock);
++ return(0);
++}
++
+ EXPORT_SYMBOL(shmem_file_setup);
++
++struct file_operations anon_file_operations;
++
++static int anon_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct file *new;
++ struct inode *inode;
++ loff_t size = vma->vm_end - vma->vm_start;
++ int err;
++
++ if(file->private_data == NULL){
++ new = shmem_file_setup("dev/anon", size);
++ if(IS_ERR(new))
++ return(PTR_ERR(new));
++
++ new->f_op = &anon_file_operations;
++ file->private_data = new;
++ }
++
++ if (vma->vm_file)
++ fput(vma->vm_file);
++ vma->vm_file = file->private_data;
++ get_file(vma->vm_file);
++
++ inode = vma->vm_file->f_dentry->d_inode;
++ err = adjust_map_counts(SHMEM_I(inode), vma->vm_pgoff, size, 1);
++ if(err)
++ return(err);
++
++ vma->vm_ops = &shmem_vm_ops;
++ return 0;
++}
++
++static void anon_munmap(struct file *file, struct vm_area_struct *vma,
++ unsigned long start, unsigned long len)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ struct shmem_inode_info *info = SHMEM_I(inode);
++ pgd_t *pgd;
++ pmd_t *pmd;
++ pte_t *pte;
++ struct page *page;
++ unsigned long addr, idx, *count;
++
++ for(addr = start; addr < start + len; addr += PAGE_SIZE){
++ idx = (addr - vma->vm_start + vma->vm_pgoff);
++ idx >>= PAGE_CACHE_SHIFT;
++
++ count = shmem_map_count(info, idx, NULL);
++ BUG_ON(count == NULL);
++
++ (*count)--;
++ if(*count > 0)
++ continue;
++
++ pgd = pgd_offset(vma->vm_mm, addr);
++ if(pgd_none(*pgd))
++ continue;
++
++ pmd = pmd_offset(pgd, addr);
++ if(pmd_none(*pmd))
++ continue;
++
++ pte = pte_offset(pmd, addr);
++ if(!pte_present(*pte)) /* XXX need to handle swapped pages */
++ continue;
++
++ *pte = pte_mkclean(*pte);
++
++ page = pte_page(*pte);
++ LockPage(page);
++ lru_cache_del(page);
++ ClearPageDirty(page);
++ remove_inode_page(page);
++ UnlockPage(page);
++
++ page_cache_release(page);
++ }
++}
++
++int anon_release(struct inode *inode, struct file *file)
++{
++ if(file->private_data != NULL)
++ fput(file->private_data);
++ return(0);
++}
++
++struct file_operations anon_file_operations = {
++ .mmap = anon_mmap,
++ .munmap = anon_munmap,
++ .release = anon_release,
++};