Index: linux-2.4.29/arch/um/config_block.in =================================================================== --- linux-2.4.29.orig/arch/um/config_block.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config_block.in 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/config_char.in =================================================================== --- linux-2.4.29.orig/arch/um/config_char.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config_char.in 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/config.in =================================================================== --- linux-2.4.29.orig/arch/um/config.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config.in 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,123 @@ +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 'Usable host filesystem' CONFIG_HUMFS + +if [ "$CONFIG_HOSTFS" = "y" -o "$CONFIG_HUMFS" = "y" ]; then + define_tristate CONFIG_EXTERNFS y +fi + +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 +if [ "$CONFIG_SMP" = "y" ]; then + int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 +fi + +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 + +source crypto/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 + +if [ "$CONFIG_MODE_TT" = "n" ]; then + dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM +fi + +dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM +endmenu Index: linux-2.4.29/arch/um/config_net.in =================================================================== --- linux-2.4.29.orig/arch/um/config_net.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config_net.in 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,48 @@ +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 + dep_tristate ' PPP MPPE compression (encryption)' CONFIG_PPP_MPPE $CONFIG_PPP +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 Index: linux-2.4.29/arch/um/config.release =================================================================== --- linux-2.4.29.orig/arch/um/config.release 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config.release 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/config_scsi.in =================================================================== --- linux-2.4.29.orig/arch/um/config_scsi.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/config_scsi.in 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/defconfig =================================================================== --- linux-2.4.29.orig/arch/um/defconfig 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/defconfig 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,430 @@ +# +# 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_HUMFS=y +CONFIG_EXTERNFS=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_PPP_MPPE 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=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 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=y +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 +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG 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_GCOV is not set Index: linux-2.4.29/arch/um/drivers/chan_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/chan_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/chan_kern.c 2005-05-03 22:28:14.196452024 +0300 @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "chan_kern.h" +#include "user_util.h" +#include "kern.h" +#include "irq_user.h" +#include "sigio.h" +#include "line.h" +#include "os.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, +}; + +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_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 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: + */ Index: linux-2.4.29/arch/um/drivers/chan_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/chan_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/chan_user.c 2005-05-03 22:28:14.197451872 +0300 @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kern_util.h" +#include "user_util.h" +#include "chan_user.h" +#include "user.h" +#include "helper.h" +#include "os.h" +#include "choose-mode.h" +#include "mode.h" + +static void winch_handler(int sig) +{ +} + +struct winch_data { + int pty_fd; + int pipe_fd; + int close_me; +}; + +/* XXX This breaks horribly (by hanging UML) when moved to chan_kern.c - + * needs investigation + */ +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); +} + +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: + */ Index: linux-2.4.29/arch/um/drivers/cow.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/cow.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/cow.h 2005-05-03 22:43:32.718815400 +0300 @@ -0,0 +1,41 @@ +#ifndef __COW_H__ +#define __COW_H__ + +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +# define ntohll(x) (x) +# define htonll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define ntohll(x) bswap_64(x) +# define htonll(x) bswap_64(x) +#else +#error "__BYTE_ORDER not defined" +#endif + +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: + */ Index: linux-2.4.29/arch/um/drivers/cow_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/cow_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/cow_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,630 @@ +#define COW_MAJOR 60 +#define MAJOR_NR COW_MAJOR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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: + */ Index: linux-2.4.29/arch/um/drivers/cow_sys.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/cow_sys.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/cow_sys.h 2005-05-03 22:43:34.768503800 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/cow_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/cow_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/cow_user.c 2005-05-03 22:28:14.203450960 +0300 @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 { + __u32 magic; + __u32 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: + */ Index: linux-2.4.29/arch/um/drivers/daemon.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/daemon.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/daemon.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/daemon_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/daemon_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/daemon_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/daemon_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/daemon_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/daemon_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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 +#include +#include +#include +#include +#include +#include "net_user.h" +#include "daemon.h" +#include "kern_util.h" +#include "user_util.h" +#include "user.h" +#include "os.h" + +#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) + +enum request_type { REQ_NEW_CONTROL }; + +#define SWITCH_MAGIC 0xfeedface + +struct request_v3 { + 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: + */ Index: linux-2.4.29/arch/um/drivers/fd.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/fd.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/fd.c 2005-05-03 22:28:14.208450200 +0300 @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include "user.h" +#include "user_util.h" +#include "chan_user.h" + +struct fd_chan { + int fd; + int raw; + struct termios tt; + 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; + int err; + + if(data->raw && isatty(data->fd)){ + CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); + if(err) + return(err); + + err = raw(data->fd); + if(err) + return(err); + } + 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; + int err; + + if(data->raw && isatty(fd)){ + CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); + if(err) + printk("Failed to restore terminal state - " + "errno = %d\n", -err); + 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: + */ Index: linux-2.4.29/arch/um/drivers/harddog_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/harddog_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/harddog_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,194 @@ +/* UML hardware watchdog, shamelessly stolen from: + * + * SoftDog 0.05: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * Software only watchdog driver. Unlike its big brother the WDT501P + * driver this won't always recover a failed machine. + * + * 03/96: Angelo Haritsis : + * Modularised. + * Added soft_margin; use upon insmod to change the timer delay. + * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate + * minors. + * + * 19980911 Alan Cox + * Made SMP safe for 2.3.x + * + * 20011127 Joel Becker (jlbec@evilplan.org> + * Added soft_noboot; Allows testing the softdog trigger without + * requiring a recompile. + * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "helper.h" +#include "mconsole.h" + +MODULE_LICENSE("GPL"); + +/* 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: + */ Index: linux-2.4.29/arch/um/drivers/harddog_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/harddog_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/harddog_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include "user_util.h" +#include "user.h" +#include "helper.h" +#include "mconsole.h" +#include "os.h" +#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: + */ Index: linux-2.4.29/arch/um/drivers/hostaudio_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/hostaudio_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/hostaudio_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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=\n" DSP_HELP); + +static int set_mixer(char *name, int *add) +{ + mixer = name; + return(0); +} + +__uml_setup("mixer=", set_mixer, "mixer=\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: + */ Index: linux-2.4.29/arch/um/drivers/line.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/line.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/line.c 2005-05-03 22:28:14.214449288 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/drivers/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/Makefile 2005-05-03 22:28:14.215449136 +0300 @@ -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) Index: linux-2.4.29/arch/um/drivers/mcast.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mcast.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mcast.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/mcast_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mcast_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mcast_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,145 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + */ + +#include "linux/kernel.h" +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/etherdevice.h" +#include "linux/in.h" +#include "linux/inet.h" +#include "net_kern.h" +#include "net_user.h" +#include "mcast.h" + +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: + */ Index: linux-2.4.29/arch/um/drivers/mcast_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mcast_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mcast_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,177 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "net_user.h" +#include "mcast.h" +#include "kern_util.h" +#include "user_util.h" +#include "user.h" +#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: + */ Index: linux-2.4.29/arch/um/drivers/mconsole_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mconsole_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mconsole_kern.c 2005-05-03 22:28:14.222448072 +0300 @@ -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); + +static void mc_task_proc(void *unused) +{ + struct mconsole_entry *req; + unsigned long flags; + + while(!list_empty(&mc_requests)){ + local_irq_save(flags); + req = list_entry(mc_requests.next, struct mconsole_entry, + list); + list_del(&req->list); + local_irq_restore(flags); + req->request.cmd->handler(&req->request); + kfree(req); + } +} + +struct tq_struct mconsole_task = { + .routine = mc_task_proc, + .data = NULL +}; + +static 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 = - Add a new device to UML; \n\ + same syntax as command line \n\ + config - Query the configuration of a device \n\ + remove - Remove a device from UML \n\ + sysrq - 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 - make UML enter into the kernel log\n\ + proc - returns the contents of the UML's /proc/\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:\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: + */ Index: linux-2.4.29/arch/um/drivers/mconsole_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mconsole_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mconsole_user.c 2005-05-03 22:28:14.223447920 +0300 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "mconsole.h" +#include "umid.h" + +static struct mconsole_command commands[] = { + { "version", mconsole_version, 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;irequest.data, cmd->command, + strlen(cmd->command))){ + return(cmd); + } + } + return(NULL); +} + +#define MIN(a,b) ((a)<(b) ? (a):(b)) + +#define STRINGX(x) #x +#define STRING(x) STRINGX(x) + +int mconsole_get_request(int fd, struct mc_request *req) +{ + int len; + + req->originlen = sizeof(req->origin); + req->len = recvfrom(fd, &req->request, sizeof(req->request), 0, + (struct sockaddr *) req->origin, &req->originlen); + if (req->len < 0) + return 0; + + req->originating_fd = fd; + + if(req->request.magic != MCONSOLE_MAGIC){ + /* Unversioned request */ + len = MIN(sizeof(req->request.data) - 1, + strlen((char *) &req->request)); + memmove(req->request.data, &req->request, len); + req->request.data[len] = '\0'; + + req->request.magic = MCONSOLE_MAGIC; + req->request.version = 0; + req->request.len = len; + + mconsole_reply_v0(req, "ERR Version 0 mconsole clients are " + "not supported by this driver"); + return(0); + } + + if(req->request.len >= MCONSOLE_MAX_DATA){ + mconsole_reply(req, "Request too large", 1, 0); + return(0); + } + if(req->request.version != MCONSOLE_VERSION){ + mconsole_reply(req, "This driver only supports version " + STRING(MCONSOLE_VERSION) " clients", 1, 0); + } + + req->request.data[req->request.len] = '\0'; + req->cmd = mconsole_parse(req); + if(req->cmd == NULL){ + mconsole_reply(req, "Unknown command", 1, 0); + return(0); + } + + return(1); +} + +int mconsole_reply(struct mc_request *req, char *str, int err, int more) +{ + struct mconsole_reply reply; + int total, len, n; + + total = strlen(str); + do { + reply.err = err; + + /* err can only be true on the first packet */ + err = 0; + + len = MIN(total, MCONSOLE_MAX_DATA - 1); + + if(len == total) reply.more = more; + else reply.more = 1; + + memcpy(reply.data, str, len); + reply.data[len] = '\0'; + total -= len; + 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: + */ Index: linux-2.4.29/arch/um/drivers/mmapper_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/mmapper_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/mmapper_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 "); +MODULE_DESCRIPTION("DSPLinux simulator mmapper driver"); +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/drivers/net_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/net_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/net_kern.c 2005-05-03 22:28:14.228447160 +0300 @@ -0,0 +1,903 @@ +/* + * 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 "linux/ethtool.h" +#include "asm/uaccess.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); + /* clear buffer - it can happen that the host side of the interface + * is full when we get here. In this case, new data is never queued, + * SIGIOs never arrive, and the net never works. + */ + while((err = uml_net_rx(dev)) > 0) ; + + 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) +{ + static const struct ethtool_drvinfo info = { + .cmd = ETHTOOL_GDRVINFO, + .driver = "uml virtual ethernet", + .version = "42", + }; + void *useraddr; + u32 ethcmd; + + switch (cmd) { + case SIOCETHTOOL: + useraddr = ifr->ifr_data; + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + default: + return -EOPNOTSUPP; + } + default: + 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]+=,\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: + */ Index: linux-2.4.29/arch/um/drivers/net_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/net_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/net_user.c 2005-05-03 22:28:14.229447008 +0300 @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user.h" +#include "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); + + read_output(fds[0], output, output_len); + os_close_file(fds[0]); + os_close_file(fds[1]); + CATCH_EINTR(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: + */ Index: linux-2.4.29/arch/um/drivers/null.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/null.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/null.c 2005-05-03 22:28:14.230446856 +0300 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "chan_user.h" +#include "os.h" + +static int null_chan; + +void *null_init(char *str, int device, struct chan_opts *opts) +{ + return(&null_chan); +} + +int null_open(int input, int output, int primary, void *d, 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: + */ Index: linux-2.4.29/arch/um/drivers/pcap_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/pcap_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/pcap_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2002 Jeff Dike + * 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: + */ Index: linux-2.4.29/arch/um/drivers/pcap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/pcap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/pcap_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2002 Jeff Dike + * Licensed under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#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: + */ Index: linux-2.4.29/arch/um/drivers/pcap_user.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/pcap_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/pcap_user.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/port.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/port.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/port.h 2005-05-03 22:28:14.234446248 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/port_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/port_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/port_kern.c 2005-05-03 22:28:14.235446096 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/port_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/port_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/port_user.c 2005-05-03 22:28:14.237445792 +0300 @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "chan_user.h" +#include "port.h" +#include "helper.h" +#include "os.h" + +struct port_chan { + int raw; + struct termios tt; + void *kernel_data; + 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, err; + + fd = port_wait(data->kernel_data); + if((fd >= 0) && data->raw){ + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); + } + *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, arg; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if(fd == -1) + return(-errno); + + arg = 1; + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ + err = -errno; + goto out; + } + + 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: + */ Index: linux-2.4.29/arch/um/drivers/pty.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/pty.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/pty.c 2005-05-03 22:28:14.238445640 +0300 @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#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, err; + + fd = get_pty(); + if(fd < 0){ + printk("open_pts : Failed to open pts\n"); + return(-errno); + } + if(data->raw){ + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); + } + + 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, err; + char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; + + fd = getmaster(dev); + if(fd < 0) + return(-errno); + + if(data->raw){ + err = raw(fd); + if(err) + return(err); + } + + 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: + */ Index: linux-2.4.29/arch/um/drivers/slip.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slip.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slip.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/slip_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slip_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slip_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/slip_proto.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slip_proto.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slip_proto.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/slip_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slip_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slip_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,276 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "net_user.h" +#include "slip.h" +#include "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); + } + CATCH_EINTR(err = waitpid(pid, &status, 0)); + if(err < 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: + */ Index: linux-2.4.29/arch/um/drivers/slirp.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slirp.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slirp.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/slirp_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slirp_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slirp_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/slirp_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/slirp_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/slirp_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "net_user.h" +#include "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 + + CATCH_EINTR(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: + */ Index: linux-2.4.29/arch/um/drivers/ssl.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/ssl.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/ssl.c 2005-05-03 22:28:14.247444272 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/ssl.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/ssl.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/ssl.h 2005-05-03 22:28:14.248444120 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/stdio_console.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/stdio_console.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/stdio_console.c 2005-05-03 22:28:14.249443968 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/stdio_console.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/stdio_console.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/stdio_console.h 2005-05-03 22:28:14.250443816 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/tty.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/tty.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/tty.c 2005-05-03 22:28:14.251443664 +0300 @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include "chan_user.h" +#include "user_util.h" +#include "user.h" +#include "os.h" + +struct tty_chan { + char *dev; + int raw; + struct termios tt; +}; + +void *tty_chan_init(char *str, int device, struct chan_opts *opts) +{ + struct tty_chan *data; + + if(*str != ':'){ + printk("tty_init : channel type 'tty' must specify " + "a device\n"); + return(NULL); + } + str++; + + 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, err; + + fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); + if(fd < 0) return(fd); + if(data->raw){ + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); + } + + *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: + */ Index: linux-2.4.29/arch/um/drivers/ubd_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/ubd_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/ubd_kern.c 2005-05-03 22:28:14.257442752 +0300 @@ -0,0 +1,1380 @@ +/* + * 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" +" 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;ifd); + 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, dev->fd, io_req->offset + dev->cow.data_offset)){ + 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_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, int is_user) +{ + __u64 bitmap_offset; + unsigned long new_bitmap[2]; + int i, err, n; + + /* This can only fix kernelspace faults */ + if(is_user) + return(0); + + /* ubd-mmap is only enabled in skas mode */ + if(CHOOSE_MODE(1, 0)) + return(0); + + /* 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: + */ Index: linux-2.4.29/arch/um/drivers/ubd_user.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/ubd_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/ubd_user.c 2005-05-03 22:28:14.259442448 +0300 @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "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 +#include + +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_major == buf2.ust_major) && + (buf1.ust_minor == buf2.ust_minor) && + (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: + */ Index: linux-2.4.29/arch/um/drivers/xterm.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/xterm.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/xterm.c 2005-05-03 22:28:14.260442296 +0300 @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kern_util.h" +#include "chan_user.h" +#include "helper.h" +#include "user_util.h" +#include "user.h" +#include "os.h" +#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=,,<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" +); + +/* XXX This badly needs some cleaning up in the error paths */ +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; + } + + CATCH_EINTR(err = tcgetattr(new, &data->tt)); + if(err){ + new = err; + goto out; + } + + if(data->raw){ + err = raw(new); + if(err){ + new = err; + goto out; + } + } + + 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: + */ Index: linux-2.4.29/arch/um/drivers/xterm.h =================================================================== --- linux-2.4.29.orig/arch/um/drivers/xterm.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/xterm.h 2005-05-03 22:28:14.261442144 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/drivers/xterm_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/drivers/xterm_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/drivers/xterm_kern.c 2005-05-03 22:28:14.262441992 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/fs/hostfs/externfs.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/externfs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/externfs.c 2005-05-03 22:28:14.269440928 +0300 @@ -0,0 +1,1283 @@ +/* + * Copyright (C) 2000 - 2004 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 "mem.h" +#include "filehandle.h" + +struct externfs { + struct list_head list; + struct externfs_mount_ops *mount_ops; + struct file_system_type type; +}; + +static inline struct externfs_inode *EXTERNFS_I(struct inode *inode) +{ + return(inode->u.generic_ip); +} + +#define file_externfs_i(file) EXTERNFS_I((file)->f_dentry->d_inode) + +int externfs_d_delete(struct dentry *dentry) +{ + return(1); +} + +struct dentry_operations externfs_dentry_ops = { +}; + +#define EXTERNFS_SUPER_MAGIC 0x00c0ffee + +static struct inode_operations externfs_iops; +static struct inode_operations externfs_dir_iops; +static struct address_space_operations externfs_link_aops; + +static char *dentry_name(struct dentry *dentry, int extra) +{ + struct dentry *parent; + char *name; + int len; + + len = 0; + parent = dentry; + while(parent->d_parent != parent){ + len += parent->d_name.len + 1; + parent = parent->d_parent; + } + + 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; + } + + return(name); +} + +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)); +} + +char *inode_name_prefix(struct inode *inode, char *prefix) +{ + int len; + char *name; + + len = strlen(prefix); + name = inode_name(inode, len); + if(name == NULL) + return(name); + + memmove(&name[len], name, strlen(name) + 1); + memcpy(name, prefix, strlen(prefix)); + return(name); +} + +static int read_name(struct inode *ino, char *name) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + /* 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 = (*ops->stat_file)(name, ino->i_sb->u.generic_sbp, + (dev_t *) &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; + return(0); +} + +static char *follow_link(char *link, + int (*do_read_link)(char *path, int uid, int gid, + char *buf, int size, + struct externfs_data *ed), + int uid, int gid, struct externfs_data *ed) +{ + 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_read_link)(link, uid, gid, name, len, ed); + 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); + return(resolved); + + out_free: + kfree(name); + out: + return(ERR_PTR(n)); +} + +static int read_inode(struct inode *ino) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *name, *new; + int err, type; + + err = -ENOMEM; + name = inode_name(ino, 0); + if(name == NULL) + goto out; + + type = (*ops->file_type)(name, NULL, ed); + if(type < 0){ + err = type; + goto out_free; + } + + if(type == OS_TYPE_SYMLINK){ + new = follow_link(name, ops->read_link, current->fsuid, + current->fsgid, ed); + if(IS_ERR(new)){ + err = PTR_ERR(new); + goto out_free; + } + kfree(name); + name = new; + } + + err = read_name(ino, name); + out_free: + kfree(name); + out: + return(err); +} + +void externfs_delete_inode(struct inode *ino) +{ + struct externfs_inode *ext = EXTERNFS_I(ino); + struct externfs_file_ops *ops = ext->ops; + + (*ops->close_file)(ext, ino->i_size); + + clear_inode(ino); +} + +int externfs_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; + struct externfs_data *ed = sb->u.generic_sbp; + + err = (*ed->file_ops->statfs)(&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, ed); + 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 = EXTERNFS_SUPER_MAGIC; + return(0); +} + +static struct super_operations externfs_sbops = { + .delete_inode = externfs_delete_inode, + .statfs = externfs_statfs, +}; + +int externfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + void *dir; + char *name; + unsigned long long next, ino; + int error, len; + struct externfs_file_ops *ops = file_externfs_i(file)->ops; + struct externfs_data *ed = + file->f_dentry->d_inode->i_sb->u.generic_sbp; + + name = dentry_name(file->f_dentry, 0); + if(name == NULL) + return(-ENOMEM); + + dir = (*ops->open_dir)(name, current->fsuid, current->fsgid, ed); + kfree(name); + if(IS_ERR(dir)) + return(PTR_ERR(dir)); + + next = file->f_pos; + while((name = (*ops->read_dir)(dir, &next, &ino, &len, ed)) != NULL){ + error = (*filldir)(ent, name, len, file->f_pos, ino, + DT_UNKNOWN); + if(error) + break; + file->f_pos = next; + } + (*ops->close_dir)(dir, ed); + return(0); +} + +int externfs_file_open(struct inode *ino, struct file *file) +{ + ino->i_nlink++; + return(0); +} + +int externfs_dir_open(struct inode *ino, struct file *file) +{ + return(0); +} + +int externfs_dir_release(struct inode *ino, struct file *file) +{ + return(0); +} + +int externfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct externfs_file_ops *ops = file_externfs_i(file)->ops; + struct inode *inode = dentry->d_inode; + struct externfs_data *ed = inode->i_sb->u.generic_sbp; + + return((*ops->truncate_file)(EXTERNFS_I(inode), inode->i_size, ed)); +} + +static struct file_operations externfs_file_fops = { + .owner = NULL, + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .open = externfs_file_open, + .release = NULL, + .fsync = externfs_fsync, +}; + +static struct file_operations externfs_dir_fops = { + .owner = NULL, + .readdir = externfs_readdir, + .open = externfs_dir_open, + .release = externfs_dir_release, + .fsync = externfs_fsync, +}; + +struct wp_info { + struct page *page; + int count; + unsigned long long start; + unsigned long long size; + int (*truncate)(struct externfs_inode *ei, __u64 size, + struct externfs_data *ed); + struct externfs_inode *ei; + struct externfs_data *ed; +}; + +static void externfs_finish_writepage(char *buffer, int res, void *arg) +{ + struct wp_info *wp = arg; + + if(res == wp->count){ + ClearPageError(wp->page); + if(wp->start + res > wp->size) + (*wp->truncate)(wp->ei, wp->size, wp->ed); + } + else { + SetPageError(wp->page); + ClearPageUptodate(wp->page); + } + + kunmap(wp->page); + unlock_page(wp->page); + kfree(wp); +} + +static int externfs_writepage(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops; + struct wp_info *wp; + struct externfs_data *ed = inode->i_sb->u.generic_sbp; + char *buffer; + unsigned long long base; + int count = PAGE_CACHE_SIZE; + int end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int err, offset; + + base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; + + /* If we are entirely outside the file, then return an error */ + err = -EIO; + offset = inode->i_size & (PAGE_CACHE_SIZE-1); + if (page->index > end_index || + ((page->index == end_index) && !offset)) + goto out_unlock; + + err = -ENOMEM; + wp = kmalloc(sizeof(*wp), GFP_KERNEL); + if(wp == NULL) + goto out_unlock; + + *wp = ((struct wp_info) { .page = page, + .count = count, + .start = base, + .size = inode->i_size, + .truncate = ops->truncate_file, + .ei = EXTERNFS_I(inode), + .ed = ed }); + + buffer = kmap(page); + err = (*ops->write_file)(EXTERNFS_I(inode), base, buffer, 0, + count, externfs_finish_writepage, wp, ed); + + return err; + + out_unlock: + unlock_page(page); + return(err); +} + +static void externfs_finish_readpage(char *buffer, int res, void *arg) +{ + struct page *page = arg; + struct inode *inode; + + if(res < 0){ + SetPageError(page); + goto out; + } + + inode = page->mapping->host; + if(inode->i_size >> PAGE_CACHE_SHIFT == page->index) + res = inode->i_size % PAGE_CACHE_SIZE; + + memset(&buffer[res], 0, PAGE_CACHE_SIZE - res); + + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) + ClearPageError(page); + out: + kunmap(page); + unlock_page(page); +} + +static int externfs_readpage(struct file *file, struct page *page) +{ + struct inode *ino = page->mapping->host; + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *buffer; + long long start; + int err = 0; + + start = (long long) page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + + if(ops->map_file_page != NULL){ + /* XXX What happens when PAGE_SIZE != PAGE_CACHE_SIZE? */ + err = (*ops->map_file_page)(file_externfs_i(file), start, + buffer, file->f_mode & FMODE_WRITE, + ed); + if(!err) + err = PAGE_CACHE_SIZE; + } + else err = (*ops->read_file)(file_externfs_i(file), start, buffer, + PAGE_CACHE_SIZE, 0, 0, + externfs_finish_readpage, page, ed); + + if(err > 0) + err = 0; + return(err); +} + +struct writepage_info { + struct semaphore sem; + int res; +}; + +static void externfs_finish_prepare(char *buffer, int res, void *arg) +{ + struct writepage_info *wp = arg; + + wp->res = res; + up(&wp->sem); +} + +int externfs_prepare_write(struct file *file, struct page *page, + unsigned int from, unsigned int to) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops; + struct externfs_data *ed = inode->i_sb->u.generic_sbp; + char *buffer; + long long start; + int err; + struct writepage_info wp; + + if(Page_Uptodate(page)) + return(0); + + start = (long long) page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + + if(ops->map_file_page != NULL){ + err = (*ops->map_file_page)(file_externfs_i(file), start, + buffer, file->f_mode & FMODE_WRITE, + ed); + goto out; + } + + init_MUTEX_LOCKED(&wp.sem); + err = (*ops->read_file)(file_externfs_i(file), start, buffer, + PAGE_CACHE_SIZE, from, to, + externfs_finish_prepare, &wp, ed); + down(&wp.sem); + if(err < 0) + goto out; + + err = wp.res; + if(err < 0) + goto out; + + if(from > 0) + memset(buffer, 0, from); + if(to < PAGE_CACHE_SIZE) + memset(buffer + to, 0, PAGE_CACHE_SIZE - to); + + SetPageUptodate(page); + err = 0; + out: + kunmap(page); + return(err); +} + +static int externfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops; + unsigned long long size; + long long start; + int err; + + start = (long long) (page->index << PAGE_CACHE_SHIFT); + + if(ops->map_file_page != NULL) + err = to - from; + else { + size = start + to; + if(size > inode->i_size){ + inode->i_size = size; + mark_inode_dirty(inode); + } + } + + set_page_dirty(page); + return(to - from); +} + +static void externfs_removepage(struct page *page) +{ + physmem_remove_mapping(page_address(page)); +} + +static struct address_space_operations externfs_aops = { + .writepage = externfs_writepage, + .readpage = externfs_readpage, + .removepage = externfs_removepage, +/* .set_page_dirty = __set_page_dirty_nobuffers, */ + .prepare_write = externfs_prepare_write, + .commit_write = externfs_commit_write +}; + +static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, + int need_fh) +{ + struct inode *inode; + struct externfs_data *ed = sb->u.generic_sbp; + struct externfs_mount_ops *ops = ed->mount_ops; + char *name = NULL; + int type, err = -ENOMEM, rdev; + + if(dentry){ + name = dentry_name(dentry, 0); + if(name == NULL) + goto out; + type = (*ed->file_ops->file_type)(name, &rdev, ed); + } + else type = OS_TYPE_DIR; + + inode = new_inode(sb); + if(inode == NULL) + goto out_free; + + insert_inode_hash(inode); + + if(type == OS_TYPE_SYMLINK) + inode->i_op = &page_symlink_inode_operations; + else if(type == OS_TYPE_DIR) + inode->i_op = &externfs_dir_iops; + else inode->i_op = &externfs_iops; + + if(type == OS_TYPE_DIR) inode->i_fop = &externfs_dir_fops; + else inode->i_fop = &externfs_file_fops; + + if(type == OS_TYPE_SYMLINK) + inode->i_mapping->a_ops = &externfs_link_aops; + else inode->i_mapping->a_ops = &externfs_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; + case OS_TYPE_SYMLINK: + inode->i_mode = S_IFLNK | S_IRWXUGO; + } + + if(need_fh){ + struct externfs_inode *ei; + + err = -ENOMEM; + ei = (*ops->init_file)(ed); + if(ei == NULL) + goto out_put; + + *ei = ((struct externfs_inode) { .ops = ed->file_ops }); + inode->u.generic_ip = ei; + + err = (*ed->file_ops->open_file)(ei, name, current->fsuid, + current->fsgid, inode, ed); + if(err && ((err != -ENOENT) && (err != -EISDIR))) + goto out_put; + } + + return(inode); + + out_put: + iput(inode); + out_free: + kfree(name); + out: + return(ERR_PTR(err)); +} + +int externfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops; + struct inode *inode; + struct externfs_data *ed = dir->i_sb->u.generic_sbp; + struct externfs_inode *ei; + char *name; + int err = -ENOMEM; + + name = dentry_name(dentry, 0); + if(name == NULL) + goto out; + + inode = get_inode(dir->i_sb, dentry, 0); + if(IS_ERR(inode)){ + err = PTR_ERR(inode); + goto out_free; + } + + ei = (*ed->mount_ops->init_file)(ed); + if(ei == NULL) + /* XXX need a free_file() */ + goto out_put; + + *ei = ((struct externfs_inode) { .ops = ed->file_ops }); + inode->u.generic_ip = ei; + + err = (*ops->create_file)(ei, name, mode, current->fsuid, + current->fsuid, inode, ed); + if(err) + goto out_put; + + err = read_name(inode, name); + if(err) + goto out_rm; + + inode->i_nlink++; + d_instantiate(dentry, inode); + out_free: + kfree(name); + out: + return(err); + + out_rm: + (*ops->unlink_file)(name, ed); + out_put: + inode->i_nlink = 0; + iput(inode); + goto out_free; +} + +struct dentry *externfs_lookup(struct inode *ino, struct dentry *dentry) +{ + struct inode *inode; + char *name; + int err; + + inode = get_inode(ino->i_sb, dentry, 1); + if(IS_ERR(inode)){ + err = PTR_ERR(inode); + goto out; + } + + err = -ENOMEM; + name = dentry_name(dentry, 0); + if(name == NULL) + goto out_put; + + err = read_name(inode, name); + kfree(name); + if(err){ + if(err != -ENOENT) + goto out_put; + + inode->i_nlink = 0; + iput(inode); + inode = NULL; + } + d_add(dentry, inode); + dentry->d_op = &externfs_dentry_ops; + return(NULL); + + out_put: + inode->i_nlink = 0; + iput(inode); + out: + return(ERR_PTR(err)); +} + +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 externfs_link(struct dentry *to, struct inode *ino, struct dentry *from) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *from_name, *to_name; + int err = -ENOMEM; + + from_name = inode_dentry_name(ino, from); + if(from_name == NULL) + goto out; + + to_name = dentry_name(to, 0); + if(to_name == NULL) + goto out_free_from; + + err = (*ops->link_file)(to_name, from_name, current->fsuid, + current->fsgid, ed); + if(err) + goto out_free_to; + + d_instantiate(from, to->d_inode); + to->d_inode->i_nlink++; + atomic_inc(&to->d_inode->i_count); + + out_free_to: + kfree(to_name); + out_free_from: + kfree(from_name); + out: + return(err); +} + +int externfs_unlink(struct inode *ino, struct dentry *dentry) +{ + struct inode *inode; + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *file; + int err; + + file = inode_dentry_name(ino, dentry); + if(file == NULL) + return(-ENOMEM); + + inode = dentry->d_inode; + if((inode->i_nlink == 1) && (ops->invisible != NULL)) + (*ops->invisible)(EXTERNFS_I(inode)); + + err = (*ops->unlink_file)(file, ed); + kfree(file); + + inode->i_nlink--; + + return(err); +} + +int externfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + struct inode *inode; + char *file; + int err; + + file = inode_dentry_name(ino, dentry); + if(file == NULL) + return(-ENOMEM); + err = (*ops->make_symlink)(file, to, current->fsuid, current->fsgid, + ed); + kfree(file); + + inode = get_inode(ino->i_sb, dentry, 1); + if(IS_ERR(inode)){ + err = PTR_ERR(inode); + goto out; + } + + d_instantiate(dentry, inode); + inode->i_nlink++; + iput(inode); + out: + return(err); +} + +int externfs_make_dir(struct inode *ino, struct dentry *dentry, int mode) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + struct inode *inode; + char *file; + int err; + + file = inode_dentry_name(ino, dentry); + if(file == NULL) + return(-ENOMEM); + err = (*ops->make_dir)(file, mode, current->fsuid, current->fsgid, ed); + + inode = get_inode(ino->i_sb, dentry, 1); + if(IS_ERR(inode)){ + err = PTR_ERR(inode); + goto out_free; + } + + err = read_name(inode, file); + kfree(file); + if(err) + goto out_put; + + d_instantiate(dentry, inode); + inode->i_nlink = 2; + inode->i_mode = S_IFDIR | mode; + iput(inode); + + ino->i_nlink++; + out: + return(err); + out_free: + kfree(file); + out_put: + inode->i_nlink = 0; + iput(inode); + goto out; +} + +int externfs_remove_dir(struct inode *ino, struct dentry *dentry) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + void *mount = ino->i_sb->u.generic_sbp; + char *file; + int err; + + file = inode_dentry_name(ino, dentry); + if(file == NULL) + return(-ENOMEM); + err = (*ops->remove_dir)(file, current->fsuid, current->fsgid, mount); + kfree(file); + + dentry->d_inode->i_nlink = 0; + ino->i_nlink--; + return(err); +} + +int externfs_make_node(struct inode *dir, struct dentry *dentry, int mode, + int dev) +{ + struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops; + struct externfs_data *ed = dir->i_sb->u.generic_sbp; + struct inode *inode; + char *name; + int err = -ENOMEM; + + name = dentry_name(dentry, 0); + if(name == NULL) + goto out; + + inode = get_inode(dir->i_sb, dentry, 1); + if(IS_ERR(inode)){ + err = PTR_ERR(inode); + goto out_free; + } + + init_special_inode(inode, mode, dev); + err = (*ops->make_node)(name, mode & S_IRWXUGO, current->fsuid, + current->fsgid, mode & S_IFMT, major(dev), + minor(dev), ed); + if(err) + goto out_put; + + err = read_name(inode, name); + if(err) + goto out_rm; + + d_instantiate(dentry, inode); + out_free: + kfree(name); + out: + return(err); + + out_rm: + (*ops->unlink_file)(name, ed); + out_put: + inode->i_nlink = 0; + iput(inode); + goto out_free; +} + +int externfs_rename(struct inode *from_ino, struct dentry *from, + struct inode *to_ino, struct dentry *to) +{ + struct externfs_file_ops *ops = EXTERNFS_I(from_ino)->ops; + struct externfs_data *ed = from_ino->i_sb->u.generic_sbp; + 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 = (*ops->rename_file)(from_name, to_name, ed); + kfree(from_name); + kfree(to_name); + + from_ino->i_nlink--; + to_ino->i_nlink++; + return(err); +} + +void externfs_truncate(struct inode *ino) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + + (*ops->truncate_file)(EXTERNFS_I(ino), ino->i_size, ed); +} + +int externfs_permission(struct inode *ino, int desired) +{ + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *name; + int r = 0, w = 0, x = 0, err; + + if(ops->access_file == NULL) + return(vfs_permission(ino, desired)); + + 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 = (*ops->access_file)(name, r, w, x, current->fsuid, + current->fsgid, ed); + kfree(name); + + if(!err) + err = vfs_permission(ino, desired); + return(err); +} + +int externfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct externfs_file_ops *ops = EXTERNFS_I(dentry->d_inode)->ops; + struct externfs_data *ed = dentry->d_inode->i_sb->u.generic_sbp; + struct externfs_iattr attrs; + char *name; + int err; + + attrs.ia_valid = 0; + if(attr->ia_valid & ATTR_MODE){ + attrs.ia_valid |= EXTERNFS_ATTR_MODE; + attrs.ia_mode = attr->ia_mode; + } + if(attr->ia_valid & ATTR_UID){ + attrs.ia_valid |= EXTERNFS_ATTR_UID; + attrs.ia_uid = attr->ia_uid; + } + if(attr->ia_valid & ATTR_GID){ + attrs.ia_valid |= EXTERNFS_ATTR_GID; + attrs.ia_gid = attr->ia_gid; + } + if(attr->ia_valid & ATTR_SIZE){ + attrs.ia_valid |= EXTERNFS_ATTR_SIZE; + attrs.ia_size = attr->ia_size; + } + if(attr->ia_valid & ATTR_ATIME){ + attrs.ia_valid |= EXTERNFS_ATTR_ATIME; + attrs.ia_atime = attr->ia_atime; + } + if(attr->ia_valid & ATTR_MTIME){ + attrs.ia_valid |= EXTERNFS_ATTR_MTIME; + attrs.ia_mtime = attr->ia_mtime; + } + if(attr->ia_valid & ATTR_CTIME){ + attrs.ia_valid |= EXTERNFS_ATTR_CTIME; + attrs.ia_ctime = attr->ia_ctime; + } + if(attr->ia_valid & ATTR_ATIME_SET){ + attrs.ia_valid |= EXTERNFS_ATTR_ATIME_SET; + } + if(attr->ia_valid & ATTR_MTIME_SET){ + attrs.ia_valid |= EXTERNFS_ATTR_MTIME_SET; + } + name = dentry_name(dentry, 0); + if(name == NULL) + return(-ENOMEM); + err = (*ops->set_attr)(name, &attrs, ed); + kfree(name); + if(err) + return(err); + + return(inode_setattr(dentry->d_inode, attr)); +} + +int externfs_getattr(struct dentry *dentry, struct iattr *attr) +{ + not_implemented(); + return(-EINVAL); +} + +static struct inode_operations externfs_iops = { + .create = externfs_create, + .link = externfs_link, + .unlink = externfs_unlink, + .symlink = externfs_symlink, + .mkdir = externfs_make_dir, + .rmdir = externfs_remove_dir, + .mknod = externfs_make_node, + .rename = externfs_rename, + .truncate = externfs_truncate, + .permission = externfs_permission, + .setattr = externfs_setattr, + .getattr = externfs_getattr, +}; + +static struct inode_operations externfs_dir_iops = { + .create = externfs_create, + .lookup = externfs_lookup, + .link = externfs_link, + .unlink = externfs_unlink, + .symlink = externfs_symlink, + .mkdir = externfs_make_dir, + .rmdir = externfs_remove_dir, + .mknod = externfs_make_node, + .rename = externfs_rename, + .truncate = externfs_truncate, + .permission = externfs_permission, + .setattr = externfs_setattr, + .getattr = externfs_getattr, +}; + +int externfs_link_readpage(struct file *file, struct page *page) +{ + struct inode *ino = page->mapping->host; + struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops; + struct externfs_data *ed = ino->i_sb->u.generic_sbp; + char *buffer, *name; + long long start; + int err; + + start = page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + name = inode_name(ino, 0); + if(name == NULL) + return(-ENOMEM); + + err = (*ops->read_link)(name, current->fsuid, current->fsgid, buffer, + PAGE_CACHE_SIZE, ed); + + 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 int externfs_flushpage(struct page *page, unsigned long offset) +{ + return(externfs_writepage(page)); +} + +struct externfs_data *inode_externfs_info(struct inode *inode) +{ + return(inode->i_sb->u.generic_sbp); +} + +static struct address_space_operations externfs_link_aops = { + .readpage = externfs_link_readpage, + .removepage = externfs_removepage, + .flushpage = externfs_flushpage, +}; + +DECLARE_MUTEX(externfs_sem); +struct list_head externfses = LIST_HEAD_INIT(externfses); + +static struct externfs *find_externfs(struct file_system_type *type) +{ + struct list_head *ele; + struct externfs *fs; + + down(&externfs_sem); + list_for_each(ele, &externfses){ + fs = list_entry(ele, struct externfs, list); + if(&fs->type == type) + goto out; + } + fs = NULL; + out: + up(&externfs_sem); + return(fs); +} + +#define DEFAULT_ROOT "/" + +char *host_root_filename(char *mount_arg) +{ + char *root = DEFAULT_ROOT; + + if((mount_arg != NULL) && (*mount_arg != '\0')) + root = mount_arg; + + return(uml_strdup(root)); +} + +struct super_block *externfs_read_super(struct super_block *sb, void *data, + int silent) +{ + struct externfs *fs; + struct inode *root_inode; + struct externfs_data *sb_data; + int err = -EINVAL; + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = EXTERNFS_SUPER_MAGIC; + sb->s_op = &externfs_sbops; + + fs = find_externfs(sb->s_type); + if(fs == NULL){ + printk("Couldn't find externfs for filesystem '%s'\n", + sb->s_type->name); + goto out; + } + + sb_data = (*fs->mount_ops->mount)(data); + if(IS_ERR(sb_data)){ + err = PTR_ERR(sb_data); + goto out; + } + + sb->u.generic_sbp = sb_data; + sb_data->mount_ops = fs->mount_ops; + + root_inode = get_inode(sb, NULL, 1); + if(IS_ERR(root_inode)) + goto out; + + sb->s_root = d_alloc_root(root_inode); + if(sb->s_root == NULL) + goto out_put; + + if(read_inode(root_inode)) + goto out_dput; + return(sb); + + out_dput: + /* dput frees the inode */ + dput(sb->s_root); + return(NULL); + out_put: + root_inode->i_nlink = 0; + make_bad_inode(root_inode); + iput(root_inode); + out: + return(NULL); +} + +void init_externfs(struct externfs_data *ed, struct externfs_file_ops *ops) +{ + ed->file_ops = ops; +} + +int register_externfs(char *name, struct externfs_mount_ops *mount_ops) +{ + struct externfs *new; + int err = -ENOMEM; + + new = kmalloc(sizeof(*new), GFP_KERNEL); + if(new == NULL) + goto out; + + memset(new, 0, sizeof(*new)); + *new = ((struct externfs) { .list = LIST_HEAD_INIT(new->list), + .mount_ops = mount_ops, + .type = { .name = name, + .read_super = externfs_read_super, + .fs_flags = 0, + .owner = THIS_MODULE } }); + list_add(&new->list, &externfses); + + err = register_filesystem(&new->type); + if(err) + goto out_del; + return(0); + + out_del: + list_del(&new->list); + kfree(new); + out: + return(err); +} + +void unregister_externfs(char *name) +{ + struct list_head *ele; + struct externfs *fs; + + down(&externfs_sem); + list_for_each(ele, &externfses){ + fs = list_entry(ele, struct externfs, list); + if(!strcmp(fs->type.name, name)){ + list_del(ele); + up(&externfs_sem); + return; + } + } + up(&externfs_sem); + printk("Unregister_externfs - filesystem '%s' not found\n", name); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/fs/hostfs/host_file.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/host_file.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/host_file.c 2005-05-03 22:28:14.271440624 +0300 @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/string.h" +#include "linux/errno.h" +#include "linux/types.h" +#include "linux/slab.h" +#include "linux/blkdev.h" +#include "asm/fcntl.h" +#include "hostfs.h" + +extern int append; + +char *get_path(const char *path[], char *buf, int size) +{ + const char **s; + char *p; + int new = 1; + + for(s = path; *s != NULL; s++){ + new += strlen(*s); + if((*(s + 1) != NULL) && (strlen(*s) > 0) && + ((*s)[strlen(*s) - 1] != '/')) + new++; + } + + if(new > size){ + buf = kmalloc(new, GFP_KERNEL); + if(buf == NULL) + return(NULL); + } + + p = buf; + for(s = path; *s != NULL; s++){ + strcpy(p, *s); + p += strlen(*s); + if((*(s + 1) != NULL) && (strlen(*s) > 0) && + ((*s)[strlen(*s) - 1] != '/')) + strcpy(p++, "/"); + } + + return(buf); +} + +void free_path(const char *buf, char *tmp) +{ + if((buf != tmp) && (buf != NULL)) + kfree((char *) buf); +} + +int host_open_file(const char *path[], int r, int w, struct file_handle *fh) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int mode = 0, err; + struct openflags flags = OPENFLAGS(); + + if (r) + flags = of_read(flags); + if (w) + flags = of_write(flags); + if(append) + flags = of_append(flags); + + err = -ENOMEM; + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = open_filehandle(file, flags, mode, fh); + out: + free_path(file, tmp); + return(err); +} + +void *host_open_dir(const char *path[]) +{ + char tmp[HOSTFS_BUFSIZE], *file; + void *dir = ERR_PTR(-ENOMEM); + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + dir = open_dir(file); + out: + free_path(file, tmp); + return(dir); +} + +char *host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out) +{ + int err; + char *name; + + err = os_seek_dir(stream, *pos); + if(err) + return(ERR_PTR(err)); + + err = os_read_dir(stream, ino_out, &name); + if(err) + return(ERR_PTR(err)); + + if(name == NULL) + return(NULL); + + *len_out = strlen(name); + *pos = os_tell_dir(stream); + return(name); +} + +int host_file_type(const char *path[], int *rdev) +{ + char tmp[HOSTFS_BUFSIZE], *file; + struct uml_stat buf; + int ret; + + ret = -ENOMEM; + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + if(rdev != NULL){ + ret = os_lstat_file(file, &buf); + if(ret) + goto out; + *rdev = MKDEV(buf.ust_rmajor, buf.ust_rminor); + } + + ret = os_file_type(file); + out: + free_path(file, tmp); + return(ret); +} + +int host_create_file(const char *path[], int mode, struct file_handle *fh) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = open_filehandle(file, of_create(of_rdwr(OPENFLAGS())), mode, fh); + out: + free_path(file, tmp); + return(err); +} + +static int do_stat_file(const char *path, dev_t *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 uml_stat buf; + int err; + + err = os_lstat_file(path, &buf); + if(err < 0) + return(err); + + if(dev_out != NULL) *dev_out = MKDEV(buf.ust_major, buf.ust_minor); + if(inode_out != NULL) *inode_out = buf.ust_ino; + if(mode_out != NULL) *mode_out = buf.ust_mode; + if(nlink_out != NULL) *nlink_out = buf.ust_nlink; + if(uid_out != NULL) *uid_out = buf.ust_uid; + if(gid_out != NULL) *gid_out = buf.ust_gid; + if(size_out != NULL) *size_out = buf.ust_size; + if(atime_out != NULL) *atime_out = buf.ust_atime; + if(mtime_out != NULL) *mtime_out = buf.ust_mtime; + if(ctime_out != NULL) *ctime_out = buf.ust_ctime; + if(blksize_out != NULL) *blksize_out = buf.ust_blksize; + if(blocks_out != NULL) *blocks_out = buf.ust_blocks; + + return(0); +} + +int host_stat_file(const char *path[], dev_t *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) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err; + + err = -ENOMEM; + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = do_stat_file(file, dev_out, inode_out, mode_out, nlink_out, + uid_out, gid_out, size_out, atime_out, mtime_out, + ctime_out, blksize_out, blocks_out); + out: + free_path(file, tmp); + return(err); +} + +int host_set_attr(const char *path[], struct externfs_iattr *attrs) +{ + char tmp[HOSTFS_BUFSIZE], *file; + unsigned long time; + int err = 0, ma; + + if(append && (attrs->ia_valid & EXTERNFS_ATTR_SIZE)) + return(-EPERM); + + err = -ENOMEM; + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + if(attrs->ia_valid & EXTERNFS_ATTR_MODE){ + err = os_set_file_perms(file, attrs->ia_mode); + if(err < 0) + goto out; + } + if(attrs->ia_valid & EXTERNFS_ATTR_UID){ + err = os_set_file_owner(file, attrs->ia_uid, -1); + if(err < 0) + goto out; + } + if(attrs->ia_valid & EXTERNFS_ATTR_GID){ + err = os_set_file_owner(file, -1, attrs->ia_gid); + if(err < 0) + goto out; + } + if(attrs->ia_valid & EXTERNFS_ATTR_SIZE){ + err = os_truncate_file(file, attrs->ia_size); + if(err < 0) + goto out; + } + ma = EXTERNFS_ATTR_ATIME_SET | EXTERNFS_ATTR_MTIME_SET; + if((attrs->ia_valid & ma) == ma){ + err = os_set_file_time(file, attrs->ia_atime, attrs->ia_mtime); + if(err) + goto out; + } + else { + if(attrs->ia_valid & EXTERNFS_ATTR_ATIME_SET){ + err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, &time, + NULL, NULL, NULL); + if(err != 0) + goto out; + + err = os_set_file_time(file, attrs->ia_atime, time); + if(err) + goto out; + } + if(attrs->ia_valid & EXTERNFS_ATTR_MTIME_SET){ + err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &time, NULL, + NULL, NULL, NULL); + if(err != 0) + goto out; + + err = os_set_file_time(file, time, attrs->ia_mtime); + if(err) + goto out; + } + } + if(attrs->ia_valid & EXTERNFS_ATTR_CTIME) ; + if(attrs->ia_valid & (EXTERNFS_ATTR_ATIME | EXTERNFS_ATTR_MTIME)){ + err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &attrs->ia_atime, + &attrs->ia_mtime, NULL, NULL, NULL); + if(err != 0) + goto out; + } + + err = 0; + out: + free_path(file, tmp); + return(err); +} + +int host_make_symlink(const char *from[], const char *to) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(from, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_make_symlink(to, file); + out: + free_path(file, tmp); + return(err); +} + +int host_unlink_file(const char *path[]) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + if(append) + return(-EPERM); + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_remove_file(file); + out: + free_path(file, tmp); + return(err); +} + +int host_make_dir(const char *path[], int mode) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_make_dir(file, mode); + out: + free_path(file, tmp); + return(err); +} + +int host_remove_dir(const char *path[]) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_remove_dir(file); + out: + free_path(file, tmp); + return(err); +} + +int host_link_file(const char *to[], const char *from[]) +{ + char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t; + int err = -ENOMEM; + + f = get_path(from, from_tmp, sizeof(from_tmp)); + t = get_path(to, to_tmp, sizeof(to_tmp)); + if((f == NULL) || (t == NULL)) + goto out; + + err = os_link_file(t, f); + out: + free_path(f, from_tmp); + free_path(t, to_tmp); + return(err); +} + +int host_read_link(const char *path[], char *buf, int size) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int n = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + n = os_read_symlink(file, buf, size); + if(n < size) + buf[n] = '\0'; + out: + free_path(file, tmp); + return(n); +} + +int host_rename_file(const char *from[], const char *to[]) +{ + char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t; + int err = -ENOMEM; + + f = get_path(from, from_tmp, sizeof(from_tmp)); + t = get_path(to, to_tmp, sizeof(to_tmp)); + if((f == NULL) || (t == NULL)) + goto out; + + err = os_move_file(f, t); + out: + free_path(f, from_tmp); + free_path(t, to_tmp); + return(err); +} + +int host_stat_fs(const char *path[], 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) +{ + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_stat_filesystem(file, bsize_out, blocks_out, bfree_out, + bavail_out, files_out, ffree_out, fsid_out, + fsid_size, namelen_out, spare_out); + out: + free_path(file, tmp); + return(err); +} + +char *generic_host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + void *mount) +{ + return(host_read_dir(stream, pos, ino_out, len_out)); +} + +int generic_host_truncate_file(struct file_handle *fh, __u64 size, void *m) +{ + return(truncate_file(fh, 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: + */ Index: linux-2.4.29/arch/um/fs/hostfs/host_fs.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/host_fs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/host_fs.c 2005-05-03 22:28:14.273440320 +0300 @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/string.h" +#include "linux/types.h" +#include "linux/errno.h" +#include "linux/slab.h" +#include "linux/init.h" +#include "linux/fs.h" +#include "linux/stat.h" +#include "hostfs.h" +#include "kern.h" +#include "init.h" +#include "kern_util.h" +#include "filehandle.h" +#include "os.h" + +/* Changed in hostfs_args before the kernel starts running */ +static char *jail_dir = "/"; +int append = 0; + +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" +); + +struct hostfs_data { + struct externfs_data ext; + char *mount; +}; + +struct hostfs_file { + struct externfs_inode ext; + struct file_handle fh; +}; + +static int hostfs_access_file(char *file, int r, int w, int x, int uid, + int gid, struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + char tmp[HOSTFS_BUFSIZE]; + int err, mode = 0; + + if(r) mode = OS_ACC_R_OK; + if(w) mode |= OS_ACC_W_OK; + if(x) mode |= OS_ACC_X_OK; + + err = -ENOMEM; + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_access(file, mode); + free_path(file, tmp); + out: + return(err); +} + +static int hostfs_make_node(const char *file, int mode, int uid, int gid, + int type, int major, int minor, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + char tmp[HOSTFS_BUFSIZE]; + int err = -ENOMEM; + + file = get_path(path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + /* XXX Pass type in an OS-independent way */ + mode |= type; + + err = os_make_dev(file, mode, major, minor); + free_path(file, tmp); + out: + return(err); +} + +static int hostfs_stat_file(const char *file, struct externfs_data *ed, + dev_t *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) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + /* XXX Why pretend everything is owned by root? */ + *uid_out = 0; + *gid_out = 0; + return(host_stat_file(path, dev_out, inode_out, mode_out, nlink_out, + NULL, NULL, size_out, atime_out, mtime_out, + ctime_out, blksize_out, blocks_out)); +} + +static int hostfs_file_type(const char *file, int *rdev, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_file_type(path, rdev)); +} + +static char *hostfs_name(struct inode *inode) +{ + struct externfs_data *ed = inode_externfs_info(inode); + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + + return(inode_name_prefix(inode, mount)); +} + +static struct externfs_inode *hostfs_init_file(struct externfs_data *ed) +{ + struct hostfs_file *hf; + + hf = kmalloc(sizeof(*hf), GFP_KERNEL); + if(hf == NULL) + return(NULL); + + hf->fh.fd = -1; + return(&hf->ext); +} + +static int hostfs_open_file(struct externfs_inode *ext, char *file, + int uid, int gid, struct inode *inode, + struct externfs_data *ed) +{ + struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext); + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + int err; + + err = host_open_file(path, 1, 1, &hf->fh); + if(err == -EISDIR) + goto out; + + if(err == -EACCES) + err = host_open_file(path, 1, 0, &hf->fh); + + if(err) + goto out; + + is_reclaimable(&hf->fh, hostfs_name, inode); + out: + return(err); +} + +static void *hostfs_open_dir(char *file, int uid, int gid, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_open_dir(path)); +} + +static void hostfs_close_dir(void *stream, struct externfs_data *ed) +{ + os_close_dir(stream); +} + +static char *hostfs_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + + return(generic_host_read_dir(stream, pos, ino_out, len_out, mount)); +} + +static int hostfs_read_file(struct externfs_inode *ext, + unsigned long long offset, char *buf, int len, + int ignore_start, int ignore_end, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed) +{ + struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext); + int err = 0; + + if(ignore_start != 0){ + err = read_file(&hf->fh, offset, buf, ignore_start); + if(err < 0) + goto out; + } + + if(ignore_end != len) + err = read_file(&hf->fh, offset + ignore_end, buf + ignore_end, + len - ignore_end); + + out: + + (*completion)(buf, err, arg); + if (err > 0) + err = 0; + return(err); +} + +static int hostfs_write_file(struct externfs_inode *ext, + unsigned long long offset, const char *buf, + int start, int len, + void (*completion)(char *, int, void *), + void *arg, struct externfs_data *ed) +{ + struct file_handle *fh; + int err; + + fh = &container_of(ext, struct hostfs_file, ext)->fh; + err = write_file(fh, offset + start, buf + start, len); + + (*completion)((char *) buf, err, arg); + if (err > 0) + err = 0; + + return(err); +} + +static int hostfs_create_file(struct externfs_inode *ext, char *file, int mode, + int uid, int gid, struct inode *inode, + struct externfs_data *ed) +{ + struct hostfs_file *hf = container_of(ext, struct hostfs_file, + ext); + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + int err = -ENOMEM; + + err = host_create_file(path, mode, &hf->fh); + if(err) + goto out; + + is_reclaimable(&hf->fh, hostfs_name, inode); + out: + return(err); +} + +static int hostfs_set_attr(const char *file, struct externfs_iattr *attrs, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_set_attr(path, attrs)); +} + +static int hostfs_make_symlink(const char *from, const char *to, int uid, + int gid, struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, from, NULL }; + + return(host_make_symlink(path, to)); +} + +static int hostfs_link_file(const char *to, const char *from, int uid, int gid, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *to_path[] = { jail_dir, mount, to, NULL }; + const char *from_path[] = { jail_dir, mount, from, NULL }; + + return(host_link_file(to_path, from_path)); +} + +static int hostfs_unlink_file(const char *file, struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_unlink_file(path)); +} + +static int hostfs_make_dir(const char *file, int mode, int uid, int gid, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_make_dir(path, mode)); +} + +static int hostfs_remove_dir(const char *file, int uid, int gid, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_remove_dir(path)); +} + +static int hostfs_read_link(char *file, int uid, int gid, char *buf, int size, + struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, file, NULL }; + + return(host_read_link(path, buf, size)); +} + +static int hostfs_rename_file(char *from, char *to, struct externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *to_path[] = { jail_dir, mount, to, NULL }; + const char *from_path[] = { jail_dir, mount, from, NULL }; + + return(host_rename_file(from_path, to_path)); +} + +static int hostfs_stat_fs(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 externfs_data *ed) +{ + char *mount = container_of(ed, struct hostfs_data, ext)->mount; + const char *path[] = { jail_dir, mount, NULL }; + + return(host_stat_fs(path, bsize_out, blocks_out, bfree_out, bavail_out, + files_out, ffree_out, fsid_out, fsid_size, + namelen_out, spare_out)); +} + +static void hostfs_close_file(struct externfs_inode *ext, + unsigned long long size) +{ + struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext); + + if(hf->fh.fd == -1) + return; + + truncate_file(&hf->fh, size); + close_file(&hf->fh); +} + +static int hostfs_truncate_file(struct externfs_inode *ext, __u64 size, + struct externfs_data *ed) +{ + struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext); + + return(truncate_file(&hf->fh, size)); +} + +static struct externfs_file_ops hostfs_file_ops = { + .stat_file = hostfs_stat_file, + .file_type = hostfs_file_type, + .access_file = hostfs_access_file, + .open_file = hostfs_open_file, + .open_dir = hostfs_open_dir, + .read_dir = hostfs_read_dir, + .read_file = hostfs_read_file, + .write_file = hostfs_write_file, + .map_file_page = NULL, + .close_file = hostfs_close_file, + .close_dir = hostfs_close_dir, + .invisible = NULL, + .create_file = hostfs_create_file, + .set_attr = hostfs_set_attr, + .make_symlink = hostfs_make_symlink, + .unlink_file = hostfs_unlink_file, + .make_dir = hostfs_make_dir, + .remove_dir = hostfs_remove_dir, + .make_node = hostfs_make_node, + .link_file = hostfs_link_file, + .read_link = hostfs_read_link, + .rename_file = hostfs_rename_file, + .statfs = hostfs_stat_fs, + .truncate_file = hostfs_truncate_file +}; + +static struct externfs_data *mount_fs(char *mount_arg) +{ + struct hostfs_data *hd; + int err = -ENOMEM; + + hd = kmalloc(sizeof(*hd), GFP_KERNEL); + if(hd == NULL) + goto out; + + hd->mount = host_root_filename(mount_arg); + if(hd->mount == NULL) + goto out_free; + + init_externfs(&hd->ext, &hostfs_file_ops); + + return(&hd->ext); + out_free: + kfree(hd); + out: + return(ERR_PTR(err)); +} + +static struct externfs_mount_ops hostfs_mount_ops = { + .init_file = hostfs_init_file, + .mount = mount_fs, +}; + +static int __init init_hostfs(void) +{ + return(register_externfs("hostfs", &hostfs_mount_ops)); +} + +static void __exit exit_hostfs(void) +{ + unregister_externfs("hostfs"); +} + +__initcall(init_hostfs); +__exitcall(exit_hostfs); + +#if 0 +module_init(init_hostfs) +module_exit(exit_hostfs) +MODULE_LICENSE("GPL"); +#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: + */ Index: linux-2.4.29/arch/um/fs/hostfs/hostfs.h =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/hostfs.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/hostfs.h 2005-05-03 23:46:13.801043992 +0300 @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __UM_FS_HOSTFS +#define __UM_FS_HOSTFS + +#include "linux/fs.h" +#include "linux/blkdev.h" +#include "filehandle.h" +#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 EXTERNFS_ATTR_MODE 1 +#define EXTERNFS_ATTR_UID 2 +#define EXTERNFS_ATTR_GID 4 +#define EXTERNFS_ATTR_SIZE 8 +#define EXTERNFS_ATTR_ATIME 16 +#define EXTERNFS_ATTR_MTIME 32 +#define EXTERNFS_ATTR_CTIME 64 +#define EXTERNFS_ATTR_ATIME_SET 128 +#define EXTERNFS_ATTR_MTIME_SET 256 +#define EXTERNFS_ATTR_FORCE 512 /* Not a change, but a change it */ +#define EXTERNFS_ATTR_ATTR_FLAG 1024 + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct externfs_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; +}; + +struct externfs_data { + struct externfs_file_ops *file_ops; + struct externfs_mount_ops *mount_ops; +}; + +struct externfs_inode { + struct externfs_file_ops *ops; +}; + +struct externfs_mount_ops { + struct externfs_data *(*mount)(char *mount_arg); + struct externfs_inode *(*init_file)(struct externfs_data *ed); +}; + +struct externfs_file_ops { + int (*stat_file)(const char *path, struct externfs_data *ed, + dev_t *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); + int (*file_type)(const char *path, int *rdev, + struct externfs_data *ed); + int (*access_file)(char *path, int r, int w, int x, int uid, int gid, + struct externfs_data *ed); + int (*open_file)(struct externfs_inode *ext, char *file, + int uid, int gid, struct inode *inode, + struct externfs_data *ed); + void (*close_file)(struct externfs_inode *ext, + unsigned long long size); + void *(*open_dir)(char *path, int uid, int gid, + struct externfs_data *ed); + char *(*read_dir)(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + struct externfs_data *ed); + int (*read_file)(struct externfs_inode *ext, + unsigned long long offset, char *buf, int len, + int ignore_start, int ignore_end, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed); + int (*write_file)(struct externfs_inode *ext, + unsigned long long offset, const char *buf, + int start, int len, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed); + int (*map_file_page)(struct externfs_inode *ext, + unsigned long long offset, char *buf, int w, + struct externfs_data *ed); + void (*close_dir)(void *stream, struct externfs_data *ed); + void (*invisible)(struct externfs_inode *ext); + int (*create_file)(struct externfs_inode *ext, char *path, + int mode, int uid, int gid, struct inode *inode, + struct externfs_data *ed); + int (*set_attr)(const char *path, struct externfs_iattr *attrs, + struct externfs_data *ed); + int (*make_symlink)(const char *from, const char *to, int uid, int gid, + struct externfs_data *ed); + int (*unlink_file)(const char *path, struct externfs_data *ed); + int (*make_dir)(const char *path, int mode, int uid, int gid, + struct externfs_data *ed); + int (*remove_dir)(const char *path, int uid, int gid, + struct externfs_data *ed); + int (*make_node)(const char *path, int mode, int uid, int gid, + int type, int maj, int min, struct externfs_data *ed); + int (*link_file)(const char *to, const char *from, int uid, int gid, + struct externfs_data *ed); + int (*read_link)(char *path, int uid, int gid, char *buf, int size, + struct externfs_data *ed); + int (*rename_file)(char *from, char *to, struct externfs_data *ed); + int (*statfs)(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 externfs_data *ed); + int (*truncate_file)(struct externfs_inode *ext, __u64 size, + struct externfs_data *ed); +}; + +#define HOSTFS_BUFSIZE 64 + +extern int register_externfs(char *name, struct externfs_mount_ops *mount_ops); +extern void unregister_externfs(char *name); +extern void init_externfs(struct externfs_data *ed, + struct externfs_file_ops *ops); +struct externfs_data *inode_externfs_info(struct inode *inode); + +extern char *generic_root_filename(char *mount_arg); +extern void host_close_file(void *stream); +extern int host_read_file(int fd, unsigned long long offset, char *buf, + int len); +extern int host_open_file(const char *path[], int r, int w, + struct file_handle *fh); +extern void *host_open_dir(const char *path[]); +extern char *host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out); +extern int host_file_type(const char *path[], int *rdev); +extern char *host_root_filename(char *mount_arg); +extern char *get_path(const char *path[], char *buf, int size); +extern void free_path(const char *buf, char *tmp); +extern int host_create_file(const char *path[], int mode, + struct file_handle *fh); +extern int host_set_attr(const char *path[], struct externfs_iattr *attrs); +extern int host_make_symlink(const char *from[], const char *to); +extern int host_unlink_file(const char *path[]); +extern int host_make_dir(const char *path[], int mode); +extern int host_remove_dir(const char *path[]); +extern int host_link_file(const char *to[], const char *from[]); +extern int host_read_link(const char *path[], char *buf, int size); +extern int host_rename_file(const char *from[], const char *to[]); +extern int host_stat_fs(const char *path[], 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); +extern int host_stat_file(const char *path[], dev_t *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 char *generic_host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + void *mount); +extern int generic_host_read_file(int fd, unsigned long long offset, char *buf, + int len, void *mount); +extern void generic_host_close_file(void *stream, unsigned long long size, + void *mount); +extern int generic_host_truncate_file(struct file_handle *fh, __u64 size, + void *m); + +extern char *inode_name_prefix(struct inode *inode, char *prefix); + +#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: + */ Index: linux-2.4.29/arch/um/fs/hostfs/humfs.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/humfs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/humfs.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/tqueue.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/kdev_t.h> +#include <asm/irq.h> +#include "hostfs.h" +#include "mem.h" +#include "os.h" +#include "mode.h" +#include "aio.h" +#include "irq_user.h" +#include "irq_kern.h" +#include "filehandle.h" +#include "metadata.h" + +#define HUMFS_VERSION 2 + +static int humfs_stat_file(const char *path, struct externfs_data *ed, + dev_t *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 humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int err, mode, perms, major, minor; + char type; + + err = host_stat_file(data_path, dev_out, inode_out, mode_out, + nlink_out, NULL, NULL, size_out, atime_out, + mtime_out, ctime_out, blksize_out, blocks_out); + if(err) + return(err); + + err = (*mount->meta->ownerships)(path, &perms, uid_out, gid_out, + &type, &major, &minor, mount); + if(err) + return(err); + + *mode_out = (*mode_out & ~S_IRWXUGO) | perms; + + mode = 0; + switch(type){ + case 'c': + mode = S_IFCHR; + break; + case 'b': + mode = S_IFBLK; + break; + case 's': + mode = S_IFSOCK; + break; + default: + break; + } + + if(mode != 0) + *mode_out = (*mode_out & ~S_IFMT) | mode; + + return(0); +} + +static int meta_type(const char *path, int *dev_out, void *m) +{ + struct humfs *mount = m; + int err, type, maj, min; + char c; + + err = (*mount->meta->ownerships)(path, NULL, NULL, NULL, &c, &maj, + &min, mount); + if(err) + return(err); + + if(c == 0) + return(0); + + if(dev_out) + *dev_out = MKDEV(maj, min); + + switch(c){ + case 'c': + type = OS_TYPE_CHARDEV; + break; + case 'b': + type = OS_TYPE_BLOCKDEV; + break; + case 'p': + type = OS_TYPE_FIFO; + break; + case 's': + type = OS_TYPE_SOCK; + break; + default: + type = -EINVAL; + break; + } + + return(type); +} + +static int humfs_file_type(const char *path, int *dev_out, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int type; + + type = meta_type(path, dev_out, mount); + if(type != 0) + return(type); + + return(host_file_type(data_path, dev_out)); +} + +static char *humfs_data_name(struct inode *inode) +{ + struct externfs_data *ed = inode_externfs_info(inode); + struct humfs *mount = container_of(ed, struct humfs, ext); + + return(inode_name_prefix(inode, mount->data)); +} + +static struct externfs_inode *humfs_init_file(struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct humfs_file *hf; + + hf = (*mount->meta->init_file)(); + if(IS_ERR(hf)) + return((struct externfs_inode *) hf); + + hf->data.fd = -1; + return(&hf->ext); +} + +static int humfs_open_file(struct externfs_inode *ext, char *path, int uid, + int gid, struct inode *inode, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + const char *data_path[3] = { mount->data, path, NULL }; + struct openflags flags; + char tmp[HOSTFS_BUFSIZE], *file; + int err = -ENOMEM; + + file = get_path(data_path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + flags = of_rdwr(OPENFLAGS()); + if(mount->direct) + flags = of_direct(flags); + + if(path == NULL) + path = ""; + err = (*mount->meta->open_file)(hf, path, inode, mount); + if(err) + goto out_free; + + err = open_filehandle(file, flags, 0, &hf->data); + if(err == -EISDIR) + goto out; + else if(err == -EPERM){ + flags = of_set_rw(flags, 1, 0); + err = open_filehandle(file, flags, 0, &hf->data); + } + + if(err) + goto out_close; + + hf->mount = mount; + is_reclaimable(&hf->data, humfs_data_name, inode); + + out_free: + free_path(file, tmp); + out: + return(err); + + out_close: + (*mount->meta->close_file)(hf); + goto out_free; +} + +static void *humfs_open_dir(char *path, int uid, int gid, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + + return(host_open_dir(data_path)); +} + +static void humfs_close_dir(void *stream, struct externfs_data *ed) +{ + os_close_dir(stream); +} + +static char *humfs_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + + return(generic_host_read_dir(stream, pos, ino_out, len_out, mount)); +} + +LIST_HEAD(humfs_replies); + +struct humfs_aio { + struct aio_context aio; + struct list_head list; + void (*completion)(char *, int, void *); + char *buf; + int real_len; + int err; + void *data; +}; + +static int humfs_reply_fd = -1; + +struct humfs_aio last_task_aio, last_intr_aio; +struct humfs_aio *last_task_aio_ptr, *last_intr_aio_ptr; + +void humfs_task_proc(void *unused) +{ + struct humfs_aio *aio; + unsigned long flags; + + while(!list_empty(&humfs_replies)){ + local_irq_save(flags); + aio = list_entry(humfs_replies.next, struct humfs_aio, list); + + last_task_aio = *aio; + last_task_aio_ptr = aio; + + list_del(&aio->list); + local_irq_restore(flags); + + if(aio->err >= 0) + aio->err = aio->real_len; + (*aio->completion)(aio->buf, aio->err, aio->data); + kfree(aio); + } +} + +struct tq_struct humfs_task = { + .routine = humfs_task_proc, + .data = NULL +}; + +static void humfs_interrupt(int irq, void *dev_id, struct pt_regs *unused) +{ + struct aio_thread_reply reply; + struct humfs_aio *aio; + int err, fd = (int) dev_id; + + while(1){ + err = os_read_file(fd, &reply, sizeof(reply)); + if(err < 0){ + if(err == -EAGAIN) + break; + printk("humfs_interrupt - read returned err %d\n", + -err); + return; + } + aio = reply.data; + aio->err = reply.err; + list_add(&aio->list, &humfs_replies); + last_intr_aio = *aio; + last_intr_aio_ptr = aio; + } + + if(!list_empty(&humfs_replies)) + schedule_task(&humfs_task); + reactivate_fd(fd, HUMFS_IRQ); +} + +static int init_humfs_aio(void) +{ + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if(err){ + printk("init_humfs_aio - pipe failed, err = %d\n", -err); + goto out; + } + + err = um_request_irq(HUMFS_IRQ, fds[0], IRQ_READ, humfs_interrupt, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "humfs", + (void *) fds[0]); + if(err){ + printk("init_humfs_aio - : um_request_irq failed, err = %d\n", + err); + goto out_close; + } + + humfs_reply_fd = fds[1]; + goto out; + + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + out: + return(0); +} + +__initcall(init_humfs_aio); + +static int humfs_aio(enum aio_type type, int fd, unsigned long long offset, + char *buf, int len, int real_len, + void (*completion)(char *, int, void *), void *arg) +{ + struct humfs_aio *aio; + int err = -ENOMEM; + + aio = kmalloc(sizeof(*aio), GFP_KERNEL); + if(aio == NULL) + goto out; + *aio = ((struct humfs_aio) { .aio = INIT_AIO_CONTEXT, + .list = LIST_HEAD_INIT(aio->list), + .completion= completion, + .buf = buf, + .err = 0, + .real_len = real_len, + .data = arg }); + + err = submit_aio(type, fd, buf, len, offset, humfs_reply_fd, aio); + if(err) + (*completion)(buf, err, arg); + + out: + return(err); +} + +static int humfs_read_file(struct externfs_inode *ext, + unsigned long long offset, char *buf, int len, + int ignore_start, int ignore_end, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed) +{ + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + int fd = filehandle_fd(&hf->data); + + if(fd < 0){ + (*completion)(buf, fd, arg); + return(fd); + } + + return(humfs_aio(AIO_READ, fd, offset, buf, len, len, completion, + arg)); +} + +static int humfs_write_file(struct externfs_inode *ext, + unsigned long long offset, const char *buf, + int start, int len, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + int err, orig_len = len, fd = filehandle_fd(&hf->data); + + if(fd < 0){ + (*completion)((char *) buf, fd, arg); + return(fd); + } + + if(mount->direct) + len = PAGE_SIZE; + else { + offset += start; + buf += start; + } + + err = humfs_aio(AIO_WRITE, fd, offset, (char *) buf, len, orig_len, + completion, arg); + + if(err < 0) + return(err); + + if(mount->direct) + err = orig_len; + + return(err); +} + +static int humfs_map_file_page(struct externfs_inode *ext, + unsigned long long offset, char *buf, int w, + struct externfs_data *ed) +{ + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + unsigned long long size, need; + int err, fd = filehandle_fd(&hf->data); + + if(fd < 0) + return(fd); + + err = os_fd_size(fd, &size); + if(err) + return(err); + + need = offset + PAGE_SIZE; + if(size < need){ + err = os_truncate_fd(fd, need); + if(err) + return(err); + } + + return(physmem_subst_mapping(buf, fd, offset, w)); +} + +static void humfs_close_file(struct externfs_inode *ext, + unsigned long long size) +{ + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + int fd; + + if(hf->data.fd == -1) + return; + + fd = filehandle_fd(&hf->data); + physmem_forget_descriptor(fd); + truncate_file(&hf->data, size); + close_file(&hf->data); + + (*hf->mount->meta->close_file)(hf); +} + +/* XXX Assumes that you can't make a normal file */ + +static int humfs_make_node(const char *path, int mode, int uid, int gid, + int type, int major, int minor, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct file_handle fh; + const char *data_path[3] = { mount->data, path, NULL }; + int err; + char t; + + err = host_create_file(data_path, S_IRWXUGO, &fh); + if(err) + goto out; + + close_file(&fh); + + switch(type){ + case S_IFCHR: + t = 'c'; + break; + case S_IFBLK: + t = 'b'; + break; + case S_IFIFO: + t = 'p'; + break; + case S_IFSOCK: + t = 's'; + break; + default: + err = -EINVAL; + printk("humfs_make_node - bad node type : %d\n", type); + goto out_rm; + } + + err = (*mount->meta->make_node)(path, mode, uid, gid, t, major, minor, + mount); + if(err) + goto out_rm; + + out: + return(err); + + out_rm: + host_unlink_file(data_path); + goto out; +} + +static int humfs_create_file(struct externfs_inode *ext, char *path, int mode, + int uid, int gid, struct inode *inode, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int err; + + err = (*mount->meta->create_file)(hf, path, mode, uid, gid, inode, + mount); + if(err) + goto out; + + err = host_create_file(data_path, S_IRWXUGO, &hf->data); + if(err) + goto out_rm; + + + is_reclaimable(&hf->data, humfs_data_name, inode); + + return(0); + + out_rm: + (*mount->meta->remove_file)(path, mount); + (*mount->meta->close_file)(hf); + out: + return(err); +} + +static int humfs_set_attr(const char *path, struct externfs_iattr *attrs, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int (*chown)(const char *, int, int, int, struct humfs *); + int err; + + chown = mount->meta->change_ownerships; + if(attrs->ia_valid & EXTERNFS_ATTR_MODE){ + err = (*chown)(path, attrs->ia_mode, -1, -1, mount); + if(err) + return(err); + } + if(attrs->ia_valid & EXTERNFS_ATTR_UID){ + err = (*chown)(path, -1, attrs->ia_uid, -1, mount); + if(err) + return(err); + } + if(attrs->ia_valid & EXTERNFS_ATTR_GID){ + err = (*chown)(path, -1, -1, attrs->ia_gid, mount); + if(err) + return(err); + } + + attrs->ia_valid &= ~(EXTERNFS_ATTR_MODE | EXTERNFS_ATTR_UID | + EXTERNFS_ATTR_GID); + + return(host_set_attr(data_path, attrs)); +} + +static int humfs_make_symlink(const char *from, const char *to, int uid, + int gid, struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + struct humfs_file *hf; + const char *data_path[3] = { mount->data, from, NULL }; + int err = -ENOMEM; + + hf = (*mount->meta->init_file)(); + if(hf == NULL) + goto out; + + err = (*mount->meta->create_file)(hf, from, S_IRWXUGO, uid, gid, NULL, + mount); + if(err) + goto out_close; + + err = host_make_symlink(data_path, to); + if(err) + (*mount->meta->remove_file)(from, mount); + + out_close: + (*mount->meta->close_file)(hf); + out: + return(err); +} + +static int humfs_link_file(const char *to, const char *from, int uid, int gid, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path_from[3] = { mount->data, from, NULL }; + const char *data_path_to[3] = { mount->data, to, NULL }; + int err; + + err = (*mount->meta->create_link)(to, from, mount); + if(err) + return(err); + + err = host_link_file(data_path_to, data_path_from); + if(err) + (*mount->meta->remove_file)(from, mount); + + return(err); +} + +static int humfs_unlink_file(const char *path, struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int err; + + err = (*mount->meta->remove_file)(path, mount); + if (err) + return err; + + (*mount->meta->remove_file)(path, mount); + return(host_unlink_file(data_path)); +} + +static void humfs_invisible(struct externfs_inode *ext) +{ + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + struct humfs *mount = hf->mount; + + (*mount->meta->invisible)(hf); + not_reclaimable(&hf->data); +} + +static int humfs_make_dir(const char *path, int mode, int uid, int gid, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int err; + + err = (*mount->meta->create_dir)(path, mode, uid, gid, mount); + if(err) + return(err); + + err = host_make_dir(data_path, S_IRWXUGO); + if(err) + (*mount->meta->remove_dir)(path, mount); + + return(err); +} + +static int humfs_remove_dir(const char *path, int uid, int gid, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, path, NULL }; + int err; + + err = host_remove_dir(data_path); + if (err) + return err; + + (*mount->meta->remove_dir)(path, mount); + + return(err); +} + +static int humfs_read_link(char *file, int uid, int gid, char *buf, int size, + struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, file, NULL }; + + return(host_read_link(data_path, buf, size)); +} + +struct humfs *inode_humfs_info(struct inode *inode) +{ + return(container_of(inode_externfs_info(inode), struct humfs, ext)); +} + +static int humfs_rename_file(char *from, char *to, struct externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path_from[3] = { mount->data, from, NULL }; + const char *data_path_to[3] = { mount->data, to, NULL }; + int err; + + err = (*mount->meta->rename_file)(from, to, mount); + if(err) + return(err); + + err = host_rename_file(data_path_from, data_path_to); + if(err) + (*mount->meta->rename_file)(to, from, mount); + + return(err); +} + +static int humfs_stat_fs(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 externfs_data *ed) +{ + struct humfs *mount = container_of(ed, struct humfs, ext); + const char *data_path[3] = { mount->data, NULL }; + int err; + + /* XXX Needs to maintain this info as metadata */ + err = host_stat_fs(data_path, bsize_out, blocks_out, bfree_out, + bavail_out, files_out, ffree_out, fsid_out, + fsid_size, namelen_out, spare_out); + if(err) + return(err); + + *blocks_out = mount->total / *bsize_out; + *bfree_out = (mount->total - mount->used) / *bsize_out; + *bavail_out = (mount->total - mount->used) / *bsize_out; + return(0); +} + +int humfs_truncate_file(struct externfs_inode *ext, __u64 size, + struct externfs_data *ed) +{ + struct humfs_file *hf = container_of(ext, struct humfs_file, ext); + + return(truncate_file(&hf->data, size)); +} + +char *humfs_path(char *dir, char *file) +{ + int need_slash, len = strlen(dir) + strlen(file); + char *new; + + need_slash = (dir[strlen(dir) - 1] != '/'); + if(need_slash) + len++; + + new = kmalloc(len + 1, GFP_KERNEL); + if(new == NULL) + return(NULL); + + strcpy(new, dir); + if(need_slash) + strcat(new, "/"); + strcat(new, file); + + return(new); +} + +DECLARE_MUTEX(meta_sem); +struct list_head metas = LIST_HEAD_INIT(metas); + +static struct humfs_meta_ops *find_meta(const char *name) +{ + struct list_head *ele; + struct humfs_meta_ops *m; + + down(&meta_sem); + list_for_each(ele, &metas){ + m = list_entry(ele, struct humfs_meta_ops, list); + if(!strcmp(m->name, name)) + goto out; + } + m = NULL; + out: + up(&meta_sem); + return(m); +} + +void register_meta(struct humfs_meta_ops *ops) +{ + down(&meta_sem); + list_add(&ops->list, &metas); + up(&meta_sem); +} + +void unregister_meta(struct humfs_meta_ops *ops) +{ + down(&meta_sem); + list_del(&ops->list); + up(&meta_sem); +} + +static struct humfs *read_superblock(char *root) +{ + struct humfs *mount; + struct humfs_meta_ops *meta = NULL; + struct file_handle *fh; + const char *path[] = { root, "superblock", NULL }; + u64 used, total; + char meta_buf[33], line[HOSTFS_BUFSIZE], *newline; + unsigned long long pos; + int version, i, n, err; + + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if(fh == NULL) + return(ERR_PTR(-ENOMEM)); + + err = host_open_file(path, 1, 0, fh); + if(err){ + printk("Failed to open %s/%s, errno = %d\n", path[0], + path[1], err); + return(ERR_PTR(err)); + } + + used = 0; + total = 0; + pos = 0; + i = 0; + while(1){ + n = read_file(fh, pos, &line[i], sizeof(line) - i - 1); + if((n == 0) && (i == 0)) + break; + if(n < 0) + return(ERR_PTR(n)); + + pos += n; + if(n > 0) + line[n + i] = '\0'; + + newline = strchr(line, '\n'); + if(newline == NULL){ + printk("read_superblock - line too long : '%s'\n", + line); + return(ERR_PTR(-EINVAL)); + } + newline++; + + if(sscanf(line, "version %d\n", &version) == 1){ + if(version != HUMFS_VERSION){ + printk("humfs version mismatch - want version " + "%d, got version %d.\n", HUMFS_VERSION, + version); + return(ERR_PTR(-EINVAL)); + } + } + else if(sscanf(line, "used %Lu\n", &used) == 1) ; + else if(sscanf(line, "total %Lu\n", &total) == 1) ; + else if(sscanf(line, "metadata %32s\n", meta_buf) == 1){ + meta = find_meta(meta_buf); + if(meta == NULL){ + printk("read_superblock - meta api \"%s\" not " + "registered\n", meta_buf); + return(ERR_PTR(-EINVAL)); + } + } + + else { + printk("read_superblock - bogus line : '%s'\n", line); + return(ERR_PTR(-EINVAL)); + } + + i = newline - line; + memmove(line, newline, sizeof(line) - i); + i = strlen(line); + } + + if(used == 0){ + printk("read_superblock - used not specified or set to " + "zero\n"); + return(ERR_PTR(-EINVAL)); + } + if(total == 0){ + printk("read_superblock - total not specified or set to " + "zero\n"); + return(ERR_PTR(-EINVAL)); + } + if(used > total){ + printk("read_superblock - used is greater than total\n"); + return(ERR_PTR(-EINVAL)); + } + + if(meta == NULL){ + meta = find_meta("shadow_fs"); + } + + if(meta == NULL){ + printk("read_superblock - valid meta api was not specified\n"); + return(ERR_PTR(-EINVAL)); + } + + mount = (*meta->init_mount)(root); + if(IS_ERR(mount)) + return(mount); + + *mount = ((struct humfs) { .total = total, + .used = used, + .meta = meta }); + return(mount); +} + +struct externfs_file_ops humfs_no_mmap_file_ops = { + .stat_file = humfs_stat_file, + .file_type = humfs_file_type, + .access_file = NULL, + .open_file = humfs_open_file, + .open_dir = humfs_open_dir, + .read_dir = humfs_read_dir, + .read_file = humfs_read_file, + .write_file = humfs_write_file, + .map_file_page = NULL, + .close_file = humfs_close_file, + .close_dir = humfs_close_dir, + .invisible = humfs_invisible, + .create_file = humfs_create_file, + .set_attr = humfs_set_attr, + .make_symlink = humfs_make_symlink, + .unlink_file = humfs_unlink_file, + .make_dir = humfs_make_dir, + .remove_dir = humfs_remove_dir, + .make_node = humfs_make_node, + .link_file = humfs_link_file, + .read_link = humfs_read_link, + .rename_file = humfs_rename_file, + .statfs = humfs_stat_fs, + .truncate_file = humfs_truncate_file +}; + +struct externfs_file_ops humfs_mmap_file_ops = { + .stat_file = humfs_stat_file, + .file_type = humfs_file_type, + .access_file = NULL, + .open_file = humfs_open_file, + .open_dir = humfs_open_dir, + .read_dir = humfs_read_dir, + .read_file = humfs_read_file, + .write_file = humfs_write_file, + .map_file_page = humfs_map_file_page, + .close_file = humfs_close_file, + .close_dir = humfs_close_dir, + .invisible = humfs_invisible, + .create_file = humfs_create_file, + .set_attr = humfs_set_attr, + .make_symlink = humfs_make_symlink, + .unlink_file = humfs_unlink_file, + .make_dir = humfs_make_dir, + .remove_dir = humfs_remove_dir, + .make_node = humfs_make_node, + .link_file = humfs_link_file, + .read_link = humfs_read_link, + .rename_file = humfs_rename_file, + .statfs = humfs_stat_fs, + .truncate_file = humfs_truncate_file +}; + +static struct externfs_data *mount_fs(char *mount_arg) +{ + char *root, *data, *flags; + struct humfs *mount; + struct externfs_file_ops *file_ops; + int err, do_mmap = 0; + + if(mount_arg == NULL){ + printk("humfs - no host directory specified\n"); + return(NULL); + } + + flags = strchr((char *) mount_arg, ','); + if(flags != NULL){ + do { + *flags++ = '\0'; + + if(!strcmp(flags, "mmap")) + do_mmap = 1; + + flags = strchr(flags, ','); + } while(flags != NULL); + } + + err = -ENOMEM; + root = host_root_filename(mount_arg); + if(root == NULL) + goto err; + + mount = read_superblock(root); + if(IS_ERR(mount)){ + err = PTR_ERR(mount); + goto err_free_root; + } + + data = humfs_path(root, "data/"); + if(data == NULL) + goto err_free_mount; + + if(CHOOSE_MODE(do_mmap, 0)){ + printk("humfs doesn't support mmap in tt mode\n"); + do_mmap = 0; + } + + mount->data = data; + mount->mmap = do_mmap; + + file_ops = do_mmap ? &humfs_mmap_file_ops : &humfs_no_mmap_file_ops; + init_externfs(&mount->ext, file_ops); + + return(&mount->ext); + + err_free_mount: + kfree(mount); + err_free_root: + kfree(root); + err: + return(NULL); +} + +struct externfs_mount_ops humfs_mount_ops = { + .init_file = humfs_init_file, + .mount = mount_fs, +}; + +static int __init init_humfs(void) +{ + return(register_externfs("humfs", &humfs_mount_ops)); +} + +static void __exit exit_humfs(void) +{ + unregister_externfs("humfs"); +} + +__initcall(init_humfs); +__exitcall(exit_humfs); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/fs/hostfs/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/Makefile 2005-05-03 22:28:14.284438648 +0300 @@ -0,0 +1,14 @@ +# +# Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com) +# Licensed under the GPL +# + +O_TARGET := hostfs.o + +obj-$(CONFIG_EXTERNFS) += externfs.o +obj-$(CONFIG_HOSTFS) += host_fs.o host_file.o +obj-$(CONFIG_HUMFS) += humfs.o host_file.o meta_fs.o + +obj-m = $(O_TARGET) + +include $(TOPDIR)/Rules.make Index: linux-2.4.29/arch/um/fs/hostfs/metadata.h =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/metadata.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/metadata.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2004 Piotr Neuman (sikkh@wp.pl) and + * Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __UM_FS_METADATA +#define __UM_FS_METADATA + +#include "linux/fs.h" +#include "linux/list.h" +#include "os.h" +#include "hostfs.h" +#include "filehandle.h" + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct humfs { + struct externfs_data ext; + __u64 used; + __u64 total; + char *data; + int mmap; + int direct; + struct humfs_meta_ops *meta; +}; + +struct humfs_file { + struct humfs *mount; + struct file_handle data; + struct externfs_inode ext; +}; + +struct humfs_meta_ops { + struct list_head list; + char *name; + struct humfs_file *(*init_file)(void); + int (*open_file)(struct humfs_file *hf, const char *path, + struct inode *inode, struct humfs *humfs); + int (*create_file)(struct humfs_file *hf, const char *path, int mode, + int uid, int gid, struct inode *inode, + struct humfs *humfs); + void (*close_file)(struct humfs_file *humfs); + int (*ownerships)(const char *path, int *mode_out, int *uid_out, + int *gid_out, char *type_out, int *maj_out, + int *min_out, struct humfs *humfs); + int (*make_node)(const char *path, int mode, int uid, int gid, + int type, int major, int minor, struct humfs *humfs); + int (*create_link)(const char *to, const char *from, + struct humfs *humfs); + int (*remove_file)(const char *path, struct humfs *humfs); + int (*create_dir)(const char *path, int mode, int uid, int gid, + struct humfs *humfs); + int (*remove_dir)(const char *path, struct humfs *humfs); + int (*change_ownerships)(const char *path, int mode, int uid, int gid, + struct humfs *humfs); + int (*rename_file)(const char *from, const char *to, + struct humfs *humfs); + void (*invisible)(struct humfs_file *hf); + struct humfs *(*init_mount)(char *root); + void (*free_mount)(struct humfs *humfs); +}; + +void register_meta(struct humfs_meta_ops *ops); +void unregister_meta(struct humfs_meta_ops *ops); + +char *humfs_path(char *dir, char *file); +char *humfs_name(struct inode *inode, char *prefix); +extern struct humfs *inode_humfs_info(struct inode *inode); + +#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: + */ Index: linux-2.4.29/arch/um/fs/hostfs/meta_fs.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hostfs/meta_fs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hostfs/meta_fs.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <linux/slab.h> +#include "hostfs.h" +#include "metadata.h" +#include "kern_util.h" + +#define METADATA_FILE_PATH(meta) (meta)->root, "file_metadata" +#define METADATA_DIR_PATH(meta) (meta)->root, "dir_metadata" + +struct meta_fs { + struct humfs humfs; + char *root; +}; + +struct meta_file { + struct humfs_file humfs; + struct file_handle fh; +}; + +static int meta_file_path(const char *path, struct meta_fs *meta, + const char *path_out[]) +{ + const char *data_path[] = { meta->root, "data", path, NULL }; + char data_tmp[HOSTFS_BUFSIZE]; + char *data_file = get_path(data_path, data_tmp, sizeof(data_tmp)); + + if(data_file == NULL) + return(-ENOMEM); + + path_out[0] = meta->root; + path_out[2] = path; + if(os_file_type(data_file) == OS_TYPE_DIR){ + path_out[1] = "dir_metadata"; + path_out[3] = "metadata"; + path_out[4] = NULL; + } + else { + path_out[1] = "file_metadata"; + path_out[3] = NULL; + } + + return(0); +} + +static int open_meta_file(const char *path, struct humfs *humfs, + struct file_handle *fh) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + const char *meta_path[5]; + char meta_tmp[HOSTFS_BUFSIZE]; + char *meta_file; + int err; + + err = meta_file_path(path, meta, meta_path); + if(err) + goto out; + + meta_file = get_path(meta_path, meta_tmp, sizeof(meta_tmp)); + if(meta_file == NULL) + goto out; + + err = open_filehandle(meta_file, of_rdwr(OPENFLAGS()), 0, fh); + + out: + return(err); +} + +static char *meta_fs_name(struct inode *inode) +{ + struct humfs *mount = inode->i_sb->u.generic_sbp; + struct meta_fs *meta = container_of(mount, struct meta_fs, humfs); + const char *metadata_path[5]; + char tmp[HOSTFS_BUFSIZE], *name, *file; + + if(meta_file_path("", meta, metadata_path)) + return(NULL); + + file = get_path(metadata_path, tmp, sizeof(tmp)); + if(file == NULL) + return(NULL); + + name = inode_name_prefix(inode, file); + + free_path(file, tmp); + return(name); +} + +static void metafs_invisible(struct humfs_file *hf) +{ + struct meta_file *mf = container_of(hf, struct meta_file, humfs); + + not_reclaimable(&mf->fh); +} + +static struct humfs_file *metafs_init_file(void) +{ + struct meta_file *mf; + int err = -ENOMEM; + + mf = kmalloc(sizeof(*mf), GFP_KERNEL); + if(mf == NULL) + return(ERR_PTR(err)); + + return(&mf->humfs); +} + +static int metafs_open_file(struct humfs_file *hf, const char *path, + struct inode *inode, struct humfs *humfs) +{ + struct meta_file *mf = container_of(hf, struct meta_file, humfs); + int err; + + err = open_meta_file(path, humfs, &mf->fh); + if(err) + return(err); + + is_reclaimable(&mf->fh, meta_fs_name, inode); + + return(0); +} + +static void metafs_close_file(struct humfs_file *hf) +{ + struct meta_file *meta = container_of(hf, struct meta_file, humfs); + + close_file(&meta->fh); + kfree(meta); +} + +static int metafs_create_file(struct humfs_file *hf, const char *path, + int mode, int uid, int gid, struct inode *inode, + struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + struct meta_file *mf = container_of(hf, struct meta_file, humfs); + char tmp[HOSTFS_BUFSIZE]; + const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL }; + char *file = get_path(metadata_path, tmp, sizeof(tmp)); + char buf[sizeof("mmmm uuuuuuuuuu gggggggggg")]; + int err = -ENOMEM; + + if(file == NULL) + goto out; + + err = open_filehandle(file, of_write(of_create(OPENFLAGS())), 0644, + &mf->fh); + if(err) + goto out_free_path; + + if(inode != NULL) + is_reclaimable(&mf->fh, meta_fs_name, inode); + + sprintf(buf, "%d %d %d\n", mode & S_IRWXUGO, uid, gid); + err = write_file(&mf->fh, 0, buf, strlen(buf)); + if(err < 0) + goto out_rm; + + free_path(file, tmp); + return(0); + + out_rm: + close_file(&mf->fh); + os_remove_file(file); + out_free_path: + free_path(file, tmp); + out: + return(err); +} + +static int metafs_create_link(const char *to, const char *from, + struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + const char *path_to[] = { METADATA_FILE_PATH(meta), to, NULL }; + const char *path_from[] = { METADATA_FILE_PATH(meta), from, NULL }; + + return(host_link_file(path_to, path_from)); +} + +static int metafs_remove_file(const char *path, struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + char tmp[HOSTFS_BUFSIZE]; + const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL }; + char *file = get_path(metadata_path, tmp, sizeof(tmp)); + int err = -ENOMEM; + + if(file == NULL) + goto out; + + err = os_remove_file(file); + + out: + free_path(file, tmp); + return(err); +} + +static int metafs_create_directory(const char *path, int mode, int uid, + int gid, struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + char tmp[HOSTFS_BUFSIZE]; + const char *dir_path[] = { METADATA_DIR_PATH(meta), path, NULL, NULL }; + const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL, + NULL }; + char *file, dir_meta[sizeof("mmmm uuuuuuuuuu gggggggggg\n")]; + int err, fd; + + err = host_make_dir(dir_path, 0755); + if(err) + goto out; + + err = host_make_dir(file_path, 0755); + if(err) + goto out_rm; + + /* This to make the index independent of the number of elements in + * METADATA_DIR_PATH(). + */ + dir_path[sizeof(dir_path) / sizeof(dir_path[0]) - 2] = "metadata"; + + err = -ENOMEM; + file = get_path(dir_path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + fd = os_open_file(file, of_create(of_rdwr(OPENFLAGS())), 0644); + if(fd < 0){ + err = fd; + goto out_free; + } + + sprintf(dir_meta, "%d %d %d\n", mode & S_IRWXUGO, uid, gid); + err = os_write_file(fd, dir_meta, strlen(dir_meta)); + if(err > 0) + err = 0; + + os_close_file(fd); + + out_free: + free_path(file, tmp); + out_rm: + host_remove_dir(dir_path); + out: + return(err); +} + +static int metafs_remove_directory(const char *path, struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + char tmp[HOSTFS_BUFSIZE], *file; + const char *dir_path[] = { METADATA_DIR_PATH(meta), path, "metadata", + NULL }; + const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL }; + char *slash; + int err; + + err = -ENOMEM; + file = get_path(dir_path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_remove_file(file); + if(err) + goto out_free; + + slash = strrchr(file, '/'); + if(slash == NULL){ + printk("remove_shadow_directory failed to find last slash\n"); + goto out_free; + } + *slash = '\0'; + err = os_remove_dir(file); + free_path(file, tmp); + + file = get_path(file_path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = os_remove_dir(file); + if(err) + goto out_free; + + out: + return(err); + out_free: + free_path(file, tmp); + goto out; +} + +static int metafs_make_node(const char *path, int mode, int uid, int gid, + int type, int maj, int min, struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + struct file_handle fh; + char tmp[HOSTFS_BUFSIZE]; + const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL }; + int err; + char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")], *file; + + sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid, type, + maj, min); + + err = -ENOMEM; + file = get_path(metadata_path, tmp, sizeof(tmp)); + if(file == NULL) + goto out; + + err = open_filehandle(file, + of_create(of_rdwr(OPENFLAGS())), 0644, &fh); + if(err) + goto out_free; + + err = write_file(&fh, 0, buf, strlen(buf)); + if(err > 0) + err = 0; + + close_file(&fh); + + out_free: + free_path(file, tmp); + out: + return(err); +} + +static int metafs_ownerships(const char *path, int *mode_out, int *uid_out, + int *gid_out, char *type_out, int *maj_out, + int *min_out, struct humfs *humfs) +{ + struct file_handle fh; + char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")]; + int err, n, mode, uid, gid, maj, min; + char type; + + err = open_meta_file(path, humfs, &fh); + if(err) + goto out; + + err = os_read_file(fh.fd, buf, sizeof(buf) - 1); + if(err < 0) + goto out_close; + + buf[err] = '\0'; + err = 0; + + n = sscanf(buf, "%d %d %d %c %d %d", &mode, &uid, &gid, &type, &maj, + &min); + if(n == 3){ + maj = -1; + min = -1; + type = 0; + err = 0; + } + else if(n != 6) + err = -EINVAL; + + if(mode_out != NULL) + *mode_out = mode; + if(uid_out != NULL) + *uid_out = uid; + if(gid_out != NULL) + *gid_out = uid; + if(type_out != NULL) + *type_out = type; + if(maj_out != NULL) + *maj_out = maj; + if(min_out != NULL) + *min_out = min; + + out_close: + close_file(&fh); + out: + return(err); +} + +static int metafs_change_ownerships(const char *path, int mode, int uid, + int gid, struct humfs *humfs) +{ + struct file_handle fh; + char type; + char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")]; + int err = -ENOMEM, old_mode, old_uid, old_gid, n, maj, min; + + err = open_meta_file(path, humfs, &fh); + if(err) + goto out; + + err = read_file(&fh, 0, buf, sizeof(buf) - 1); + if(err < 0) + goto out_close; + + buf[err] = '\0'; + + n = sscanf(buf, "%d %d %d %c %d %d\n", &old_mode, &old_uid, &old_gid, + &type, &maj, &min); + if((n != 3) && (n != 6)){ + err = -EINVAL; + goto out_close; + } + + if(mode == -1) + mode = old_mode; + if(uid == -1) + uid = old_uid; + if(gid == -1) + gid = old_gid; + + if(n == 3) + sprintf(buf, "%d %d %d\n", mode & S_IRWXUGO, uid, gid); + else + sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid, + type, maj, min); + + err = write_file(&fh, 0, buf, strlen(buf)); + if(err > 0) + err = 0; + + err = truncate_file(&fh, strlen(buf)); + + out_close: + close_file(&fh); + out: + return(err); +} + +static int metafs_rename_file(const char *from, const char *to, + struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + const char *metadata_path_from[5], *metadata_path_to[5]; + int err; + + err = meta_file_path(from, meta, metadata_path_from); + if(err) + return(err); + + err = meta_file_path(to, meta, metadata_path_to); + if(err) + return(err); + + return(host_rename_file(metadata_path_from, metadata_path_to)); +} + +static struct humfs *metafs_init_mount(char *root) +{ + struct meta_fs *meta; + int err = -ENOMEM; + + meta = kmalloc(sizeof(*meta), GFP_KERNEL); + if(meta == NULL) + goto out; + + meta->root = uml_strdup(root); + if(meta->root == NULL) + goto out_free_meta; + + return(&meta->humfs); + + out_free_meta: + kfree(meta); + out: + return(ERR_PTR(err)); +} + +static void metafs_free_mount(struct humfs *humfs) +{ + struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs); + + kfree(meta); +} + +struct humfs_meta_ops hum_fs_meta_fs_ops = { + .list = LIST_HEAD_INIT(hum_fs_meta_fs_ops.list), + .name = "shadow_fs", + .init_file = metafs_init_file, + .open_file = metafs_open_file, + .close_file = metafs_close_file, + .ownerships = metafs_ownerships, + .make_node = metafs_make_node, + .create_file = metafs_create_file, + .create_link = metafs_create_link, + .remove_file = metafs_remove_file, + .create_dir = metafs_create_directory, + .remove_dir = metafs_remove_directory, + .change_ownerships = metafs_change_ownerships, + .rename_file = metafs_rename_file, + .invisible = metafs_invisible, + .init_mount = metafs_init_mount, + .free_mount = metafs_free_mount, +}; + +static int __init init_meta_fs(void) +{ + register_meta(&hum_fs_meta_fs_ops); + return(0); +} + +static void __exit exit_meta_fs(void) +{ + unregister_meta(&hum_fs_meta_fs_ops); +} + +__initcall(init_meta_fs); +__exitcall(exit_meta_fs); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/fs/hppfs/hppfs_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/fs/hppfs/hppfs_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hppfs/hppfs_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/fs/hppfs/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/fs/hppfs/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/hppfs/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/fs/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/fs/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/fs/Makefile 2005-05-03 22:28:14.291437584 +0300 @@ -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: Index: linux-2.4.29/arch/um/include/2_5compat.h =================================================================== --- linux-2.4.29.orig/arch/um/include/2_5compat.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/2_5compat.h 2005-05-03 22:28:14.292437432 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/aio.h =================================================================== --- linux-2.4.29.orig/arch/um/include/aio.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/aio.h 2005-05-03 22:28:14.293437280 +0300 @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef AIO_H__ +#define AIO_H__ + +enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP }; + +struct aio_thread_reply { + void *data; + int err; +}; + +struct aio_context { + int reply_fd; +}; + +#define INIT_AIO_CONTEXT { .reply_fd = -1 } + +extern int submit_aio(enum aio_type type, int fd, char *buf, int len, + unsigned long long offset, int reply_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: + */ Index: linux-2.4.29/arch/um/include/chan_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/chan_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/chan_kern.h 2005-05-03 22:28:14.294437128 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/chan_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/chan_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/chan_user.h 2005-05-03 22:28:14.295436976 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/choose-mode.h =================================================================== --- linux-2.4.29.orig/arch/um/include/choose-mode.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/choose-mode.h 2005-05-03 22:28:14.295436976 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/filehandle.h =================================================================== --- linux-2.4.29.orig/arch/um/include/filehandle.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/filehandle.h 2005-05-03 22:28:14.296436824 +0300 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __FILEHANDLE_H__ +#define __FILEHANDLE_H__ + +#include "linux/list.h" +#include "linux/fs.h" +#include "os.h" + +struct file_handle { + struct list_head list; + int fd; + char *(*get_name)(struct inode *); + struct inode *inode; + struct openflags flags; +}; + +extern struct file_handle bad_filehandle; + +extern int open_file(char *name, struct openflags flags, int mode); +extern void *open_dir(char *file); +extern int open_filehandle(char *name, struct openflags flags, int mode, + struct file_handle *fh); +extern int read_file(struct file_handle *fh, unsigned long long offset, + char *buf, int len); +extern int write_file(struct file_handle *fh, unsigned long long offset, + const char *buf, int len); +extern int truncate_file(struct file_handle *fh, unsigned long long size); +extern int close_file(struct file_handle *fh); +extern void not_reclaimable(struct file_handle *fh); +extern void is_reclaimable(struct file_handle *fh, + char *(name_proc)(struct inode *), + struct inode *inode); +extern int filehandle_fd(struct file_handle *fh); +extern int make_pipe(struct file_handle *fhs); + +#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: + */ Index: linux-2.4.29/arch/um/include/frame.h =================================================================== --- linux-2.4.29.orig/arch/um/include/frame.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/frame.h 2005-05-03 22:28:14.297436672 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/frame_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/frame_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/frame_kern.h 2005-05-03 22:28:14.298436520 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/frame_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/frame_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/frame_user.h 2005-05-03 22:28:14.299436368 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/helper.h =================================================================== --- linux-2.4.29.orig/arch/um/include/helper.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/helper.h 2005-05-03 22:28:14.300436216 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/init.h =================================================================== --- linux-2.4.29.orig/arch/um/include/init.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/init.h 2005-05-03 22:28:14.301436064 +0300 @@ -0,0 +1,124 @@ +#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"))) + +#ifndef __KERNEL__ + +#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn +#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn + +#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) + +#endif + +#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: + */ Index: linux-2.4.29/arch/um/include/initrd.h =================================================================== --- linux-2.4.29.orig/arch/um/include/initrd.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/initrd.h 2005-05-03 22:28:14.301436064 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/irq_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/irq_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/irq_kern.h 2005-05-03 22:28:14.303435760 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/irq_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/irq_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/irq_user.h 2005-05-03 22:28:14.304435608 +0300 @@ -0,0 +1,36 @@ +/* + * 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 int deactivate_all_fds(void); +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: + */ Index: linux-2.4.29/arch/um/include/kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/kern.h 2005-05-03 22:28:14.304435608 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/kern_util.h =================================================================== --- linux-2.4.29.orig/arch/um/include/kern_util.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/kern_util.h 2005-05-03 22:28:14.306435304 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/line.h =================================================================== --- linux-2.4.29.orig/arch/um/include/line.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/line.h 2005-05-03 22:28:14.307435152 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/include/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,7 @@ +all : sc.h + +sc.h : ../util/mk_sc + ../util/mk_sc > $@ + +../util/mk_sc : + $(MAKE) -C ../util mk_sc Index: linux-2.4.29/arch/um/include/mconsole.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mconsole.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mconsole.h 2005-05-03 22:28:14.309434848 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/mconsole_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mconsole_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mconsole_kern.h 2005-05-03 22:28:14.310434696 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/mem.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mem.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mem.h 2005-05-03 22:28:14.310434696 +0300 @@ -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(const void *virt, int fd, __u64 offset); +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: + */ Index: linux-2.4.29/arch/um/include/mem_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mem_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mem_kern.h 2005-05-03 22:28:14.311434544 +0300 @@ -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, int); +}; + +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: + */ Index: linux-2.4.29/arch/um/include/mem_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mem_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mem_user.h 2005-05-03 22:28:14.313434240 +0300 @@ -0,0 +1,82 @@ +/* + * 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); +extern void check_tmpexec(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: + */ Index: linux-2.4.29/arch/um/include/mode.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mode.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mode.h 2005-05-03 22:28:14.313434240 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/mode_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/mode_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/mode_kern.h 2005-05-03 22:28:14.314434088 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/net_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/net_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/net_kern.h 2005-05-03 22:28:14.315433936 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/net_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/net_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/net_user.h 2005-05-03 22:28:14.316433784 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/os.h =================================================================== --- linux-2.4.29.orig/arch/um/include/os.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/os.h 2005-05-03 22:28:14.318433480 +0300 @@ -0,0 +1,221 @@ +/* + * 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_major; /* device */ + int ust_minor; + 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 */ + int ust_rmajor; + int ust_rminor; +}; + +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 */ + unsigned int d : 1; /* O_DIRECT */ +}; + +#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ + .t = 0, .a = 0, .e = 0, .cl = 0, \ + .d = 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); +} + +static inline struct openflags of_direct(struct openflags flags) +{ + flags.d = 1; + return(flags); +} + +extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_lstat_file(const char *file_name, struct uml_stat *ubuf); +extern int os_stat_fd(const int fd, struct uml_stat *buf); +extern int os_access(const char *file, int mode); +extern int os_set_file_time(const char *file, unsigned long access, + unsigned long mod); +extern int os_set_file_perms(const char *file, int mode); +extern int os_set_file_owner(const char *file, int owner, int group); +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 void *os_open_dir(char *dir, int *err_out); +extern int os_seek_dir(void *stream, unsigned long long pos); +extern int os_read_dir(void *stream, unsigned long long *ino_out, + char **name_out); +extern int os_tell_dir(void *stream); +extern int os_close_dir(void *stream); +extern int os_remove_file(const char *file); +extern int os_move_file(const char *from, const char *to); +extern int os_truncate_file(const char *file, unsigned long long len); +extern int os_truncate_fd(int fd, unsigned long long len); +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_fd_size(int fd, 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_clear_fd_async(int fd); +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_make_symlink(const char *to, const char *from); +extern int os_read_symlink(const char *file, char *buf, int size); +extern int os_link_file(const char *to, const char *from); +extern int os_make_dir(const char *dir, int mode); +extern int os_remove_dir(const char *dir); +extern int os_make_dev(const char *name, int mode, int major, int minor); +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); +extern int os_stat_filesystem(char *path, 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); +extern unsigned long long os_usecs(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: + */ Index: linux-2.4.29/arch/um/include/process.h =================================================================== --- linux-2.4.29.orig/arch/um/include/process.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/process.h 2005-05-03 22:28:14.319433328 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/ptrace_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/ptrace_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/ptrace_user.h 2005-05-03 22:28:14.319433328 +0300 @@ -0,0 +1,25 @@ +/* + * 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" + +/* syscall emulation path in ptrace */ +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +extern int use_sysemu; + +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 Index: linux-2.4.29/arch/um/include/sigcontext.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sigcontext.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sigcontext.h 2005-05-03 22:28:14.320433176 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sigio.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sigio.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sigio.h 2005-05-03 22:28:14.321433024 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/signal_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/signal_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/signal_kern.h 2005-05-03 22:28:14.322432872 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/signal_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/signal_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/signal_user.h 2005-05-03 22:28:14.323432720 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/skas_ptrace.h =================================================================== --- linux-2.4.29.orig/arch/um/include/skas_ptrace.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/skas_ptrace.h 2005-05-03 22:28:14.323432720 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/syscall_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/syscall_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/syscall_user.h 2005-05-03 22:28:14.324432568 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/checksum.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/checksum.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/checksum.h 2005-05-03 22:28:14.326432264 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/frame.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/frame.h 2005-05-03 22:28:14.351428464 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/frame_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/frame_kern.h 2005-05-03 22:28:14.352428312 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/frame_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/frame_user.h 2005-05-03 22:28:14.353428160 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/ptrace.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/ptrace.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/ptrace.h 2005-05-03 22:28:14.355427856 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/ptrace_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/ptrace_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/ptrace_user.h 2005-05-03 22:28:14.356427704 +0300 @@ -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 Index: linux-2.4.29/arch/um/include/sysdep-i386/sigcontext.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/sigcontext.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/sigcontext.h 2005-05-03 22:28:14.357427552 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-i386/syscalls.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-i386/syscalls.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-i386/syscalls.h 2005-05-03 22:28:14.358427400 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ia64/ptrace.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ia64/ptrace.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ia64/ptrace.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ia64/sigcontext.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ia64/sigcontext.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ia64/sigcontext.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ia64/syscalls.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ia64/syscalls.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ia64/syscalls.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ppc/ptrace.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ppc/ptrace.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ppc/ptrace.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ppc/sigcontext.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ppc/sigcontext.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ppc/sigcontext.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysdep-ppc/syscalls.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysdep-ppc/syscalls.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysdep-ppc/syscalls.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/sysrq.h =================================================================== --- linux-2.4.29.orig/arch/um/include/sysrq.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/sysrq.h 2005-05-03 22:28:14.364426488 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SYSRQ_H +#define __UM_SYSRQ_H + +extern void show_trace(unsigned long *stack); + +#endif Index: linux-2.4.29/arch/um/include/tempfile.h =================================================================== --- linux-2.4.29.orig/arch/um/include/tempfile.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/tempfile.h 2005-05-03 22:28:14.365426336 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/time_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/time_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/time_user.h 2005-05-03 22:28:14.366426184 +0300 @@ -0,0 +1,18 @@ +/* + * 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 void disable_timer(void); +extern unsigned long time_lock(void); +extern void time_unlock(unsigned long); + +#endif Index: linux-2.4.29/arch/um/include/tlb.h =================================================================== --- linux-2.4.29.orig/arch/um/include/tlb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/tlb.h 2005-05-03 22:28:14.367426032 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/ubd_user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/ubd_user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/ubd_user.h 2005-05-03 22:28:14.368425880 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/umid.h =================================================================== --- linux-2.4.29.orig/arch/um/include/umid.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/umid.h 2005-05-03 22:28:14.368425880 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/uml_uaccess.h =================================================================== --- linux-2.4.29.orig/arch/um/include/uml_uaccess.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/uml_uaccess.h 2005-05-03 22:28:14.369425728 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/um_mmu.h =================================================================== --- linux-2.4.29.orig/arch/um/include/um_mmu.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/um_mmu.h 2005-05-03 22:28:14.370425576 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/umn.h =================================================================== --- linux-2.4.29.orig/arch/um/include/umn.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/umn.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/um_uaccess.h =================================================================== --- linux-2.4.29.orig/arch/um/include/um_uaccess.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/um_uaccess.h 2005-05-03 22:28:14.372425272 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/include/user.h =================================================================== --- linux-2.4.29.orig/arch/um/include/user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/user.h 2005-05-03 22:28:14.373425120 +0300 @@ -0,0 +1,31 @@ +/* + * 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); +extern void *um_vmalloc(int size); +extern void vfree(void *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: + */ Index: linux-2.4.29/arch/um/include/user_util.h =================================================================== --- linux-2.4.29.orig/arch/um/include/user_util.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/include/user_util.h 2005-05-03 22:28:14.374424968 +0300 @@ -0,0 +1,105 @@ +/* + * 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" + +#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR)) + +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 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 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); +extern int setjmp_wrapper(void (*proc)(void *, void *), ...); +extern int raw(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: + */ Index: linux-2.4.29/arch/um/kernel/checksum.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/checksum.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/checksum.c 2005-05-03 22:28:14.375424816 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/common.ld.in =================================================================== --- linux-2.4.29.orig/arch/um/kernel/common.ld.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/common.ld.in 2005-05-03 22:28:14.000000000 +0300 @@ -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) } Index: linux-2.4.29/arch/um/kernel/config.c.in =================================================================== --- linux-2.4.29.orig/arch/um/kernel/config.c.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/config.c.in 2005-05-03 22:28:14.406420104 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/dyn_link.ld.in =================================================================== --- linux-2.4.29.orig/arch/um/kernel/dyn_link.ld.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/dyn_link.ld.in 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,169 @@ +OUTPUT_FORMAT("ELF_FORMAT") +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) + +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/kernel/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) } +} Index: linux-2.4.29/arch/um/kernel/exec_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/exec_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/exec_kern.c 2005-05-03 22:28:14.408419800 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/exitcode.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/exitcode.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/exitcode.c 2005-05-03 22:28:14.409419648 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/filehandle.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/filehandle.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/filehandle.c 2005-05-03 22:28:14.410419496 +0300 @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/slab.h" +#include "linux/list.h" +#include "linux/spinlock.h" +#include "linux/fs.h" +#include "linux/errno.h" +#include "filehandle.h" +#include "os.h" +#include "kern_util.h" + +static spinlock_t open_files_lock = SPIN_LOCK_UNLOCKED; +static struct list_head open_files = LIST_HEAD_INIT(open_files); + +#define NUM_RECLAIM 128 + +static void reclaim_fds(void) +{ + struct file_handle *victim; + int closed = NUM_RECLAIM; + + spin_lock(&open_files_lock); + while(!list_empty(&open_files) && closed--){ + victim = list_entry(open_files.prev, struct file_handle, list); + os_close_file(victim->fd); + victim->fd = -1; + list_del_init(&victim->list); + } + spin_unlock(&open_files_lock); +} + +int open_file(char *name, struct openflags flags, int mode) +{ + int fd; + + fd = os_open_file(name, flags, mode); + if(fd != -EMFILE) + return(fd); + + reclaim_fds(); + fd = os_open_file(name, flags, mode); + + return(fd); +} + +void *open_dir(char *file) +{ + void *dir; + int err; + + dir = os_open_dir(file, &err); + if(dir != NULL) + return(dir); + if(err != -EMFILE) + return(ERR_PTR(err)); + + reclaim_fds(); + + dir = os_open_dir(file, &err); + if(dir == NULL) + dir = ERR_PTR(err); + + return(dir); +} + +void not_reclaimable(struct file_handle *fh) +{ + char *name; + + if(fh->get_name == NULL) + return; + + if(list_empty(&fh->list)){ + name = (*fh->get_name)(fh->inode); + if(name != NULL){ + fh->fd = open_file(name, fh->flags, 0); + kfree(name); + } + else printk("File descriptor %d has no name\n", fh->fd); + } + else { + spin_lock(&open_files_lock); + list_del_init(&fh->list); + spin_unlock(&open_files_lock); + } +} + +void is_reclaimable(struct file_handle *fh, char *(name_proc)(struct inode *), + struct inode *inode) +{ + fh->get_name = name_proc; + fh->inode = inode; + + spin_lock(&open_files_lock); + list_add(&fh->list, &open_files); + spin_unlock(&open_files_lock); +} + +static int active_handle(struct file_handle *fh) +{ + int fd; + char *name; + + if(!list_empty(&fh->list)) + list_move(&fh->list, &open_files); + + if(fh->fd != -1) + return(0); + + if(fh->inode == NULL) + return(-ENOENT); + + name = (*fh->get_name)(fh->inode); + if(name == NULL) + return(-ENOMEM); + + fd = open_file(name, fh->flags, 0); + kfree(name); + if(fd < 0) + return(fd); + + fh->fd = fd; + is_reclaimable(fh, fh->get_name, fh->inode); + + return(0); +} + +int filehandle_fd(struct file_handle *fh) +{ + int err; + + err = active_handle(fh); + if(err) + return(err); + + return(fh->fd); +} + +static void init_fh(struct file_handle *fh, int fd, struct openflags flags) +{ + flags.c = 0; + *fh = ((struct file_handle) { .list = LIST_HEAD_INIT(fh->list), + .fd = fd, + .get_name = NULL, + .inode = NULL, + .flags = flags }); +} + +int open_filehandle(char *name, struct openflags flags, int mode, + struct file_handle *fh) +{ + int fd; + + fd = open_file(name, flags, mode); + if(fd < 0) + return(fd); + + init_fh(fh, fd, flags); + return(0); +} + +int close_file(struct file_handle *fh) +{ + spin_lock(&open_files_lock); + list_del(&fh->list); + spin_unlock(&open_files_lock); + + os_close_file(fh->fd); + + fh->fd = -1; + return(0); +} + +int read_file(struct file_handle *fh, unsigned long long offset, char *buf, + int len) +{ + int err; + + err = active_handle(fh); + if(err) + return(err); + + err = os_seek_file(fh->fd, offset); + if(err) + return(err); + + return(os_read_file(fh->fd, buf, len)); +} + +int write_file(struct file_handle *fh, unsigned long long offset, + const char *buf, int len) +{ + int err; + + err = active_handle(fh); + if(err) + return(err); + + if(offset != -1) + err = os_seek_file(fh->fd, offset); + if(err) + return(err); + + return(os_write_file(fh->fd, buf, len)); +} + +int truncate_file(struct file_handle *fh, unsigned long long size) +{ + int err; + + err = active_handle(fh); + if(err) + return(err); + + return(os_truncate_fd(fh->fd, size)); +} + +int make_pipe(struct file_handle *fhs) +{ + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if(err && (err != -EMFILE)) + return(err); + + if(err){ + reclaim_fds(); + err = os_pipe(fds, 1, 1); + } + if(err) + return(err); + + init_fh(&fhs[0], fds[0], OPENFLAGS()); + init_fh(&fhs[1], fds[1], OPENFLAGS()); + 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: + */ Index: linux-2.4.29/arch/um/kernel/frame.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/frame.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/frame.c 2005-05-03 22:28:14.412419192 +0300 @@ -0,0 +1,343 @@ +/* + * 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 "user_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. + */ + CATCH_EINTR(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. + */ + CATCH_EINTR(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); + } + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 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: + */ Index: linux-2.4.29/arch/um/kernel/frame_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/frame_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/frame_kern.c 2005-05-03 22:28:14.413419040 +0300 @@ -0,0 +1,173 @@ +/* + * 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/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: + */ Index: linux-2.4.29/arch/um/kernel/gmon_syms.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/gmon_syms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/gmon_syms.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/gprof_syms.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/gprof_syms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/gprof_syms.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/helper.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/helper.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/helper.c 2005-05-03 22:28:14.416418584 +0300 @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sched.h> +#include <sys/signal.h> +#include <sys/wait.h> +#include "user.h" +#include "kern_util.h" +#include "user_util.h" +#include "os.h" + +struct helper_data { + void (*pre_exec)(void*); + void *pre_data; + char **argv; + int fd; +}; + +/* Debugging aid, changed only from gdb */ +int helper_pause = 0; + +static void helper_hup(int sig) +{ +} + +static int helper_child(void *arg) +{ + struct helper_data *data = arg; + char **argv = data->argv; + int errval; + + if(helper_pause){ + signal(SIGHUP, helper_hup); + pause(); + } + if(data->pre_exec != NULL) + (*data->pre_exec)(data->pre_data); + execvp(argv[0], argv); + errval = errno; + printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); + os_write_file(data->fd, &errval, sizeof(errval)); + os_kill_process(os_getpid(), 0); + return(0); +} + +/* 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; + os_kill_process(pid, 1); + } + else if(n != 0){ + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + pid = -errno; + } + err = pid; + + out_close: + os_close_file(fds[0]); + out_free: + if(stack_out == NULL) + free_stack(stack, 0); + else *stack_out = stack; + 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){ + CATCH_EINTR(pid = waitpid(pid, &status, 0)); + if(pid < 0){ + printk("run_helper_thread - wait failed, errno = %d\n", + errno); + pid = -errno; + } + if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) + printk("run_helper_thread - thread returned status " + "0x%x\n", status); + free_stack(stack, stack_order); + } + else *stack_out = stack; + return(pid); +} + +int helper_wait(int pid, int block) +{ + int ret; + + CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); + if(ret < 0){ + printk("helper_wait : waitpid failed, errno = %d\n", errno); + return(-errno); + } + return(ret); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/initrd_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/initrd_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/initrd_kern.c 2005-05-03 22:28:14.417418432 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/initrd_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/initrd_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/initrd_user.c 2005-05-03 22:28:14.418418280 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/init_task.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/init_task.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/init_task.c 2005-05-03 22:28:14.419418128 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/irq.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/irq.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/irq.c 2005-05-03 22:28:14.422417672 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/irq_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/irq_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/irq_user.c 2005-05-03 22:28:14.424417368 +0300 @@ -0,0 +1,438 @@ +/* + * 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); +} + +int deactivate_all_fds(void) +{ + struct irq_fd *irq; + int err; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_clear_fd_async(irq->fd); + if(err) + return(err); + } + + return(0); +} + +void forward_ipi(int fd, int pid) +{ + int err; + + err = os_set_owner(fd, pid); + if(err < 0) + printk("forward_ipi: set_owner failed, fd = %d, me = %d, " + "target = %d, err = %d\n", fd, os_getpid(), pid, -err); +} + +void forward_interrupts(int pid) +{ + struct irq_fd *irq; + unsigned long flags; + int err; + + flags = irq_lock(); + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_set_owner(irq->fd, pid); + if(err < 0){ + /* XXX Just remove the irq rather than + * print out an infinite stream of these + */ + printk("Failed to forward %d to pid %d, err = %d\n", + irq->fd, pid, -err); + } + + irq->pid = pid; + } + irq_unlock(flags); +} + +void init_irq_signals(int on_sigstack) +{ + __sighandler_t h; + int flags; + + flags = on_sigstack ? SA_ONSTACK : 0; + if(timer_irq_inited) h = (__sighandler_t) alarm_handler; + else h = boot_timer_handler; + + set_handler(SIGVTALRM, h, flags | SA_RESTART, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); + set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + signal(SIGWINCH, SIG_IGN); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/ksyms.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/ksyms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/ksyms.c 2005-05-03 23:56:02.752509760 +0300 @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/module.h" +#include "linux/string.h" +#include "linux/smp_lock.h" +#include "linux/spinlock.h" +#include "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 "mem_user.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); +EXPORT_SYMBOL(find_iomem); + +#ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(strncpy_from_user_tt); +EXPORT_SYMBOL(copy_from_user_tt); +EXPORT_SYMBOL(copy_to_user_tt); +#endif + +#ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strncpy_from_user_skas); +EXPORT_SYMBOL(copy_to_user_skas); +EXPORT_SYMBOL(copy_from_user_skas); +#endif + +EXPORT_SYMBOL(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: + */ Index: linux-2.4.29/arch/um/kernel/link.ld =================================================================== --- linux-2.4.29.orig/arch/um/kernel/link.ld 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/link.ld 2005-05-03 22:43:46.000000000 +0300 @@ -0,0 +1,147 @@ +OUTPUT_FORMAT("elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 2684354560 + SIZEOF_HEADERS; + + __binary_start = .; + + .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 = .); + + .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) } + + + .data : + { + . = ALIGN(32768); /* 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) } +} Index: linux-2.4.29/arch/um/kernel/link.ld.in =================================================================== --- linux-2.4.29.orig/arch/um/kernel/link.ld.in 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/link.ld.in 2005-05-03 22:28:14.000000000 +0300 @@ -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/kernel/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) } +} Index: linux-2.4.29/arch/um/kernel/main.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/main.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/main.c 2005-05-03 22:28:14.429416608 +0300 @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <sys/resource.h> +#include <sys/mman.h> +#include <sys/user.h> +#include <asm/page.h> +#include "user_util.h" +#include "kern_util.h" +#include "mem_user.h" +#include "signal_user.h" +#include "time_user.h" +#include "irq_user.h" +#include "user.h" +#include "init.h" +#include "mode.h" +#include "choose-mode.h" +#include "uml-config.h" + +/* 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){ + int err; + + printf("\n"); + + /* Let any pending signals fire, then disable them. This + * ensures that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); + disable_timer(); + err = deactivate_all_fds(); + if(err) + printf("deactivate_all_fds failed, errno = %d\n", -err); + + 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) +{ + void *ret; + + if(!CAN_KMALLOC()) + return(__real_malloc(size)); + else if(size <= PAGE_SIZE) /* finding contiguos pages is hard */ + ret = um_kmalloc(size); + else ret = um_vmalloc(size); + + /* glibc people insist that if malloc fails, errno should be + * set by malloc as well. So we do. + */ + if(ret == NULL) + errno = ENOMEM; + + return(ret); +} + +void *__wrap_calloc(int n, int size) +{ + void *ptr = __wrap_malloc(n * size); + + if(ptr == NULL) return(NULL); + memset(ptr, 0, n * size); + return(ptr); +} + +extern void __real_free(void *); + +extern unsigned long high_physmem; + +void __wrap_free(void *ptr) +{ + unsigned long addr = (unsigned long) ptr; + + /* We need to know how the allocation happened, so it can be correctly + * freed. This is done by seeing what region of memory the pointer is + * in - + * physical memory - kmalloc/kfree + * kernel virtual memory - vmalloc/vfree + * anywhere else - malloc/free + * If kmalloc is not yet possible, then the kernel memory regions + * may not be set up yet, and the variables not set up. So, + * free is called. + * + * CAN_KMALLOC is checked because it would be bad to free a buffer + * with kmalloc/vmalloc after they have been turned off during + * shutdown. + */ + + if((addr >= uml_physmem) && (addr < high_physmem)){ + if(CAN_KMALLOC()) + kfree(ptr); + } + else if((addr >= start_vm) && (addr < end_vm)){ + if(CAN_KMALLOC()) + vfree(ptr); + } + else __real_free(ptr); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/Makefile 2005-05-03 22:28:14.430416456 +0300 @@ -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 filehandle.o frame_kern.o \ + frame.o helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o \ + mem_user.o physmem.o process.o process_kern.o ptrace.o reboot.o \ + resource.o sigio_user.o sigio_kern.o signal_kern.o signal_user.o \ + smp.o syscall_kern.o 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 \ + main.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 Index: linux-2.4.29/arch/um/kernel/mem.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/mem.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/mem.c 2005-05-03 22:28:14.431416304 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/mem_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/mem_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/mem_user.c 2005-05-03 22:28:14.433416000 +0300 @@ -0,0 +1,271 @@ +/* + * 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); +} + +void check_tmpexec(void) +{ + void *addr; + int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); + + addr = mmap(NULL, UM_KERN_PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); + printf("Checking PROT_EXEC mmap in /tmp..."); + fflush(stdout); + if(addr == MAP_FAILED){ + err = errno; + perror("failed"); + if(err == EPERM) + printf("/tmp must be not mounted noexec\n"); + exit(1); + } + printf("OK\n"); + munmap(addr, UM_KERN_PAGE_SIZE); +} + +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, size; + + driver = str; + file = strchr(str,','); + if(file == NULL){ + printf("parse_iomem : failed to parse iomem\n"); + goto out; + } + *file = '\0'; + file++; + fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); + if(fd < 0){ + os_print_error(fd, "parse_iomem - Couldn't open io file"); + goto out; + } + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; + } + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; + } + + size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = size, + .phys = 0, + .virt = 0 }); + iomem_regions = new; + iomem_size += new->size + UM_KERN_PAGE_SIZE; + + return(0); + out_close: + os_close_file(fd); + out: + return(1); +} + +__uml_setup("iomem=", parse_iomem, +"iomem=<name>,<file>\n" +" Configure <file> as an IO memory region named <name>.\n\n" +); + +int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, + int must_succeed) +{ + int err; + + err = os_protect_memory((void *) addr, len, r, w, x); + if(err < 0){ + if(must_succeed) + panic("protect failed, err = %d", -err); + else return(err); + } + return(0); +} + +#if 0 +/* Debugging facility for dumping stuff out to the host, avoiding the timing + * problems that come with printf and breakpoints. + * Enable in case of emergency. + */ + +int logging = 1; +int logging_fd = -1; + +int logging_line = 0; +char logging_buf[512]; + +void log(char *fmt, ...) +{ + va_list ap; + struct timeval tv; + struct openflags flags; + + if(logging == 0) return; + if(logging_fd < 0){ + flags = of_create(of_trunc(of_rdwr(OPENFLAGS()))); + logging_fd = os_open_file("log", flags, 0644); + } + gettimeofday(&tv, NULL); + sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, + tv.tv_usec); + va_start(ap, fmt); + vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); + va_end(ap); + write(logging_fd, logging_buf, strlen(logging_buf)); +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/physmem.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/physmem.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/physmem.c 2005-05-03 22:28:14.436415544 +0300 @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/rbtree.h" +#include "linux/slab.h" +#include "linux/vmalloc.h" +#include "linux/bootmem.h" +#include "asm/types.h" +#include "asm/pgtable.h" +#include "kern_util.h" +#include "user_util.h" +#include "mode_kern.h" +#include "mem.h" +#include "mem_user.h" +#include "os.h" +#include "kern.h" +#include "init.h" + +struct phys_desc { + struct rb_node_s rb; + int fd; + __u64 offset; + void *virt; + unsigned long phys; + struct list_head list; +}; + +static struct rb_root_s phys_mappings = RB_ROOT; + +static struct rb_node_s **find_rb(void *virt) +{ + struct rb_node_s **n = &phys_mappings.rb_node; + struct phys_desc *d; + + while(*n != NULL){ + d = rb_entry(n, struct phys_desc, rb); + if(d->virt == virt) + return(n); + + if(d->virt > virt) + n = &(*n)->rb_left; + else + n = &(*n)->rb_right; + } + + return(n); +} + +static struct phys_desc *find_phys_mapping(void *virt) +{ + struct rb_node_s **n = find_rb(virt); + + if(*n == NULL) + return(NULL); + + return(rb_entry(n, struct phys_desc, rb)); +} + +static void insert_phys_mapping(struct phys_desc *desc) +{ + struct rb_node_s **n = find_rb(desc->virt); + + if(*n != NULL) + panic("Physical remapping for %p already present", + desc->virt); + + rb_link_node(&desc->rb, (*n)->rb_parent, n); + rb_insert_color(&desc->rb, &phys_mappings); +} + +LIST_HEAD(descriptor_mappings); + +struct desc_mapping { + int fd; + struct list_head list; + struct list_head pages; +}; + +static struct desc_mapping *find_mapping(int fd) +{ + struct desc_mapping *desc; + struct list_head *ele; + + list_for_each(ele, &descriptor_mappings){ + desc = list_entry(ele, struct desc_mapping, list); + if(desc->fd == fd) + return(desc); + } + + return(NULL); +} + +static struct desc_mapping *descriptor_mapping(int fd) +{ + struct desc_mapping *desc; + + desc = find_mapping(fd); + if(desc != NULL) + return(desc); + + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + return(NULL); + + *desc = ((struct desc_mapping) + { .fd = fd, + .list = LIST_HEAD_INIT(desc->list), + .pages = LIST_HEAD_INIT(desc->pages) }); + list_add(&desc->list, &descriptor_mappings); + + return(desc); +} + +int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) +{ + struct desc_mapping *fd_maps; + struct phys_desc *desc; + unsigned long phys; + int err; + + phys = __pa(virt); + desc = find_phys_mapping(virt); + if(desc != NULL){ + if((virt != desc->virt) || (fd != desc->fd) || + (offset != desc->offset)) + panic("Address 0x%p is already substituted\n", virt); + return(0); + } + + fd_maps = descriptor_mapping(fd); + if(fd_maps == NULL) + return(-ENOMEM); + + err = -ENOMEM; + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + goto out; + + *desc = ((struct phys_desc) + { .fd = fd, + .offset = offset, + .virt = virt, + .phys = __pa(virt), + .list = LIST_HEAD_INIT(desc->list) }); + insert_phys_mapping(desc); + + list_add(&desc->list, &fd_maps->pages); + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); + if(!err) + goto out; + + rb_erase(&desc->rb, &phys_mappings); + kfree(desc); + out: + return(err); +} + +static int physmem_fd = -1; + +static void remove_mapping(struct phys_desc *desc) +{ + void *virt = desc->virt; + int err; + + rb_erase(&desc->rb, &phys_mappings); + list_del(&desc->list); + kfree(desc); + + err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); + if(err) + panic("Failed to unmap block device page from physical memory, " + "errno = %d", -err); +} + +int physmem_remove_mapping(void *virt) +{ + struct phys_desc *desc; + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + desc = find_phys_mapping(virt); + if(desc == NULL) + return(0); + + remove_mapping(desc); + return(1); +} + +void physmem_forget_descriptor(int fd) +{ + struct desc_mapping *desc; + struct phys_desc *page; + struct list_head *ele, *next; + __u64 offset; + void *addr; + int err; + + desc = find_mapping(fd); + if(desc == NULL) + return; + + if(!list_empty(&desc->pages)) + printk("Still have mapped pages on fd %d\n", fd); + + 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(const void *virt, int fd, __u64 offset) +{ + struct phys_desc *desc; + + desc = find_phys_mapping((void *) virt); + if(desc == NULL) + return(0); + if(offset != desc->offset) + printk("offset mismatch\n"); + return(find_phys_mapping((void *) 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_phys_mapping(__va(phys & PAGE_MASK)); + int fd = -1; + + if(desc != NULL){ + fd = desc->fd; + *offset_out = desc->offset; + } + else if(phys < physmem_size){ + fd = physmem_fd; + *offset_out = phys; + } + else if(phys < __pa(end_iomem)){ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if((phys >= region->phys) && + (phys < region->phys + region->size)){ + fd = region->fd; + *offset_out = phys - region->phys; + break; + } + region = region->next; + } + } + else if(phys < __pa(end_iomem) + highmem){ + fd = physmem_fd; + *offset_out = phys - iomem_size; + } + + return(fd); +} + +static int __init uml_mem_setup(char *line, int *add) +{ + char *retptr; + physmem_size = memparse(line,&retptr); + return 0; +} +__uml_setup("mem=", uml_mem_setup, +"mem=<Amount of desired ram>\n" +" This controls how much \"physical\" memory the kernel allocates\n" +" for the system. The size is specified as a number followed by\n" +" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" +" This is not related to the amount of memory in the host. It can\n" +" be more, and the excess, if it's ever used, will just be swapped out.\n" +" Example: mem=64M\n\n" +); + +unsigned long find_iomem(char *driver, unsigned long *len_out) +{ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if(!strcmp(region->driver, driver)){ + *len_out = region->size; + return(region->virt); + } + } + + return(0); +} + +int setup_iomem(void) +{ + struct iomem_region *region = iomem_regions; + unsigned long iomem_start = high_physmem + PAGE_SIZE; + int err; + + while(region != NULL){ + err = os_map_memory((void *) iomem_start, region->fd, 0, + region->size, 1, 1, 0); + if(err) + printk("Mapping iomem region for driver '%s' failed, " + "errno = %d\n", region->driver, -err); + else { + region->virt = iomem_start; + region->phys = __pa(region->virt); + } + + iomem_start += region->size + PAGE_SIZE; + region = region->next; + } + + return(0); +} + +__initcall(setup_iomem); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/process.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/process.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/process.c 2005-05-03 22:28:14.437415392 +0300 @@ -0,0 +1,310 @@ +/* + * 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 <asm/user.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); + set_sigstack(sig_stack, pages * page_size()); + flags = SA_ONSTACK; + } + if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); +} + +void init_new_thread_signals(int altstack) +{ + int flags = altstack ? SA_ONSTACK : 0; + + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGILL, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + set_handler(SIGUSR2, (__sighandler_t) sig_handler, + flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + signal(SIGHUP, SIG_IGN); + + init_irq_signals(altstack); +} + +struct tramp { + int (*tramp)(void *); + void *tramp_data; + unsigned long temp_stack; + int flags; + int pid; +}; + +/* See above for why sigkill is here */ + +int sigkill = SIGKILL; + +int outer_tramp(void *arg) +{ + struct tramp *t; + int sig = sigkill; + + t = arg; + t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, + t->flags, t->tramp_data); + if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); + kill(os_getpid(), sig); + _exit(0); +} + +int start_fork_tramp(void *thread_arg, unsigned long temp_stack, + int clone_flags, int (*tramp)(void *)) +{ + struct tramp arg; + unsigned long sp; + int new_pid, status, err; + + /* The trampoline will run on the temporary stack */ + sp = stack_sp(temp_stack); + + clone_flags |= CLONE_FILES | SIGCHLD; + + arg.tramp = tramp; + arg.tramp_data = thread_arg; + arg.temp_stack = temp_stack; + arg.flags = clone_flags; + + /* Start the process and wait for it to kill itself */ + new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); + if(new_pid < 0) + return(new_pid); + + CATCH_EINTR(err = waitpid(new_pid, &status, 0)); + if(err < 0) + panic("Waiting for outer trampoline failed - errno = %d", + errno); + + if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); + + return(arg.pid); +} + +static int ptrace_child(void *arg) +{ + int 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); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if(n < 0) + panic("check_ptrace : wait failed, errno = %d", errno); + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) + panic("check_ptrace : expected SIGSTOP, got status = %d", + status); + + *stack_out = stack; + return(pid); +} + +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); + CATCH_EINTR(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); +} + +int use_sysemu = 0; + +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); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if(n < 0) + panic("check_ptrace : wait failed, errno = %d", errno); + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("check_ptrace : expected SIGTRAP, " + "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"); + + printk("Checking syscall emulation patch for ptrace..."); + pid = start_ptraced_child(&stack); + if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) { + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if(n < 0) + panic("check_ptrace : wait failed, errno = %d", errno); + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("check_ptrace : expected SIGTRAP, " + "got status = %d", status); + + + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, + os_getpid()); + if(n < 0) + panic("check_ptrace : failed to modify system " + "call return, errno = %d", errno); + + stop_ptraced_child(pid, stack, 0); + + printk("OK\n"); + use_sysemu = 1; + } + else { + printk("missing\n"); + stop_ptraced_child(pid, stack, 1); + } +} + +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: + */ Index: linux-2.4.29/arch/um/kernel/process_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/process_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/process_kern.c 2005-05-03 22:28:14.439415088 +0300 @@ -0,0 +1,413 @@ +/* + * 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 "linux/vmalloc.h" +#include "linux/ptrace.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; + 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)); +} + +void *um_vmalloc(int size) +{ + return(vmalloc(size)); +} + +unsigned long get_fault_addr(void) +{ + return((unsigned long) current->thread.fault_addr); +} + +EXPORT_SYMBOL(get_fault_addr); + +void not_implemented(void) +{ + printk(KERN_DEBUG "Something isn't implemented in here\n"); +} + +EXPORT_SYMBOL(not_implemented); + +int user_context(unsigned long sp) +{ + unsigned long stack; + + stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); + return(stack != current); +} + +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); +} + +int singlestepping(void * t) +{ + struct task_struct *task = t ? t : current; + + if ( ! (task->ptrace & PT_DTRACE) ) + return(0); + + if (task->thread.singlestep_syscall) + return(0); + + 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: + */ Index: linux-2.4.29/arch/um/kernel/ptrace.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/ptrace.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/ptrace.c 2005-05-03 22:28:14.441414784 +0300 @@ -0,0 +1,341 @@ +/* + * 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) +{ + child->ptrace &= ~PT_DTRACE; + child->thread.singlestep_syscall = 0; +} + +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; + + child->ptrace &= ~PT_DTRACE; + child->thread.singlestep_syscall = 0; + + 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->ptrace &= ~PT_DTRACE; + child->thread.singlestep_syscall = 0; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~PT_TRACESYS; + child->ptrace |= PT_DTRACE; + child->thread.singlestep_syscall = 0; + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: + /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + +#ifdef PTRACE_GETREGS + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, (unsigned long *)data, + 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) +{ + int is_singlestep = (current->ptrace & PT_DTRACE); + + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS) && !is_singlestep) + 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; + } + + if(is_syscall(PT_REGS_IP(¤t->thread.regs))) + current->thread.singlestep_syscall = 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: + */ Index: linux-2.4.29/arch/um/kernel/reboot.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/reboot.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/reboot.c 2005-05-03 22:28:14.441414784 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/resource.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/resource.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/resource.c 2005-05-03 22:28:14.442414632 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/sigio_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/sigio_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/sigio_kern.c 2005-05-03 22:28:14.443414480 +0300 @@ -0,0 +1,61 @@ +/* + * 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; + +static 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) +{ + int err; + + err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", + NULL); + if(err){ + printk("write_sigio_irq : um_request_irq failed, err = %d\n", + err); + return(-1); + } + sigio_irq_fd = fd; + return(0); +} + +static 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: + */ Index: linux-2.4.29/arch/um/kernel/sigio_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/sigio_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/sigio_user.c 2005-05-03 22:28:14.445414176 +0300 @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <stdlib.h> +#include <termios.h> +#include <pty.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <sched.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include "init.h" +#include "user.h" +#include "kern_util.h" +#include "user_util.h" +#include "sigio.h" +#include "helper.h" +#include "os.h" + +/* Changed during early boot */ +int pty_output_sigio = 0; +int pty_close_sigio = 0; + +/* Used as a flag during SIGIO testing early in boot */ +static volatile int got_sigio = 0; + +void __init handler(int sig) +{ + got_sigio = 1; +} + +struct openpty_arg { + int master; + int slave; + int err; +}; + +static void openpty_cb(void *arg) +{ + struct openpty_arg *info = arg; + + info->err = 0; + if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) + info->err = -errno; +} + +void __init check_one_sigio(void (*proc)(int, int)) +{ + struct sigaction old, new; + struct openpty_arg pty = { .master = -1, .slave = -1 }; + int master, slave, err; + + initial_thread_cb(openpty_cb, &pty); + if(pty.err){ + printk("openpty failed, errno = %d\n", -pty.err); + return; + } + + master = pty.master; + slave = pty.slave; + + if((master == -1) || (slave == -1)){ + printk("openpty failed to allocate a pty\n"); + return; + } + + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); + + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); + + if(sigaction(SIGIO, NULL, &old) < 0) + panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); + new = old; + new.sa_handler = handler; + if(sigaction(SIGIO, &new, NULL) < 0) + panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); + + got_sigio = 0; + (*proc)(master, slave); + + os_close_file(master); + os_close_file(slave); + + if(sigaction(SIGIO, &old, NULL) < 0) + panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); +} + +static void tty_output(int master, int slave) +{ + int n; + char buf[512]; + + printk("Checking that host ptys support output SIGIO..."); + + memset(buf, 0, sizeof(buf)); + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; + if(errno != EAGAIN) + panic("check_sigio : write failed, errno = %d\n", errno); + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + + if(got_sigio){ + printk("Yes\n"); + pty_output_sigio = 1; + } + else if(n == -EAGAIN) printk("No, enabling workaround\n"); + else panic("check_sigio : read failed, err = %d\n", n); +} + +static void tty_close(int master, int slave) +{ + printk("Checking that host ptys support SIGIO on close..."); + + os_close_file(slave); + if(got_sigio){ + printk("Yes\n"); + pty_close_sigio = 1; + } + else printk("No, enabling workaround\n"); +} + +void __init check_sigio(void) +{ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ + printk("No pseudo-terminals available - skipping pty SIGIO " + "check\n"); + return; + } + check_one_sigio(tty_output); + check_one_sigio(tty_close); +} + +/* Protected by sigio_lock(), also used by sigio_cleanup, which is an + * exitcall. + */ +static int write_sigio_pid = -1; + +/* These arrays are initialized before the sigio thread is started, and + * the descriptors closed after it is killed. So, it can't see them change. + * On the UML side, they are changed under the sigio_lock. + */ +static int write_sigio_fds[2] = { -1, -1 }; +static int sigio_private[2] = { -1, -1 }; + +struct pollfds { + struct pollfd *poll; + int size; + int used; +}; + +/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread + * synchronizes with it. + */ +struct pollfds current_poll = { + .poll = NULL, + .size = 0, + .used = 0 +}; + +struct pollfds next_poll = { + .poll = NULL, + .size = 0, + .used = 0 +}; + +static int write_sigio_thread(void *unused) +{ + struct pollfds *fds, tmp; + struct pollfd *p; + int i, n, respond_fd; + char c; + + fds = ¤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: + */ Index: linux-2.4.29/arch/um/kernel/signal_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/signal_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/signal_kern.c 2005-05-03 22:28:14.447413872 +0300 @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/stddef.h" +#include "linux/sys.h" +#include "linux/sched.h" +#include "linux/wait.h" +#include "linux/kernel.h" +#include "linux/smp_lock.h" +#include "linux/module.h" +#include "linux/slab.h" +#include "asm/signal.h" +#include "asm/uaccess.h" +#include "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 void 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; + + err = PT_REGS_SYSCALL_RET(¤t->thread.regs); + ret = 0; + switch(err){ + 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) + force_segv(signr); +} + +/* + * 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; + + 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. */ + handle_signal(regs, signr, ka, &info, oldset, error); + return(1); + } + + /* Did we come from a system call? */ + if(PT_REGS_SYSCALL_NR(regs) >= 0){ + /* Restart the system call - no handlers present */ + if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND || + PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS || + PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){ + PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); + PT_REGS_RESTART_SYSCALL(regs); + } + } + + /* This closes a way to execute a system call on the host. If + * you set a breakpoint on a system call instruction and singlestep + * from it, the tracing thread used to PTRACE_SINGLESTEP the process + * rather than PTRACE_SYSCALL it, allowing the system call to execute + * on the host. The tracing thread will check this flag and + * PTRACE_SYSCALL if necessary. + */ + if((current->ptrace & PT_DTRACE) && + is_syscall(PT_REGS_IP(¤t->thread.regs))) + current->thread.singlestep_syscall = 1; + + return(0); +} + +int do_signal(int error) +{ + return(kern_do_signal(¤t->thread.regs, NULL, error)); +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +int sys_sigsuspend(int history0, int history1, old_sigset_t mask) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; + 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); + + PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; + 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: + */ Index: linux-2.4.29/arch/um/kernel/signal_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/signal_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/signal_user.c 2005-05-03 22:28:14.448413720 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/exec_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/exec_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/exec_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/exec_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/exec_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/exec_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,63 @@ +/* + * 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 "user_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, err; + + 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); + } + + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if(err < 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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/mmu.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/mmu.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/mmu.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/mode.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/mode.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/mode.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_SKAS_H__ +#define __MODE_SKAS_H__ + +#include <sysdep/ptrace.h> + +extern unsigned long exec_regs[]; +extern unsigned long exec_fp_regs[]; +extern unsigned long exec_fpx_regs[]; +extern int have_fpx_regs; + +extern void user_time_init_skas(void); +extern 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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/mode_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/mode_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/mode_kern.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/proc_mm.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/proc_mm.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/proc_mm.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/ptrace-skas.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/ptrace-skas.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/ptrace-skas.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/skas.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/skas.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/skas.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,48 @@ +/* + * 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 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: + */ Index: linux-2.4.29/arch/um/kernel/skas/include/uaccess.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/include/uaccess.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/include/uaccess.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/kernel/skas/mem.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/mem.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/mem.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/mem_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/mem_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/mem_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/mmu.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/mmu.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/mmu.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/process.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/process.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/process.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,400 @@ +/* + * 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; + } + + if(!use_sysemu){ + 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); + + CATCH_EINTR(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 { + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if(n < 0) + panic("start_userspace : wait failed, errno = %d", + errno); + } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) + panic("start_userspace : expected SIGSTOP, got status = %d", + status); + + if(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, do_syscall, pid = userspace_pid[0]; + + do_syscall = use_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; + restore_registers(regs); + + err = ptrace(do_syscall, pid, 0, 0); + if(err) + panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", + errno); + while(1){ + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if(err < 0) + panic("userspace - waitpid failed, errno = %d\n", + errno); + + regs->skas.is_user = 1; + save_registers(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(NULL) ? PTRACE_SINGLESTEP : do_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); +} + +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: + */ Index: linux-2.4.29/arch/um/kernel/skas/process_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/process_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/process_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,211 @@ +/* + * 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" +#include "filehandle.h" +#include "proc_mm.h" + +void *_switch_to_skas(void *prev, void *next) +{ + struct task_struct *from, *to; + + from = prev; + to = next; + + /* XXX need to check runqueues[cpu].idle */ + if(current->pid == 0) + switch_timers(0); + + to->thread.prev_sched = from; + set_current(to); + + switch_threads(&from->thread.mode.skas.switch_buf, + to->thread.mode.skas.switch_buf); + + if(current->pid == 0) + switch_timers(1); + + return(current->thread.prev_sched); +} + +extern void schedule_tail(struct task_struct *prev); + +void new_thread_handler(int sig) +{ + int (*fn)(void *), n; + void *arg; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + change_sig(SIGUSR1, 1); + thread_wait(¤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(p, &p->thread.mode.skas.switch_buf, + &p->thread.mode.skas.fork_buf, handler); + return(0); +} + +int new_mm(int from) +{ + struct proc_mm_op copy; + int n; + int fd = 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 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(); + + init_new_thread_signals(1); + idle_timer(); + + init_task.thread.request.u.thread.proc = start_kernel_proc; + init_task.thread.request.u.thread.arg = NULL; + return(start_idle_thread(&init_task, + &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: + */ Index: linux-2.4.29/arch/um/kernel/skas/syscall_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/syscall_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/syscall_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/sys.h" +#include "linux/ptrace.h" +#include "asm/errno.h" +#include "asm/unistd.h" +#include "asm/ptrace.h" +#include "asm/current.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +extern syscall_handler_t *sys_call_table[]; + +long execute_syscall_skas(void *r) +{ + struct pt_regs *regs = r; + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = UPT_SYSCALL_NR(®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: + */ Index: linux-2.4.29/arch/um/kernel/skas/syscall_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/syscall_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/syscall_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/sys-i386/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/sys-i386/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/sys-i386/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 : Index: linux-2.4.29/arch/um/kernel/skas/sys-i386/sigcontext.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/sys-i386/sigcontext.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/sys-i386/sigcontext.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/time.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/time.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/time.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/tlb.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/tlb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/tlb.c 2005-05-03 22:28:14.000000000 +0300 @@ -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; 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; + } + } +} + +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: + */ Index: linux-2.4.29/arch/um/kernel/skas/trap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/trap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/trap_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/skas/uaccess.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/uaccess.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/uaccess.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/kernel.h" +#include "linux/string.h" +#include "linux/fs.h" +#include "linux/highmem.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/uaccess.h" +#include "kern_util.h" +#include "user_util.h" + +extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, + pte_t *pte_out); + +static unsigned long maybe_map(unsigned long virt, int is_write) +{ + pte_t pte; + + 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, 1, &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 void do_buffer_op(void *jmpbuf, void *arg_ptr) +{ + va_list args = *((va_list *) arg_ptr); + unsigned long addr = va_arg(args, unsigned long); + int len = va_arg(args, int); + int is_write = va_arg(args, int); + int (*op)(unsigned long, int, void *) = va_arg(args, void *); + void *arg = va_arg(args, void *); + int *res = va_arg(args, int *); + int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); + int remain = len, n; + + current->thread.fault_catcher = jmpbuf; + n = do_op(addr, size, is_write, op, arg); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } + + addr += size; + remain -= size; + if(remain == 0){ + *res = 0; + goto out; + } + + while(addr < ((addr + remain) & PAGE_MASK)){ + n = do_op(addr, PAGE_SIZE, is_write, op, arg); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } + + addr += PAGE_SIZE; + remain -= PAGE_SIZE; + } + if(remain == 0){ + *res = 0; + goto out; + } + + n = do_op(addr, remain, is_write, op, arg); + if(n != 0) + *res = (n < 0 ? remain : 0); + else *res = 0; + out: + current->thread.fault_catcher = NULL; +} + +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int faulted, res; + + faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, + &res); + if(!faulted) + return(res); + + return(addr + len - (unsigned long) current->thread.fault_addr); +} + +static int copy_chunk_from_user(unsigned long from, int len, void *arg) +{ + unsigned long *to_ptr = arg, to = *to_ptr; + + memcpy((void *) to, (void *) from, len); + *to_ptr += len; + return(0); +} + +int copy_from_user_skas(void *to, const void *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: + */ Index: linux-2.4.29/arch/um/kernel/skas/util/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/util/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/util/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 *~ Index: linux-2.4.29/arch/um/kernel/skas/util/mk_ptregs.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/skas/util/mk_ptregs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/skas/util/mk_ptregs.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/smp.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/smp.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/smp.c 2005-05-03 22:28:14.476409464 +0300 @@ -0,0 +1,329 @@ +/* + * 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(({ struct file_handle *pipe; + pipe = new_task->thread.mode.tt.switch_pipe; + write_file(&pipe[1], -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: + */ Index: linux-2.4.29/arch/um/kernel/syscall_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/syscall_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/syscall_kern.c 2005-05-03 22:28:14.477409312 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/sys_call_table.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/sys_call_table.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/sys_call_table.c 2005-05-03 22:28:14.480408856 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/syscall_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/syscall_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/syscall_user.c 2005-05-03 22:28:14.481408704 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/sysrq.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/sysrq.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/sysrq.c 2005-05-03 22:28:14.482408552 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tempfile.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tempfile.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tempfile.c 2005-05-03 22:28:14.483408400 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/time.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/time.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/time.c 2005-05-03 22:28:14.484408248 +0300 @@ -0,0 +1,144 @@ +/* + * 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 disable_timer(void) +{ + struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); + if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || + (setitimer(ITIMER_REAL, &disable, NULL) < 0)) + printk("disnable_timer - setitimer failed, errno = %d\n", + errno); +} + +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); +} + +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(); + + 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: + */ Index: linux-2.4.29/arch/um/kernel/time_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/time_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/time_kern.c 2005-05-03 22:28:14.485408096 +0300 @@ -0,0 +1,209 @@ +/* + * 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" +#include "os.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_usecs; +static long long delta; /* Deviation per interval */ + +#define MILLION 1000000 + +void timer_irq(union uml_pt_regs *regs) +{ + unsigned long long ticks = 0; + + if(!timer_irq_inited){ + /* This is to ensure that ticks don't pile up when + * the timer handler is suspended */ + first_tick = 0; + return; + } + + if(first_tick){ +#if defined(CONFIG_UML_REAL_TIME_CLOCK) + /* We've had 1 tick */ + unsigned long long usecs = os_usecs(); + + delta += usecs - prev_usecs; + prev_usecs = usecs; + + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / MILLION; + delta -= (ticks * MILLION) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_usecs = os_usecs(); + first_tick = 1; + } + + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } +} + +void boot_timer_handler(int sig) +{ + struct pt_regs regs; + + CHOOSE_MODE((void) + (UPT_SC(®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) / MILLION; + for(i=0;i<n;i++) ; +} + +void __const_udelay(um_udelay_t usecs) +{ + int i, n; + + n = (loops_per_jiffy * HZ * usecs) / MILLION; + for(i=0;i<n;i++) ; +} + +void timer_handler(int sig, union uml_pt_regs *regs) +{ +#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: + */ Index: linux-2.4.29/arch/um/kernel/tlb.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tlb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tlb.c 2005-05-03 22:28:14.486407944 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/trap_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/trap_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/trap_kern.c 2005-05-03 22:28:14.487407792 +0300 @@ -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, int is_user) +{ + 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, is_user)) + 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, is_user)) + 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: + */ Index: linux-2.4.29/arch/um/kernel/trap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/trap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/trap_user.c 2005-05-03 22:28:14.489407488 +0300 @@ -0,0 +1,145 @@ +/* + * 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); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); +} + +/* Unlocked - don't care if this is a bit off */ +int nsegfaults = 0; + +struct { + unsigned long address; + int is_write; + int pid; + unsigned long sp; + int is_user; +} segfault_record[1024]; + +void segv_handler(int sig, union uml_pt_regs *regs) +{ + int index, max; + + if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ + bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), + UPT_FAULT_WRITE(regs)); + return; + } + max = sizeof(segfault_record)/sizeof(segfault_record[0]); + index = next_trap_index(max); + + nsegfaults++; + segfault_record[index].address = UPT_FAULT_ADDR(regs); + segfault_record[index].pid = os_getpid(); + segfault_record[index].is_write = UPT_FAULT_WRITE(regs); + segfault_record[index].sp = UPT_SP(regs); + segfault_record[index].is_user = UPT_IS_USER(regs); + segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), + UPT_IS_USER(regs), regs); +} + +void usr2_handler(int sig, union uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} + +struct signal_info sig_info[] = { + [ SIGTRAP ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGFPE ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGILL ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGWINCH ] { .handler = winch, + .is_irq = 1 }, + [ SIGBUS ] { .handler = bus_handler, + .is_irq = 0 }, + [ SIGSEGV] { .handler = segv_handler, + .is_irq = 0 }, + [ SIGIO ] { .handler = sigio_handler, + .is_irq = 1 }, + [ SIGVTALRM ] { .handler = timer_handler, + .is_irq = 1 }, + [ SIGALRM ] { .handler = timer_handler, + .is_irq = 1 }, + [ SIGUSR2 ] { .handler = usr2_handler, + .is_irq = 0 }, +}; + +void 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/exec_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/exec_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/exec_kern.c 2005-05-03 22:28:14.490407336 +0300 @@ -0,0 +1,86 @@ +/* + * 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 "signal_user.h" +#include "os.h" +#include "tlb.h" +#include "mode.h" + +static int exec_tramp(void *sig_stack) +{ + init_new_thread_stack(sig_stack, NULL); + init_new_thread_signals(1); + os_stop_process(os_getpid()); + return(0); +} + +void flush_thread_tt(void) +{ + unsigned long stack; + int new_pid; + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR + "flush_thread : failed to allocate temporary stack\n"); + do_exit(SIGKILL); + } + + new_pid = start_fork_tramp(current, 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()); + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + enable_timer(); + free_page(stack); + protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); + task_protections((unsigned long) current); + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/exec_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/exec_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/exec_user.c 2005-05-03 22:28:14.491407184 +0300 @@ -0,0 +1,54 @@ +/* + * 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]; + int err; + + if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) + tracer_panic("do_exec failed to attach proc - errno = %d", + errno); + + CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); + if (err < 0) + tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", + errno); + + if(ptrace_getregs(old_pid, regs) < 0) + tracer_panic("do_exec failed to get registers - errno = %d", + errno); + + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/gdb.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/gdb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/gdb.c 2005-05-03 22:28:14.492407032 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/gdb_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/gdb_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/gdb_kern.c 2005-05-03 22:28:14.493406880 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/debug.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/debug.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/debug.h 2005-05-03 22:28:14.494406728 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/mmu.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/mmu.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/mmu.h 2005-05-03 22:28:14.495406576 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/mode.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/mode.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/mode.h 2005-05-03 22:28:14.496406424 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/mode_kern.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/mode_kern.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/mode_kern.h 2005-05-03 22:28:14.496406424 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/ptrace-tt.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/ptrace-tt.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/ptrace-tt.h 2005-05-03 22:28:14.497406272 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/tt.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/tt.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/tt.h 2005-05-03 22:28:14.498406120 +0300 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_H__ +#define __TT_H__ + +#include "sysdep/ptrace.h" + +extern int gdb_pid; +extern int debug; +extern int debug_stop; +extern int debug_trace; + +extern int honeypot; + +extern int fork_tramp(void *sig_stack); +extern int do_proc_op(void *t, int proc_id); +extern int tracer(int (*init_proc)(void *), void *sp); +extern void attach_process(int pid); +extern void tracer_panic(char *format, ...); +extern void set_init_pid(int pid); +extern int set_user_mode(void *task); +extern void set_tracing(void *t, int tracing); +extern int is_tracing(void *task); +extern void syscall_handler(int sig, union uml_pt_regs *regs); +extern void exit_kernel(int pid, void *task); +extern 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/include/uaccess.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/include/uaccess.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/include/uaccess.h 2005-05-03 22:28:14.499405968 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ksyms.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ksyms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ksyms.c 2005-05-03 22:28:14.500405816 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/Makefile 2005-05-03 22:28:14.501405664 +0300 @@ -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 : Index: linux-2.4.29/arch/um/kernel/tt/mem.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/mem.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/mem.c 2005-05-03 22:28:14.502405512 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/mem_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/mem_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/mem_user.c 2005-05-03 22:28:14.502405512 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/process_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/process_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/process_kern.c 2005-05-03 22:28:14.526401864 +0300 @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/signal.h" +#include "linux/kernel.h" +#include "linux/slab.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" +#include "filehandle.h" + +void *_switch_to_tt(void *prev, void *next) +{ + struct task_struct *from, *to, *prev_sched; + struct file_handle *pipe; + 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; + pipe = to->thread.mode.tt.switch_pipe; + err = write_file(&pipe[1], -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); + + pipe = from->thread.mode.tt.switch_pipe; + err = read_file(&pipe[0], -1, &c, sizeof(c)); + if(err != sizeof(c)) + panic("read of switch_pipe failed, errno = %d", -err); + + /* If the process that we have just scheduled away from has exited, + * then it needs to be killed here. The reason is that, even though + * it will kill itself when it next runs, that may be too late. Its + * stack will be freed, possibly before then, and if that happens, + * we have a use-after-free situation. So, it gets killed here + * in case it has not already killed itself. + */ + prev_sched = current->thread.prev_sched; + if(prev_sched->state == TASK_ZOMBIE) + os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); + + /* 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) +{ + struct file_handle *pipe = current->thread.mode.tt.switch_pipe; + + close_file(&pipe[0]); + close_file(&pipe[1]); + kfree(pipe); +} + +static void suspend_new_thread(struct file_handle *fh) +{ + char c; + + os_stop_process(os_getpid()); + + if(read_file(fh, -1, &c, sizeof(c)) != sizeof(c)) + panic("read failed in suspend_new_thread"); +} + +extern void schedule_tail(struct task_struct *prev); + +static void new_thread_handler(int sig) +{ + struct file_handle *pipe; + 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; + + pipe = current->thread.mode.tt.switch_pipe; + suspend_new_thread(&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); + + /* XXX No set_user_mode here because a newly execed process will + * immediately segfault on its non-existent IP, coming straight back + * to the signal handler, which will call set_user_mode on its way + * out. This should probably change since it's confusing. + */ +} + +static int new_thread_proc(void *stack) +{ + /* 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()); + change_sig(SIGUSR1, 1); + return(0); +} + +/* Signal masking - signals are blocked at the start of fork_tramp. They + * are re-enabled when finish_fork_handler is entered by fork_tramp hitting + * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, + * so it is blocked before it's called. They are re-enabled on sigreturn + * despite the fact that they were blocked when the SIGUSR1 was issued because + * copy_thread copies the parent's sigcontext, including the signal mask + * onto the signal frame. + */ + +static void finish_fork_handler(int sig) +{ + struct file_handle *pipe = current->thread.mode.tt.switch_pipe; + + UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); + suspend_new_thread(&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()); + change_sig(SIGUSR1, 1); + return(0); +} + +struct file_handle *make_switch_pipe(void) +{ + struct file_handle *pipe; + int err; + + pipe = kmalloc(sizeof(struct file_handle [2]), GFP_KERNEL); + if(pipe == NULL){ + pipe = ERR_PTR(-ENOMEM); + goto out; + } + + err = make_pipe(pipe); + if(err) + goto out_free; + + out: + return(pipe); + + out_free: + kfree(pipe); + pipe = ERR_PTR(err); + goto out; +} + +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; + } + + p->thread.mode.tt.switch_pipe = make_switch_pipe(); + if(IS_ERR(p->thread.mode.tt.switch_pipe)){ + err = PTR_ERR(p->thread.mode.tt.switch_pipe); + goto out; + } + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR "copy_thread : failed to allocate " + "temporary stack\n"); + err = -ENOMEM; + goto out_close; + } + + clone_flags &= CLONE_VM; + p->thread.temp_stack = stack; + new_pid = start_fork_tramp(p, stack, clone_flags, tramp); + if(new_pid < 0){ + printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", + -new_pid); + err = new_pid; + goto out_stack; + } + + 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()); + + /* Enable the signal and then disable it to ensure that it is handled + * here, and nowhere else. + */ + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + err = 0; + + out: + return(err); + + out_stack: + free_stack(stack, 0); + out_close: + close_file(&((struct file_handle *) p->thread.mode.tt.switch_pipe)[0]); + close_file(&((struct file_handle *) p->thread.mode.tt.switch_pipe)[1]); + kfree(p->thread.mode.tt.switch_pipe); + goto out; +} + +void reboot_tt(void) +{ + current->thread.request.op = OP_REBOOT; + os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); +} + +void halt_tt(void) +{ + current->thread.request.op = OP_HALT; + os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); +} + +void kill_off_processes_tt(void) +{ + struct task_struct *p; + int me; + + me = os_getpid(); + for_each_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()); + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + } +} + +int do_proc_op(void *t, int proc_id) +{ + struct task_struct *task; + struct thread_struct *thread; + int op, pid; + + task = t; + thread = &task->thread; + op = thread->request.op; + switch(op){ + case OP_NONE: + case OP_TRACE_ON: + break; + case OP_EXEC: + pid = thread->request.u.exec.pid; + do_exec(thread->mode.tt.extern_pid, pid); + thread->mode.tt.extern_pid = pid; + cpu_tasks[task->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); +} + +/* This is static rather than kmalloced because this happens before kmalloc + * is initialized. Also, it is always needed, so might as well be static on + * this ground. + */ +static struct file_handle init_switch_pipe[2]; + +void set_init_pid(int pid) +{ + int err; + + init_task.thread.mode.tt.extern_pid = pid; + + err = make_pipe(init_switch_pipe); + if(err) + panic("set_init_pid - make_pipe failed, errno = %d", err); + init_task.thread.mode.tt.switch_pipe = init_switch_pipe; +} + +int start_uml_tt(void) +{ + void *sp; + int pages; + + pages = (1 << CONFIG_KERNEL_STACK_ORDER); + sp = (void *) ((unsigned long) &init_task) + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/Makefile 2005-05-03 22:28:14.526401864 +0300 @@ -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: Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/proxy.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/proxy.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/proxy.c 2005-05-03 22:28:14.529401408 +0300 @@ -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){ + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); + if(pid != debugger.pid){ + printk("fake_child_exit - waitpid failed, " + "errno = %d\n", errno); + return; + } + debugger_proxy(status, debugger.pid); + } + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); + if(pid != debugger.pid){ + printk("fake_child_exit - waitpid failed, " + "errno = %d\n", errno); + return; + } + if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) + printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", + errno); +} + +char gdb_init_string[] = +"att 1 \n\ +b panic \n\ +b stop \n\ +handle SIGWINCH nostop noprint pass \n\ +"; + +int start_debugger(char *prog, int startup, int stop, int *fd_out) +{ + int slave, child; + + slave = open_gdb_chan(); + child = fork(); + if(child == 0){ + char *tempname = NULL; + int fd; + + if(setsid() < 0) perror("setsid"); + if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || + (dup2(slave, 2) < 0)){ + printk("start_debugger : dup2 failed, errno = %d\n", + errno); + exit(1); + } + if(ioctl(0, TIOCSCTTY, 0) < 0){ + printk("start_debugger : TIOCSCTTY failed, " + "errno = %d\n", errno); + exit(1); + } + if(tcsetpgrp (1, os_getpid()) < 0){ + printk("start_debugger : tcsetpgrp failed, " + "errno = %d\n", errno); +#ifdef notdef + exit(1); +#endif + } + fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); + if(fd < 0){ + printk("start_debugger : make_tempfile failed," + "err = %d\n", -fd); + exit(1); + } + os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + if(startup){ + if(stop){ + os_write_file(fd, "b start_kernel\n", + strlen("b start_kernel\n")); + } + os_write_file(fd, "c\n", strlen("c\n")); + } + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ + printk("start_debugger : PTRACE_TRACEME failed, " + "errno = %d\n", errno); + exit(1); + } + execlp("gdb", "gdb", "--command", tempname, prog, NULL); + printk("start_debugger : exec of gdb failed, errno = %d\n", + errno); + } + if(child < 0){ + printk("start_debugger : fork for gdb failed, errno = %d\n", + errno); + return(-1); + } + *fd_out = slave; + return(child); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/ptproxy.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/ptproxy.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/ptproxy.h 2005-05-03 22:28:14.529401408 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/ptrace.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/ptrace.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/ptrace.c 2005-05-03 22:28:14.531401104 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/sysdep.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.c 2005-05-03 22:28:14.532400952 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/sysdep.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.h 2005-05-03 22:28:14.533400800 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/wait.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.c 2005-05-03 22:28:14.534400648 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.h =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/wait.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.h 2005-05-03 22:28:14.534400648 +0300 @@ -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 Index: linux-2.4.29/arch/um/kernel/tt/syscall_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/syscall_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/syscall_kern.c 2005-05-03 22:28:14.536400344 +0300 @@ -0,0 +1,136 @@ +/* + * 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); + + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/syscall_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/syscall_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/syscall_user.c 2005-05-03 22:28:14.537400192 +0300 @@ -0,0 +1,92 @@ +/* + * 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(use_sysemu) + return(1); + + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/sys-i386/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/sys-i386/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/sys-i386/Makefile 2005-05-03 22:28:14.538400040 +0300 @@ -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 : Index: linux-2.4.29/arch/um/kernel/tt/sys-i386/sigcontext.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/sys-i386/sigcontext.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/sys-i386/sigcontext.c 2005-05-03 22:28:14.539399888 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/time.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/time.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/time.c 2005-05-03 22:28:14.540399736 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/tlb.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/tlb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/tlb.c 2005-05-03 22:28:14.541399584 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/tracer.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/tracer.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/tracer.c 2005-05-03 22:28:14.543399280 +0300 @@ -0,0 +1,457 @@ +/* + * 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; + int cont_syscall; + + 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); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if(n < 0){ + printf("waitpid on idle thread failed, errno = %d\n", errno); + exit(1); + } + if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ + printf("Failed to continue idle thread, errno = %d\n", errno); + exit(1); + } + + signal(SIGSEGV, (sighandler_t) tracer_segv); + signal(SIGUSR1, signal_usr1); + if(debug_trace){ + printf("Tracing thread pausing to be attached\n"); + stop(); + } + if(debug){ + if(gdb_pid != -1) + debugger_pid = attach_debugger(pid, gdb_pid, 1); + else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); + if(debug_parent){ + debugger_parent = os_process_parent(debugger_pid); + init_parent_proxy(debugger_parent); + err = attach(debugger_parent); + if(err){ + printf("Failed to attach debugger parent %d, " + "errno = %d\n", debugger_parent, -err); + debugger_parent = -1; + } + else { + if(ptrace(PTRACE_SYSCALL, debugger_parent, + 0, 0) < 0){ + printf("Failed to continue debugger " + "parent, errno = %d\n", errno); + debugger_parent = -1; + } + } + } + } + set_cmdline("(tracing thread)"); + while(1){ + CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); + if(pid <= 0){ + if(errno != ECHILD){ + printf("wait failed - errno = %d\n", errno); + } + continue; + } + if(pid == debugger_pid){ + int cont = 0; + + if(WIFEXITED(status) || WIFSIGNALED(status)) + debugger_pid = -1; + /* XXX Figure out how to deal with gdb and SMP */ + else cont = debugger_signal(status, cpu_tasks[0].pid); + if(cont == PTRACE_SYSCALL) strace = 1; + continue; + } + else if(pid == debugger_parent){ + debugger_parent_signal(status, pid); + continue; + } + nsignals++; + if(WIFEXITED(status)) ; +#ifdef notdef + { + printf("Child %d exited with status %d\n", pid, + WEXITSTATUS(status)); + } +#endif + else if(WIFSIGNALED(status)){ + sig = WTERMSIG(status); + if(sig != 9){ + printf("Child %d exited with signal %d\n", pid, + sig); + } + } + else if(WIFSTOPPED(status)){ + proc_id = pid_to_processor_id(pid); + sig = WSTOPSIG(status); + 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; + + cont_syscall = use_sysemu ? PTRACE_SYSEMU : + PTRACE_SYSCALL; + 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; + 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(task)) + cont_type = PTRACE_SINGLESTEP; + else cont_type = cont_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: + */ Index: linux-2.4.29/arch/um/kernel/tt/trap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/trap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/trap_user.c 2005-05-03 22:28:14.544399128 +0300 @@ -0,0 +1,64 @@ +/* + * 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(); + + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + + r = &TASK_REGS(get_current())->tt; + save_regs = *r; + is_user = user_context(SC_SP(sc)); + r->sc = sc; + if(sig != SIGUSR2) + r->syscall = -1; + + info = &sig_info[sig]; + if(!info->is_irq) unblock_signals(); + + (*info->handler)(sig, (union uml_pt_regs *) r); + + if(is_user){ + interrupt_end(); + block_signals(); + set_user_mode(NULL); + } + *r = save_regs; + errno = save_errno; + 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: + */ Index: linux-2.4.29/arch/um/kernel/tt/uaccess.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/uaccess.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/uaccess.c 2005-05-03 22:28:14.545398976 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/uaccess_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/uaccess_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/uaccess_user.c 2005-05-03 22:28:14.546398824 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tt/unmap.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tt/unmap.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tt/unmap.c 2005-05-03 22:28:14.547398672 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/tty_log.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/tty_log.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/tty_log.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and + * geoffrey hing <ghing@net.ohio-state.edu> + * Licensed under the GPL + */ + +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> +#include "init.h" +#include "user.h" +#include "kern_util.h" +#include "os.h" + +#define TTY_LOG_DIR "./" + +/* Set early in boot and then unchanged */ +static char *tty_log_dir = TTY_LOG_DIR; +static int tty_log_fd = -1; + +#define TTY_LOG_OPEN 1 +#define TTY_LOG_CLOSE 2 +#define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 + +struct tty_log_buf { + int what; + unsigned long tty; + int len; + int direction; + unsigned long sec; + unsigned long usec; +}; + +int open_tty_log(void *tty, void *current_tty) +{ + struct timeval tv; + struct tty_log_buf data; + char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; + int fd; + + gettimeofday(&tv, NULL); + if(tty_log_fd != -1){ + data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, + .tty = (unsigned long) tty, + .len = sizeof(current_tty), + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + os_write_file(tty_log_fd, ¤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; + } + + *add = 0; + return 0; +} + +__uml_setup("tty_log_fd=", set_tty_log_fd, +"tty_log_fd=<fd>\n" +" This is used to specify a preconfigured file descriptor to which all\n" +" tty data will be written. Preconfigure the descriptor with something\n" +" like '10>tty_log tty_log_fd=10'.\n\n" +); + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/kernel/uaccess_user.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/uaccess_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/uaccess_user.c 2005-05-03 22:28:14.549398368 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/kernel/um_arch.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/um_arch.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/um_arch.c 2005-05-03 22:28:14.552397912 +0300 @@ -0,0 +1,445 @@ +/* + * 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 "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, diff; + unsigned long virtmem_size, max_physmem; + unsigned int i, add; + + for (i = 1; i < argc; i++){ + if((i == 1) && (argv[i][0] == ' ')) continue; + add = 1; + uml_checksetup(argv[i], &add); + if(add) add_arg(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); + + /* Need to check this early because mmapping happens before the + * kernel is running. + */ + check_tmpexec(); + + brk_start = (unsigned long) sbrk(0); + CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); + /* Increase physical memory size for exec-shield users + so they actually get what they asked for. This should + add zero for non-exec shield users */ + + diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + if(diff > 1024 * 1024){ + printf("Adding %ld bytes to physical memory to account for " + "exec-shield gap\n", diff); + physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + } + + uml_physmem = uml_start; + + /* Reserve up to 4M after the current brk */ + uml_reserved = ROUND_4M(brk_start) + (1 << 22); + + setup_machinename(system_utsname.machine); + +#ifdef CONFIG_MODE_TT + argv1_begin = argv[1]; + argv1_end = &argv[1][strlen(argv[1])]; +#endif + + highmem = 0; + iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + + /* Zones have to begin on a 1 << MAX_ORDER page boundary, + * so this makes sure that's true for highmem + */ + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + if(physmem_size + iomem_size > max_physmem){ + highmem = physmem_size + iomem_size - max_physmem; + physmem_size -= highmem; +#ifndef CONFIG_HIGHMEM + highmem = 0; + printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " + "to %ld bytes\n", physmem_size); +#endif + } + + high_physmem = uml_physmem + physmem_size; + end_iomem = high_physmem + iomem_size; + high_memory = (void *) end_iomem; + + start_vm = VMALLOC_START; + + setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); + if(init_maps(physmem_size, iomem_size, highmem)){ + printf("Failed to allocate mem_map for %ld bytes of physical " + "memory and %ld bytes of highmem\n", physmem_size, + highmem); + exit(1); + } + + virtmem_size = physmem_size; + avail = get_kmem_end() - start_vm; + if(physmem_size > avail) virtmem_size = avail; + end_vm = start_vm + virtmem_size; + + if(virtmem_size < physmem_size) + printf("Kernel virtual memory size shrunk to %ld bytes\n", + virtmem_size); + + uml_postsetup(); + + task_protections((unsigned long) &init_task); + os_flush_stdout(); + + return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); +} + +extern int uml_exitcode; + +static int panic_exit(struct notifier_block *self, unsigned long unused1, + void *unused2) +{ +#ifdef CONFIG_MAGIC_SYSRQ + handle_sysrq('p', ¤t->thread.regs, NULL, NULL); +#endif + uml_exitcode = 1; + machine_halt(); + return(0); +} + +static struct notifier_block panic_exit_notifier = { + .notifier_call = panic_exit, + .next = NULL, + .priority = 0 +}; + +void __init setup_arch(char **cmdline_p) +{ + notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); + paging_init(); + 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: + */ Index: linux-2.4.29/arch/um/kernel/umid.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/umid.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/umid.c 2005-05-03 22:28:14.554397608 +0300 @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <dirent.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/param.h> +#include "user.h" +#include "umid.h" +#include "init.h" +#include "os.h" +#include "user_util.h" +#include "choose-mode.h" + +#define UMID_LEN 64 +#define UML_DIR "~/.uml/" + +/* Changed by set_umid and make_umid, which are run early in boot */ +static char umid[UMID_LEN] = { 0 }; + +/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ +static char *uml_dir = UML_DIR; + +/* Changed by set_umid */ +static int umid_is_random = 1; +static int umid_inited = 0; + +static int make_umid(int (*printer)(const char *fmt, ...)); + +static int __init set_umid(char *name, int is_random, + int (*printer)(const char *fmt, ...)) +{ + if(umid_inited){ + (*printer)("Unique machine name can't be set twice\n"); + return(-1); + } + + if(strlen(name) > UMID_LEN - 1) + (*printer)("Unique machine name is being truncated to %d " + "characters\n", UMID_LEN); + 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) +{ + *add = 0; + return(set_umid(name, 0, printf)); +} + +__uml_setup("umid=", set_umid_arg, +"umid=<name>\n" +" This is used to assign a unique identity to this UML machine and\n" +" is used for naming the pid file and management console socket.\n\n" +); + +int __init umid_file_name(char *name, char *buf, int len) +{ + int n; + + if(!umid_inited && make_umid(printk)) return(-1); + + n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; + if(n > len){ + printk("umid_file_name : buffer too short\n"); + return(-1); + } + + sprintf(buf, "%s%s/%s", uml_dir, umid, name); + return(0); +} + +extern int tracing_pid; + +static int __init create_pid_file(void) +{ + char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; + char pid[sizeof("nnnnn\0")]; + int fd, n; + + if(umid_file_name("pid", file, sizeof(file))) return 0; + + fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), + 0644); + if(fd < 0){ + printf("Open of machine pid file \"%s\" failed - " + "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) + 2); + if(uml_dir == NULL){ + printf("Failed to malloc uml_dir - error = %d\n", + errno); + uml_dir = name; + /* Return 0 here because do_initcalls doesn't look at + * the return value. + */ + return(0); + } + sprintf(uml_dir, "%s/", name); + } + else uml_dir = name; + return(0); +} + +static int __init make_uml_dir(void) +{ + char dir[MAXPATHLEN + 1] = { '\0' }; + int len; + + if(*uml_dir == '~'){ + char *home = getenv("HOME"); + + if(home == NULL){ + printf("make_uml_dir : no value in environment for " + "$HOME\n"); + exit(1); + } + 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: + */ Index: linux-2.4.29/arch/um/kernel/user_syms.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/user_syms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/user_syms.c 2005-05-03 23:38:38.888201256 +0300 @@ -0,0 +1,85 @@ +#include "linux/types.h" +#include "linux/module.h" + +/* XXX Deleted a number of symbols because they clashed strangely with headers + * Add them back later. + */ + +#if 1 +/* Some of this are builtin function (some are not but could in the future), + * so I *must* declare good prototypes for them and then EXPORT them. + * The kernel code uses the macro defined by include/linux/string.h, + * so I undef macros; the userspace code does not include that and I + * add an EXPORT for the glibc one.*/ + +#undef strlen +#undef memcpy +#undef memset + +//extern size_t strlen(const char *); +extern void *memcpy(void *, const void *, size_t); +extern void *memset(void *, int, size_t); +//extern int printf(const char *, ...); + +//EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcpy); +#undef strstr + +EXPORT_SYMBOL(strstr); + +#endif + +/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. + * However, the modules will use the CRC defined *here*, no matter if it is + * good; so the versions of these symbols will always match + */ +#define EXPORT_SYMBOL_PROTO(sym) \ + int sym(void); \ + EXPORT_SYMBOL(sym); + +EXPORT_SYMBOL_PROTO(__errno_location); + +EXPORT_SYMBOL_PROTO(access); +EXPORT_SYMBOL_PROTO(open); +EXPORT_SYMBOL_PROTO(open64); +EXPORT_SYMBOL_PROTO(close); +EXPORT_SYMBOL_PROTO(read); +EXPORT_SYMBOL_PROTO(write); +EXPORT_SYMBOL_PROTO(dup2); +EXPORT_SYMBOL_PROTO(__xstat); +EXPORT_SYMBOL_PROTO(__lxstat); +EXPORT_SYMBOL_PROTO(__lxstat64); +EXPORT_SYMBOL_PROTO(lseek); +EXPORT_SYMBOL_PROTO(lseek64); +EXPORT_SYMBOL_PROTO(chown); +EXPORT_SYMBOL_PROTO(truncate); +EXPORT_SYMBOL_PROTO(utime); +EXPORT_SYMBOL_PROTO(chmod); +EXPORT_SYMBOL_PROTO(rename); +EXPORT_SYMBOL_PROTO(__xmknod); + +EXPORT_SYMBOL_PROTO(symlink); +EXPORT_SYMBOL_PROTO(link); +EXPORT_SYMBOL_PROTO(unlink); +EXPORT_SYMBOL_PROTO(readlink); + +EXPORT_SYMBOL_PROTO(mkdir); +EXPORT_SYMBOL_PROTO(rmdir); +EXPORT_SYMBOL_PROTO(opendir); +EXPORT_SYMBOL_PROTO(readdir); +EXPORT_SYMBOL_PROTO(closedir); +EXPORT_SYMBOL_PROTO(seekdir); +EXPORT_SYMBOL_PROTO(telldir); + +EXPORT_SYMBOL_PROTO(ioctl); + +EXPORT_SYMBOL_PROTO(pread64); +EXPORT_SYMBOL_PROTO(pwrite64); + +EXPORT_SYMBOL_PROTO(statfs); +EXPORT_SYMBOL_PROTO(statfs64); + +EXPORT_SYMBOL_PROTO(getuid); + +EXPORT_SYMBOL_PROTO(printf); Index: linux-2.4.29/arch/um/kernel/user_util.c =================================================================== --- linux-2.4.29.orig/arch/um/kernel/user_util.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/kernel/user_util.c 2005-05-03 22:28:14.556397304 +0300 @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <setjmp.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/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){ + CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); + if((ret < 0) || + !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ + if(ret < 0){ + printk("wait failed, errno = %d\n", + errno); + } + else if(WIFEXITED(status)) + printk("process %d exited with status %d\n", + pid, WEXITSTATUS(status)); + else if(WIFSIGNALED(status)) + printk("process %d exited with signal %d\n", + pid, WTERMSIG(status)); + else if((WSTOPSIG(status) == SIGVTALRM) || + (WSTOPSIG(status) == SIGALRM) || + (WSTOPSIG(status) == SIGIO) || + (WSTOPSIG(status) == SIGPROF) || + (WSTOPSIG(status) == SIGCHLD) || + (WSTOPSIG(status) == SIGWINCH) || + (WSTOPSIG(status) == SIGINT)){ + ptrace(cont_type, pid, 0, WSTOPSIG(status)); + continue; + } + else if((relay_signals != NULL) && + sigismember(relay_signals, WSTOPSIG(status))){ + ptrace(cont_type, pid, 0, WSTOPSIG(status)); + continue; + } + else printk("process %d stopped with signal %d\n", + pid, WSTOPSIG(status)); + panic("wait_for_stop failed to wait for %d to stop " + "with %d\n", pid, sig); + } + return(status); + } +} + +int raw(int fd) +{ + struct termios tt; + int err; + + CATCH_EINTR(err = tcgetattr(fd, &tt)); + if (err < 0) { + printk("tcgetattr failed, errno = %d\n", errno); + return(-errno); + } + + cfmakeraw(&tt); + + CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); + if (err < 0) { + printk("tcsetattr failed, errno = %d\n", errno); + return(-errno); + } + + /* XXX tcsetattr could have applied only some changes + * (and cfmakeraw() is a set of changes) */ + return(0); +} + +void setup_machinename(char *machine_out) +{ + struct utsname host; + + uname(&host); + strcpy(machine_out, host.machine); +} + +char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; + +void setup_hostinfo(void) +{ + struct utsname host; + + uname(&host); + sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, + host.release, host.version, host.machine); +} + +int setjmp_wrapper(void (*proc)(void *, void *), ...) +{ + va_list args; + sigjmp_buf buf; + int n; + + n = sigsetjmp(buf, 1); + if(n == 0){ + va_start(args, proc); + (*proc)(&buf, &args); + } + va_end(args); + return(n); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,191 @@ +# +# 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 + +# We require bash because the vmlinux link and loader script cpp use bash +# features. +SHELL := /bin/bash + +# 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) + +check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) + +CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) + +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)/kernel/$(LD_SCRIPT-y) +M4_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT) + +ifndef START + START = $$(($(TOP_ADDR) - $(SIZE))) +endif + +$(LD_SCRIPT-y): $(LD_SCRIPT-y).in + pages=$$(( 1 << $(CONFIG_KERNEL_STACK_ORDER) )) ; \ + m4 -DSTART=$(START) -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 vmlinux $(LD_SCRIPT-y) + mv vmlinux vmlinux.o + $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ + -o linux 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 removed temporarily because this causes +# make to fail after make clean + +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 + +all: linux + +define archhelp + echo '* linux - Binary kernel image (./linux)' +endef Index: linux-2.4.29/arch/um/Makefile-i386 =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-i386 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-i386 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,46 @@ +ifeq ($(CONFIG_HOST_2G_2G),y) +TOP_ADDR = 0x80000000 +else +TOP_ADDR = 0xc0000000 +endif + +ifeq ($(CONFIG_MODE_SKAS),y) + ifneq ($(CONFIG_MODE_TT),y) + START = 0x8048000 + endif +endif + +ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) + +ifneq ($(CONFIG_GPROF),y) +ARCH_CFLAGS += -DUM_FASTCALL +endif + +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 + Index: linux-2.4.29/arch/um/Makefile-ia64 =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-ia64 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-ia64 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1 @@ +START_ADDR = 0x1000000000000000 Index: linux-2.4.29/arch/um/Makefile-os-Linux =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-os-Linux 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-os-Linux 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/Makefile-ppc =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-ppc 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-ppc 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/Makefile-skas =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-skas 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-skas 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/Makefile-tt =================================================================== --- linux-2.4.29.orig/arch/um/Makefile-tt 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/Makefile-tt 2005-05-03 22:28:14.000000000 +0300 @@ -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 + Index: linux-2.4.29/arch/um/os-Linux/aio.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/aio.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/aio.c 2005-05-03 22:28:14.563396240 +0300 @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sched.h> +#include <sys/syscall.h> +#include "os.h" +#include "helper.h" +#include "aio.h" +#include "init.h" +#include "user.h" +#include "mode.h" + +struct aio_thread_req { + enum aio_type type; + int io_fd; + unsigned long long offset; + char *buf; + int len; + int reply_fd; + void *data; +}; + +static int aio_req_fd_r = -1; +static int aio_req_fd_w = -1; + +#if defined(HAVE_AIO_ABI) +#include <linux/aio_abi.h> + +/* If we have the headers, we are going to build with AIO enabled. + * If we don't have aio in libc, we define the necessary stubs here. + */ + +#if !defined(HAVE_AIO_LIBC) + +#define __NR_io_setup 245 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 + +static long io_setup(int n, aio_context_t *ctxp) +{ + return(syscall(__NR_io_setup, n, ctxp)); +} + +static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) +{ + return(syscall(__NR_io_submit, ctx, nr, iocbpp)); +} + +static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, + struct io_event *events, struct timespec *timeout) +{ + return(syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout)); +} + +#endif + +/* The AIO_MMAP cases force the mmapped page into memory here + * rather than in whatever place first touches the data. I used + * to do this by touching the page, but that's delicate because + * gcc is prone to optimizing that away. So, what's done here + * is we read from the descriptor from which the page was + * mapped. The caller is required to pass an offset which is + * inside the page that was mapped. Thus, when the read + * returns, we know that the page is in the page cache, and + * that it now backs the mmapped area. + */ + +static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, + int len, unsigned long long offset, void *data) +{ + struct iocb iocb, *iocbp = &iocb; + char c; + int err; + + iocb = ((struct iocb) { .aio_data = (unsigned long) data, + .aio_reqprio = 0, + .aio_fildes = fd, + .aio_buf = (unsigned long) buf, + .aio_nbytes = len, + .aio_offset = offset, + .aio_reserved1 = 0, + .aio_reserved2 = 0, + .aio_reserved3 = 0 }); + + switch(type){ + case AIO_READ: + iocb.aio_lio_opcode = IOCB_CMD_PREAD; + err = io_submit(ctx, 1, &iocbp); + break; + case AIO_WRITE: + iocb.aio_lio_opcode = IOCB_CMD_PWRITE; + err = io_submit(ctx, 1, &iocbp); + break; + case AIO_MMAP: + iocb.aio_lio_opcode = IOCB_CMD_PREAD; + iocb.aio_buf = (unsigned long) &c; + iocb.aio_nbytes = sizeof(c); + err = io_submit(ctx, 1, &iocbp); + break; + default: + printk("Bogus op in do_aio - %d\n", type); + err = -EINVAL; + break; + } + if(err > 0) + err = 0; + + return(err); +} + +static aio_context_t ctx = 0; + +static int aio_thread(void *arg) +{ + struct aio_thread_reply reply; + struct io_event event; + int err, n, reply_fd; + + signal(SIGWINCH, SIG_IGN); + + while(1){ + n = io_getevents(ctx, 1, 1, &event, NULL); + if(n < 0){ + if(errno == EINTR) + continue; + printk("aio_thread - io_getevents failed, " + "errno = %d\n", errno); + } + else { + reply = ((struct aio_thread_reply) + { .data = (void *) event.data, + .err = event.res }); + reply_fd = + ((struct aio_context *) event.data)->reply_fd; + err = os_write_file(reply_fd, &reply, sizeof(reply)); + if(err != sizeof(reply)) + printk("not_aio_thread - write failed, " + "fd = %d, err = %d\n", + aio_req_fd_r, -err); + } + } + return(0); +} + +#endif + +static int do_not_aio(struct aio_thread_req *req) +{ + char c; + int err; + + switch(req->type){ + case AIO_READ: + err = os_seek_file(req->io_fd, req->offset); + if(err) + goto out; + + err = os_read_file(req->io_fd, req->buf, req->len); + break; + case AIO_WRITE: + err = os_seek_file(req->io_fd, req->offset); + if(err) + goto out; + + err = os_write_file(req->io_fd, req->buf, req->len); + break; + case AIO_MMAP: + err = os_seek_file(req->io_fd, req->offset); + if(err) + goto out; + + err = os_read_file(req->io_fd, &c, sizeof(c)); + break; + default: + printk("do_not_aio - bad request type : %d\n", req->type); + err = -EINVAL; + break; + } + + out: + return(err); +} + +static int not_aio_thread(void *arg) +{ + struct aio_thread_req req; + struct aio_thread_reply reply; + int err; + + signal(SIGWINCH, SIG_IGN); + while(1){ + err = os_read_file(aio_req_fd_r, &req, sizeof(req)); + if(err != sizeof(req)){ + if(err < 0) + printk("not_aio_thread - read failed, fd = %d, " + "err = %d\n", aio_req_fd_r, -err); + else { + printk("not_aio_thread - short read, fd = %d, " + "length = %d\n", aio_req_fd_r, err); + } + continue; + } + err = do_not_aio(&req); + reply = ((struct aio_thread_reply) { .data = req.data, + .err = err }); + err = os_write_file(req.reply_fd, &reply, sizeof(reply)); + if(err != sizeof(reply)) + printk("not_aio_thread - write failed, fd = %d, " + "err = %d\n", aio_req_fd_r, -err); + } +} + +static int aio_pid = -1; + +static int init_aio_24(void) +{ + unsigned long stack; + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if(err) + goto out; + + aio_req_fd_w = fds[0]; + aio_req_fd_r = fds[1]; + err = run_helper_thread(not_aio_thread, NULL, + CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); + if(err < 0) + goto out_close_pipe; + + aio_pid = err; + goto out; + + out_close_pipe: + os_close_file(fds[0]); + os_close_file(fds[1]); + aio_req_fd_w = -1; + aio_req_fd_r = -1; + out: + return(0); +} + +#ifdef HAVE_AIO_ABI +#define DEFAULT_24_AIO 0 +static int init_aio_26(void) +{ + unsigned long stack; + int err; + + if(io_setup(256, &ctx)){ + printk("aio_thread failed to initialize context, err = %d\n", + errno); + return(-errno); + } + + err = run_helper_thread(aio_thread, NULL, + CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); + if(err < 0) + return(-errno); + + aio_pid = err; + err = 0; + out: + return(err); +} + +int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, + unsigned long long offset, int reply_fd, void *data) +{ + struct aio_thread_reply reply; + int err; + + ((struct aio_context *) data)->reply_fd = reply_fd; + + err = do_aio(ctx, type, io_fd, buf, len, offset, data); + if(err){ + reply = ((struct aio_thread_reply) { .data = data, + .err = err }); + err = os_write_file(reply_fd, &reply, sizeof(reply)); + if(err != sizeof(reply)) + printk("submit_aio_26 - write failed, " + "fd = %d, err = %d\n", reply_fd, -err); + else err = 0; + } + + return(err); +} + +#else +#define DEFAULT_24_AIO 1 +static int init_aio_26(void) +{ + return(-ENOSYS); +} + +int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, + unsigned long long offset, int reply_fd, void *data) +{ + return(-ENOSYS); +} +#endif + +static int aio_24 = DEFAULT_24_AIO; + +static int __init set_aio_24(char *name, int *add) +{ + aio_24 = 1; + return(0); +} + +__uml_setup("aio=2.4", set_aio_24, +"aio=2.4\n" +" This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n" +" available. 2.4 AIO is a single thread that handles one request at a\n" +" time, synchronously. 2.6 AIO is a thread which uses 2.5 AIO interface\n" +" to handle an arbitrary number of pending requests. 2.6 AIO is not\n" +" available in tt mode, on 2.4 hosts, or when UML is built with\n" +" /usr/include/linux/aio_abi no available.\n\n" +); + +static int init_aio(void) +{ + int err; + + CHOOSE_MODE(({ + if(!aio_24){ + printk("Disabling 2.6 AIO in tt mode\n"); + aio_24 = 1; + } }), (void) 0); + + if(!aio_24){ + err = init_aio_26(); + if(err && (errno == ENOSYS)){ + printk("2.6 AIO not supported on the host - " + "reverting to 2.4 AIO\n"); + aio_24 = 1; + } + else return(err); + } + + if(aio_24) + return(init_aio_24()); + + return(0); +} + +__initcall(init_aio); + +static void exit_aio(void) +{ + if(aio_pid != -1) + os_kill_process(aio_pid, 1); +} + +__uml_exitcall(exit_aio); + +int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, + unsigned long long offset, int reply_fd, void *data) +{ + struct aio_thread_req req = { .type = type, + .io_fd = io_fd, + .offset = offset, + .buf = buf, + .len = len, + .reply_fd = reply_fd, + .data = data, + }; + int err; + + err = os_write_file(aio_req_fd_w, &req, sizeof(req)); + if(err == sizeof(req)) + err = 0; + + return(err); +} + +int submit_aio(enum aio_type type, int io_fd, char *buf, int len, + unsigned long long offset, int reply_fd, void *data) +{ + if(aio_24) + return(submit_aio_24(type, io_fd, buf, len, offset, reply_fd, + data)); + else { + return(submit_aio_26(type, io_fd, buf, len, offset, reply_fd, + data)); + } +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/etap.h =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/etap.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/etap.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/ethertap_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/ethertap_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/ethertap_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,121 @@ +/* + * 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 "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: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/ethertap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/ethertap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/ethertap_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,240 @@ +/* + * 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 "user_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; + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 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: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/Makefile 2005-05-03 22:28:14.568395480 +0300 @@ -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) Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap.h =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap.h 2005-05-03 22:28:14.568395480 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap_kern.c 2005-05-03 22:28:14.569395328 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap_user.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap_user.c 2005-05-03 22:28:14.571395024 +0300 @@ -0,0 +1,225 @@ +/* + * 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_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); + } + CATCH_EINTR(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: + */ Index: linux-2.4.29/arch/um/os-Linux/file.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/file.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/file.c 2005-05-03 22:28:14.574394568 +0300 @@ -0,0 +1,942 @@ +/* + * 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 <utime.h> +#include <dirent.h> +#include <linux/kdev_t.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 <sys/utsname.h> +#include <sys/vfs.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_major = MAJOR(src->st_dev), /* device */ + .ust_minor = MINOR(src->st_dev), + .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 */ + .ust_rmajor = MAJOR(src->st_rdev), + .ust_rminor = MINOR(src->st_rdev), + }); +} + +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_lstat_file(const char *file_name, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = lstat64(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); +} + +int os_set_file_time(const char *file, unsigned long access, unsigned long mod) +{ + struct utimbuf buf = ((struct utimbuf){ .actime = access, + .modtime = mod }); + int err; + + err = utime(file, &buf); + if(err < 0) + return(-errno); + + return(0); +} + +int os_set_file_perms(const char *file, int mode) +{ + int err; + + err = chmod(file, mode); + if(err < 0) + return(-errno); + + return(0); +} + +int os_set_file_owner(const char *file, int owner, int group) +{ + int err; + + err = chown(file, owner, group); + 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_lstat_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; + if(flags.d) f |= O_DIRECT; + + 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); +} + +void *os_open_dir(char *path, int *err_out) +{ + void *dir; + + dir = opendir(path); + *err_out = -errno; + return(dir); +} + +int os_seek_dir(void *stream, unsigned long long pos) +{ + seekdir(stream, pos); + return(0); +} + +int os_read_dir(void *stream, unsigned long long *ino_out, char **name_out) +{ + struct dirent *ent; + + errno = 0; + ent = readdir(stream); + if(ent == NULL){ + if(errno != 0) + return(-errno); + *name_out = NULL; + return(0); + } + + *ino_out = ent->d_ino; + *name_out = ent->d_name; + return(0); +} + +int os_tell_dir(void *stream) +{ + return(telldir(stream)); +} + +int os_close_dir(void *stream) +{ + int err; + + err = closedir(stream); + if(err < 0) + return(-errno); + return(0); +} + +int os_remove_file(const char *file) +{ + int err; + + err = unlink(file); + if(err) + return(-errno); + + return(0); +} + +int os_move_file(const char *from, const char *to) +{ + int err; + + err = rename(from, to); + if(err) + return(-errno); + + return(0); +} + +int os_truncate_fd(int fd, unsigned long long len) +{ + int err; + + err = ftruncate64(fd, len); + if(err) + return(-errno); + return(0); +} + +int os_truncate_file(const char *file, unsigned long long len) +{ + int err; + + err = truncate64(file, len); + if(err) + return(-errno); + return(0); +} + +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_fd_size(int fd, long long *size_out) +{ + struct stat buf; + int err; + + err = fstat(fd, &buf); + if(err) + return(-errno); + + *size_out = buf.st_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_clear_fd_async(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + flags &= ~(O_ASYNC | O_NONBLOCK); + if(fcntl(fd, F_SETFL, flags) < 0) + 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); +} + +int os_make_symlink(const char *to, const char *from) +{ + int err; + + err = symlink(to, from); + if(err) + return(-errno); + + return(0); +} + +int os_read_symlink(const char *file, char *buf, int size) +{ + int err; + + err = readlink(file, buf, size); + if(err < 0) + return(-errno); + + return(err); +} + +int os_link_file(const char *to, const char *from) +{ + int err; + + err = link(to, from); + if(err) + return(-errno); + + return(0); +} + +int os_make_dir(const char *dir, int mode) +{ + int err; + + err = mkdir(dir, mode); + if(err) + return(-errno); + + return(0); +} + +int os_make_dev(const char *name, int mode, int major, int minor) +{ + int err; + + err = mknod(name, mode, MKDEV(major, minor)); + if(err) + return(-errno); + + return(0); +} + +int os_remove_dir(const char *dir) +{ + int err; + + err = rmdir(dir); + if(err) + return(-errno); + + return(0); +} + +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); +} + +int os_stat_filesystem(char *path, 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(path, &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: + */ Index: linux-2.4.29/arch/um/os-Linux/include/file.h =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/include/file.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/include/file.h 2005-05-03 22:28:14.575394416 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/os-Linux/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/Makefile 2005-05-03 22:28:14.575394416 +0300 @@ -0,0 +1,23 @@ +# +# Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com) +# Licensed under the GPL +# + +O_TARGET = built-in.o + +obj-y = aio.o file.o process.o time.o tty.o + +HAVE_AIO_ABI = $(shell [ -e /usr/include/linux/aio_abi.h ] && \ + echo -DHAVE_AIO_ABI) +HAVE_AIO_LIBC = $(shell objdump -T /lib/libc-*.so | grep io_submit && \ + echo -DHAVE_AIO_LIBC) +CFLAGS_aio.o = $(HAVE_AIO_ABI) $(HAVE_AIO_LIBC) + +include $(TOPDIR)/Rules.make + +$(obj-y) : %.o: %.c + $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + +clean : + +archmrproper: Index: linux-2.4.29/arch/um/os-Linux/process.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/process.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/process.c 2005-05-03 22:28:14.577394112 +0300 @@ -0,0 +1,151 @@ +/* + * 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" +#include "user_util.h" + +#define ARBITRARY_ADDR -1 +#define FAILURE_PID -1 + +#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") +#define COMM_SCANF "%*[^)])" + +unsigned long os_process_pc(int pid) +{ + char proc_stat[STAT_PATH_LEN], 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 " COMM_SCANF " %*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 %lu", &pc) != 1){ + printk("os_process_pc - couldn't find pc in '%s'\n", buf); + } + return(pc); +} + +int os_process_parent(int pid) +{ + char stat[STAT_PATH_LEN]; + 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; + n = sscanf(data, "%*d " COMM_SCANF " %*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) + CATCH_EINTR(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: + */ Index: linux-2.4.29/arch/um/os-Linux/time.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/time.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/time.c 2005-05-03 22:28:14.578393960 +0300 @@ -0,0 +1,21 @@ +#include <stdlib.h> +#include <sys/time.h> + +unsigned long long os_usecs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ Index: linux-2.4.29/arch/um/os-Linux/tty.c =================================================================== --- linux-2.4.29.orig/arch/um/os-Linux/tty.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/os-Linux/tty.c 2005-05-03 22:28:14.579393808 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/bugs.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/bugs.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/bugs.c 2005-05-03 22:28:14.580393656 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/checksum.S =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/checksum.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/checksum.S 2005-05-03 22:28:14.582393352 +0300 @@ -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 Index: linux-2.4.29/arch/um/sys-i386/fault.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/fault.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/fault.c 2005-05-03 22:28:14.583393200 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/ksyms.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/ksyms.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/ksyms.c 2005-05-03 22:28:14.584393048 +0300 @@ -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); Index: linux-2.4.29/arch/um/sys-i386/ldt.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/ldt.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/ldt.c 2005-05-03 22:28:14.585392896 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/Makefile 2005-05-03 22:28:14.586392744 +0300 @@ -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 +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: Index: linux-2.4.29/arch/um/sys-i386/ptrace.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/ptrace.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/ptrace.c 2005-05-03 22:28:14.588392440 +0300 @@ -0,0 +1,367 @@ +/* + * 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 "asm/unistd.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%lx\n", + addr); + return(0); + } + /* int 0x80 or sysenter */ + return((instr == 0x80cd) || (instr == 0x340f)); +} + +/* 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: + */ Index: linux-2.4.29/arch/um/sys-i386/ptrace_user.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/ptrace_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/ptrace_user.c 2005-05-03 22:28:14.589392288 +0300 @@ -0,0 +1,118 @@ +/* + * 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, value = 0x%x, errno = %d\n", i, + regs[i], 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: + */ Index: linux-2.4.29/arch/um/sys-i386/sigcontext.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/sigcontext.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/sigcontext.c 2005-05-03 22:28:14.590392136 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/syscalls.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/syscalls.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/syscalls.c 2005-05-03 22:28:14.590392136 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-i386/sysrq.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/sysrq.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/sysrq.c 2005-05-03 22:28:14.591391984 +0300 @@ -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); +} Index: linux-2.4.29/arch/um/sys-i386/util/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/util/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/util/Makefile 2005-05-03 22:28:14.592391832 +0300 @@ -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 : + Index: linux-2.4.29/arch/um/sys-i386/util/mk_sc.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/util/mk_sc.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/util/mk_sc.c 2005-05-03 22:28:14.000000000 +0300 @@ -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); +} Index: linux-2.4.29/arch/um/sys-i386/util/mk_thread_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/util/mk_thread_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/util/mk_thread_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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); +} + Index: linux-2.4.29/arch/um/sys-i386/util/mk_thread_user.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-i386/util/mk_thread_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-i386/util/mk_thread_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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"); +} Index: linux-2.4.29/arch/um/sys-ia64/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/sys-ia64/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ia64/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/sys-ppc/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/sys-ppc/misc.S =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/misc.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/misc.S 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/sys-ppc/miscthings.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/miscthings.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/miscthings.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-ppc/ptrace.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/ptrace.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/ptrace.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-ppc/ptrace_user.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/ptrace_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/ptrace_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-ppc/sigcontext.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/sigcontext.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/sigcontext.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/sys-ppc/sysrq.c =================================================================== --- linux-2.4.29.orig/arch/um/sys-ppc/sysrq.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/sys-ppc/sysrq.c 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/arch/um/util/Makefile =================================================================== --- linux-2.4.29.orig/arch/um/util/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/util/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/arch/um/util/mk_constants_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/util/mk_constants_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/util/mk_constants_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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); +} Index: linux-2.4.29/arch/um/util/mk_constants_user.c =================================================================== --- linux-2.4.29.orig/arch/um/util/mk_constants_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/util/mk_constants_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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"); +} Index: linux-2.4.29/arch/um/util/mk_task_kern.c =================================================================== --- linux-2.4.29.orig/arch/um/util/mk_task_kern.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/util/mk_task_kern.c 2005-05-03 22:28:14.000000000 +0300 @@ -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); +} Index: linux-2.4.29/arch/um/util/mk_task_user.c =================================================================== --- linux-2.4.29.orig/arch/um/util/mk_task_user.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/arch/um/util/mk_task_user.c 2005-05-03 22:28:14.000000000 +0300 @@ -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"); +} Index: linux-2.4.29/CREDITS =================================================================== --- linux-2.4.29.orig/CREDITS 2005-05-03 21:08:24.000000000 +0300 +++ linux-2.4.29/CREDITS 2005-05-03 22:28:14.000000000 +0300 @@ -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 @@ -727,7 +728,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 Index: linux-2.4.29/Documentation/Configure.help =================================================================== --- linux-2.4.29.orig/Documentation/Configure.help 2005-05-03 21:09:27.000000000 +0300 +++ linux-2.4.29/Documentation/Configure.help 2005-05-03 23:55:57.615290736 +0300 @@ -16184,6 +16184,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. @@ -16289,17 +16346,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 @@ -16311,6 +16366,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 @@ -16357,6 +16413,9 @@ See <http://user-mode-linux.sourceforge.net/gprof.html> for more details. + This option requires that CONFIG_MODE_TT be disabled, as UML will + not build with both enabled. + If you're involved in UML kernel development and want to use gprof, say Y. If you're unsure, say N. @@ -16380,6 +16439,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 @@ -16395,6 +16467,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 @@ -16505,26 +16592,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 Index: linux-2.4.29/drivers/char/Makefile =================================================================== --- linux-2.4.29.orig/drivers/char/Makefile 2005-05-03 21:09:35.000000000 +0300 +++ linux-2.4.29/drivers/char/Makefile 2005-05-03 22:28:14.000000000 +0300 @@ -114,6 +114,12 @@ endif endif +ifeq ($(ARCH),um) + KEYMAP = + KEYBD = + CONSOLE = +endif + ifeq ($(ARCH),sh) KEYMAP = KEYBD = Index: linux-2.4.29/drivers/char/mem.c =================================================================== --- linux-2.4.29.orig/drivers/char/mem.c 2005-05-03 21:07:25.000000000 +0300 +++ linux-2.4.29/drivers/char/mem.c 2005-05-03 22:28:14.000000000 +0300 @@ -220,7 +220,7 @@ ssize_t read = 0; ssize_t virtr = 0; char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ - + if (p < (unsigned long) high_memory) { read = count; if (count > (unsigned long) high_memory - p) @@ -292,6 +292,8 @@ wrote = (unsigned long) high_memory - p; wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); + if(wrote < 0) + return(wrote); p += wrote; buf += wrote; @@ -664,6 +666,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 +697,9 @@ case 9: filp->f_op = &urandom_fops; break; + case 10: + filp->f_op = &anon_file_operations; + break; default: return -ENXIO; } @@ -719,7 +726,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; Index: linux-2.4.29/drivers/char/n_tty.c =================================================================== --- linux-2.4.29.orig/drivers/char/n_tty.c 2005-05-03 21:05:08.000000000 +0300 +++ linux-2.4.29/drivers/char/n_tty.c 2005-05-03 22:28:14.000000000 +0300 @@ -25,9 +25,11 @@ * who actually finally proved there really was a race. * * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to - * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. - * Also fixed a bug in BLOCKING mode where write_chan returns - * EAGAIN + * waiting writing processes-Sapan Bhatia <sapan@corewars.org> + * + * 2002/03/19 Fixed write_chan to stay put if console driver returns + * EAGAIN and not return since it returns an EAGAIN in a + * non-blocking operation-Sapan Bhatia <sapan@corewars.org> */ #include <linux/types.h> @@ -1393,9 +1395,9 @@ if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) { while (nr > 0) { ssize_t num = opost_block(tty, b, nr); - if (num < 0) { - if (num == -EAGAIN) - break; + if (num < 0){ + if(num == -EAGAIN) + break; retval = num; goto break_out; } Index: linux-2.4.29/drivers/char/tty_io.c =================================================================== --- linux-2.4.29.orig/drivers/char/tty_io.c 2005-05-03 21:07:50.000000000 +0300 +++ linux-2.4.29/drivers/char/tty_io.c 2005-05-03 22:28:14.000000000 +0300 @@ -967,6 +967,23 @@ tty_wakeup(tty); } +#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) { @@ -1012,8 +1029,13 @@ i = -EIO; tty_ldisc_deref(ld); 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; } @@ -1067,6 +1089,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; @@ -1662,6 +1688,11 @@ tty_set_termios_ldisc(o_tty,N_TTY); } +#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. @@ -1820,6 +1851,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; } @@ -2467,6 +2503,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 } /* Index: linux-2.4.29/drivers/net/setup.c =================================================================== --- linux-2.4.29.orig/drivers/net/setup.c 2005-05-03 21:09:27.000000000 +0300 +++ linux-2.4.29/drivers/net/setup.c 2005-05-03 22:28:14.000000000 +0300 @@ -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}, }; Index: linux-2.4.29/fs/bad_inode.c =================================================================== --- linux-2.4.29.orig/fs/bad_inode.c 2005-05-03 21:05:44.000000000 +0300 +++ linux-2.4.29/fs/bad_inode.c 2005-05-03 22:28:14.000000000 +0300 @@ -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; Index: linux-2.4.29/include/asm-i386/hardirq.h =================================================================== --- linux-2.4.29.orig/include/asm-i386/hardirq.h 2005-05-03 21:08:39.000000000 +0300 +++ linux-2.4.29/include/asm-i386/hardirq.h 2005-05-03 23:41:09.908242720 +0300 @@ -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 { Index: linux-2.4.29/include/asm-um/a.out.h =================================================================== --- linux-2.4.29.orig/include/asm-um/a.out.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/a.out.h 2005-05-03 22:28:14.909343648 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/archparam-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/archparam-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/archparam-i386.h 2005-05-03 22:28:14.911343344 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/archparam-ppc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/archparam-ppc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/archparam-ppc.h 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/arch-signal-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/arch-signal-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/arch-signal-i386.h 2005-05-03 22:28:14.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/atomic.h =================================================================== --- linux-2.4.29.orig/include/asm-um/atomic.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/atomic.h 2005-05-03 23:41:08.099517688 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_ATOMIC_H +#define __UM_ATOMIC_H + +#include "asm/arch/atomic.h" + +#endif Index: linux-2.4.29/include/asm-um/bitops.h =================================================================== --- linux-2.4.29.orig/include/asm-um/bitops.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/bitops.h 2005-05-03 23:41:08.093518600 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_BITOPS_H +#define __UM_BITOPS_H + +#include "asm/arch/bitops.h" + +#endif Index: linux-2.4.29/include/asm-um/boot.h =================================================================== --- linux-2.4.29.orig/include/asm-um/boot.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/boot.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_BOOT_H +#define __UM_BOOT_H + +#include "asm/arch/boot.h" + +#endif Index: linux-2.4.29/include/asm-um/bugs.h =================================================================== --- linux-2.4.29.orig/include/asm-um/bugs.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/bugs.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_BUGS_H +#define __UM_BUGS_H + +void check_bugs(void); + +#endif Index: linux-2.4.29/include/asm-um/byteorder.h =================================================================== --- linux-2.4.29.orig/include/asm-um/byteorder.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/byteorder.h 2005-05-03 22:37:45.347623848 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_BYTEORDER_H +#define __UM_BYTEORDER_H + +#include "asm/arch/byteorder.h" + +#endif Index: linux-2.4.29/include/asm-um/cache.h =================================================================== --- linux-2.4.29.orig/include/asm-um/cache.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/cache.h 2005-05-03 22:28:14.917342432 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_CACHE_H +#define __UM_CACHE_H + +#define L1_CACHE_BYTES 32 + +#endif Index: linux-2.4.29/include/asm-um/checksum.h =================================================================== --- linux-2.4.29.orig/include/asm-um/checksum.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/checksum.h 2005-05-03 22:28:14.917342432 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_CHECKSUM_H +#define __UM_CHECKSUM_H + +#include "sysdep/checksum.h" + +#endif Index: linux-2.4.29/include/asm-um/cobalt.h =================================================================== --- linux-2.4.29.orig/include/asm-um/cobalt.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/cobalt.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_COBALT_H +#define __UM_COBALT_H + +#include "asm/arch/cobalt.h" + +#endif Index: linux-2.4.29/include/asm-um/current.h =================================================================== --- linux-2.4.29.orig/include/asm-um/current.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/current.h 2005-05-03 23:41:08.083520120 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/delay.h =================================================================== --- linux-2.4.29.orig/include/asm-um/delay.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/delay.h 2005-05-03 22:28:14.919342128 +0300 @@ -0,0 +1,7 @@ +#ifndef __UM_DELAY_H +#define __UM_DELAY_H + +#include "asm/arch/delay.h" +#include "asm/archparam.h" + +#endif Index: linux-2.4.29/include/asm-um/desc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/desc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/desc.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_DESC_H +#define __UM_DESC_H + +#include "asm/arch/desc.h" + +#endif Index: linux-2.4.29/include/asm-um/div64.h =================================================================== --- linux-2.4.29.orig/include/asm-um/div64.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/div64.h 2005-05-03 22:28:14.941338784 +0300 @@ -0,0 +1,6 @@ +#ifndef _UM_DIV64_H +#define _UM_DIV64_H + +#include "asm/arch/div64.h" + +#endif Index: linux-2.4.29/include/asm-um/dma.h =================================================================== --- linux-2.4.29.orig/include/asm-um/dma.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/dma.h 2005-05-03 22:37:48.244183504 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/elf.h =================================================================== --- linux-2.4.29.orig/include/asm-um/elf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/elf.h 2005-05-03 22:28:14.943338480 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/errno.h =================================================================== --- linux-2.4.29.orig/include/asm-um/errno.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/errno.h 2005-05-03 22:28:14.944338328 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_ERRNO_H +#define __UM_ERRNO_H + +#include "asm/arch/errno.h" + +#endif Index: linux-2.4.29/include/asm-um/fcntl.h =================================================================== --- linux-2.4.29.orig/include/asm-um/fcntl.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/fcntl.h 2005-05-03 22:28:14.945338176 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_FCNTL_H +#define __UM_FCNTL_H + +#include "asm/arch/fcntl.h" + +#endif Index: linux-2.4.29/include/asm-um/fixmap.h =================================================================== --- linux-2.4.29.orig/include/asm-um/fixmap.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/fixmap.h 2005-05-03 23:41:11.208045120 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/floppy.h =================================================================== --- linux-2.4.29.orig/include/asm-um/floppy.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/floppy.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_FLOPPY_H +#define __UM_FLOPPY_H + +#include "asm/arch/floppy.h" + +#endif Index: linux-2.4.29/include/asm-um/hardirq.h =================================================================== --- linux-2.4.29.orig/include/asm-um/hardirq.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/hardirq.h 2005-05-03 23:41:09.909242568 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_HARDIRQ_H +#define __UM_HARDIRQ_H + +#include "asm/arch/hardirq.h" + +#endif Index: linux-2.4.29/include/asm-um/hdreg.h =================================================================== --- linux-2.4.29.orig/include/asm-um/hdreg.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/hdreg.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_HDREG_H +#define __UM_HDREG_H + +#include "asm/arch/hdreg.h" + +#endif Index: linux-2.4.29/include/asm-um/highmem.h =================================================================== --- linux-2.4.29.orig/include/asm-um/highmem.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/highmem.h 2005-05-03 23:41:11.210044816 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/hw_irq.h =================================================================== --- linux-2.4.29.orig/include/asm-um/hw_irq.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/hw_irq.h 2005-05-03 22:37:48.105204632 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/ide.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ide.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ide.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_IDE_H +#define __UM_IDE_H + +#include "asm/arch/ide.h" + +#endif Index: linux-2.4.29/include/asm-um/init.h =================================================================== --- linux-2.4.29.orig/include/asm-um/init.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/init.h 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/ioctl.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ioctl.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ioctl.h 2005-05-03 22:28:14.952337112 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_IOCTL_H +#define __UM_IOCTL_H + +#include "asm/arch/ioctl.h" + +#endif Index: linux-2.4.29/include/asm-um/ioctls.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ioctls.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ioctls.h 2005-05-03 22:37:45.509599224 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_IOCTLS_H +#define __UM_IOCTLS_H + +#include "asm/arch/ioctls.h" + +#endif Index: linux-2.4.29/include/asm-um/io.h =================================================================== --- linux-2.4.29.orig/include/asm-um/io.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/io.h 2005-05-03 22:37:48.176193840 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/ipcbuf.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ipcbuf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ipcbuf.h 2005-05-03 22:28:14.954336808 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_IPCBUF_H +#define __UM_IPCBUF_H + +#include "asm/arch/ipcbuf.h" + +#endif Index: linux-2.4.29/include/asm-um/ipc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ipc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ipc.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_IPC_H +#define __UM_IPC_H + +#include "asm/arch/ipc.h" + +#endif Index: linux-2.4.29/include/asm-um/irq.h =================================================================== --- linux-2.4.29.orig/include/asm-um/irq.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/irq.h 2005-05-03 22:28:14.956336504 +0300 @@ -0,0 +1,23 @@ +#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 HUMFS_IRQ 14 + +#define LAST_IRQ HUMFS_IRQ +#define NR_IRQS (LAST_IRQ + 1) + +#endif Index: linux-2.4.29/include/asm-um/keyboard.h =================================================================== --- linux-2.4.29.orig/include/asm-um/keyboard.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/keyboard.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_KEYBOARD_H +#define __UM_KEYBOARD_H + +#include "asm/arch/keyboard.h" + +#endif Index: linux-2.4.29/include/asm-um/kmap_types.h =================================================================== --- linux-2.4.29.orig/include/asm-um/kmap_types.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/kmap_types.h 2005-05-03 22:28:14.957336352 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/linux_logo.h =================================================================== --- linux-2.4.29.orig/include/asm-um/linux_logo.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/linux_logo.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_LINUX_LOGO_H +#define __UM_LINUX_LOGO_H + +#include "asm/arch/linux_logo.h" + +#endif Index: linux-2.4.29/include/asm-um/locks.h =================================================================== --- linux-2.4.29.orig/include/asm-um/locks.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/locks.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_LOCKS_H +#define __UM_LOCKS_H + +#include "asm/arch/locks.h" + +#endif Index: linux-2.4.29/include/asm-um/mca_dma.h =================================================================== --- linux-2.4.29.orig/include/asm-um/mca_dma.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/mca_dma.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef mca___UM_DMA_H +#define mca___UM_DMA_H + +#include "asm/arch/mca_dma.h" + +#endif Index: linux-2.4.29/include/asm-um/mman.h =================================================================== --- linux-2.4.29.orig/include/asm-um/mman.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/mman.h 2005-05-03 22:28:14.961335744 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_MMAN_H +#define __UM_MMAN_H + +#include "asm/arch/mman.h" + +#endif Index: linux-2.4.29/include/asm-um/mmu_context.h =================================================================== --- linux-2.4.29.orig/include/asm-um/mmu_context.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/mmu_context.h 2005-05-03 23:41:09.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/mmu.h =================================================================== --- linux-2.4.29.orig/include/asm-um/mmu.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/mmu.h 2005-05-03 22:28:14.962335592 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/module.h =================================================================== --- linux-2.4.29.orig/include/asm-um/module.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/module.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_MODULE_H +#define __UM_MODULE_H + +#include "asm/arch/module.h" + +#endif Index: linux-2.4.29/include/asm-um/msgbuf.h =================================================================== --- linux-2.4.29.orig/include/asm-um/msgbuf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/msgbuf.h 2005-05-03 22:28:14.964335288 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_MSGBUF_H +#define __UM_MSGBUF_H + +#include "asm/arch/msgbuf.h" + +#endif Index: linux-2.4.29/include/asm-um/mtrr.h =================================================================== --- linux-2.4.29.orig/include/asm-um/mtrr.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/mtrr.h 2005-05-03 22:37:48.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_MTRR_H +#define __UM_MTRR_H + +#include "asm/arch/mtrr.h" + +#endif Index: linux-2.4.29/include/asm-um/namei.h =================================================================== --- linux-2.4.29.orig/include/asm-um/namei.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/namei.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_NAMEI_H +#define __UM_NAMEI_H + +#include "asm/arch/namei.h" + +#endif Index: linux-2.4.29/include/asm-um/page.h =================================================================== --- linux-2.4.29.orig/include/asm-um/page.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/page.h 2005-05-03 22:37:45.335625672 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/page_offset.h =================================================================== --- linux-2.4.29.orig/include/asm-um/page_offset.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/page_offset.h 2005-05-03 22:28:14.967334832 +0300 @@ -0,0 +1 @@ +#define PAGE_OFFSET_RAW (uml_physmem) Index: linux-2.4.29/include/asm-um/param.h =================================================================== --- linux-2.4.29.orig/include/asm-um/param.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/param.h 2005-05-03 22:28:14.968334680 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/pci.h =================================================================== --- linux-2.4.29.orig/include/asm-um/pci.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/pci.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_PCI_H +#define __UM_PCI_H + +#define PCI_DMA_BUS_IS_PHYS (1) + +#endif Index: linux-2.4.29/include/asm-um/pgalloc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/pgalloc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/pgalloc.h 2005-05-03 23:41:11.209044968 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/pgtable.h =================================================================== --- linux-2.4.29.orig/include/asm-um/pgtable.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/pgtable.h 2005-05-03 23:41:09.906243024 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/poll.h =================================================================== --- linux-2.4.29.orig/include/asm-um/poll.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/poll.h 2005-05-03 22:28:14.973333920 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_POLL_H +#define __UM_POLL_H + +#include "asm/arch/poll.h" + +#endif Index: linux-2.4.29/include/asm-um/posix_types.h =================================================================== --- linux-2.4.29.orig/include/asm-um/posix_types.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/posix_types.h 2005-05-03 22:28:14.974333768 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_POSIX_TYPES_H +#define __UM_POSIX_TYPES_H + +#include "asm/arch/posix_types.h" + +#endif Index: linux-2.4.29/include/asm-um/processor-generic.h =================================================================== --- linux-2.4.29.orig/include/asm-um/processor-generic.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/processor-generic.h 2005-05-03 23:41:08.094518448 +0300 @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.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; + int nsyscalls; + struct pt_regs regs; + unsigned long cr2; + int err; + unsigned long trap_no; + int singlestep_syscall; + 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; + /* XXX This is really two filehandles, but they contain + * lists, and list.h includes processor.h through + * prefetch.h before defining struct list, so this + * makes the lists' sizes unknown at this point. + * So, this is a void *, and allocated separately. + * Check to see if this is fixed in 2.6. + */ + void *switch_pipe; + 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, \ + .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: + */ Index: linux-2.4.29/include/asm-um/processor-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/processor-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/processor-i386.h 2005-05-03 23:41:08.095518296 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/processor-ppc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/processor-ppc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/processor-ppc.h 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/ptrace-generic.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ptrace-generic.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ptrace-generic.h 2005-05-03 23:41:08.084519968 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/ptrace-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ptrace-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ptrace-i386.h 2005-05-03 23:41:08.085519816 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/resource.h =================================================================== --- linux-2.4.29.orig/include/asm-um/resource.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/resource.h 2005-05-03 22:28:14.980332856 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_RESOURCE_H +#define __UM_RESOURCE_H + +#include "asm/arch/resource.h" + +#endif Index: linux-2.4.29/include/asm-um/rwlock.h =================================================================== --- linux-2.4.29.orig/include/asm-um/rwlock.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/rwlock.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_RWLOCK_H +#define __UM_RWLOCK_H + +#include "asm/arch/rwlock.h" + +#endif Index: linux-2.4.29/include/asm-um/rwsem.h =================================================================== --- linux-2.4.29.orig/include/asm-um/rwsem.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/rwsem.h 2005-05-03 23:41:08.109516168 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/scatterlist.h =================================================================== --- linux-2.4.29.orig/include/asm-um/scatterlist.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/scatterlist.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SCATTERLIST_H +#define __UM_SCATTERLIST_H + +#include "asm/arch/scatterlist.h" + +#endif Index: linux-2.4.29/include/asm-um/segment.h =================================================================== --- linux-2.4.29.orig/include/asm-um/segment.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/segment.h 2005-05-03 22:28:14.983332400 +0300 @@ -0,0 +1,4 @@ +#ifndef __UM_SEGMENT_H +#define __UM_SEGMENT_H + +#endif Index: linux-2.4.29/include/asm-um/semaphore.h =================================================================== --- linux-2.4.29.orig/include/asm-um/semaphore.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/semaphore.h 2005-05-03 23:41:08.110516016 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SEMAPHORE_H +#define __UM_SEMAPHORE_H + +#include "asm/arch/semaphore.h" + +#endif Index: linux-2.4.29/include/asm-um/sembuf.h =================================================================== --- linux-2.4.29.orig/include/asm-um/sembuf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/sembuf.h 2005-05-03 22:28:14.984332248 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SEMBUF_H +#define __UM_SEMBUF_H + +#include "asm/arch/sembuf.h" + +#endif Index: linux-2.4.29/include/asm-um/serial.h =================================================================== --- linux-2.4.29.orig/include/asm-um/serial.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/serial.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SERIAL_H +#define __UM_SERIAL_H + +#include "asm/arch/serial.h" + +#endif Index: linux-2.4.29/include/asm-um/shmbuf.h =================================================================== --- linux-2.4.29.orig/include/asm-um/shmbuf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/shmbuf.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SHMBUF_H +#define __UM_SHMBUF_H + +#include "asm/arch/shmbuf.h" + +#endif Index: linux-2.4.29/include/asm-um/shmparam.h =================================================================== --- linux-2.4.29.orig/include/asm-um/shmparam.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/shmparam.h 2005-05-03 22:28:14.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SHMPARAM_H +#define __UM_SHMPARAM_H + +#include "asm/arch/shmparam.h" + +#endif Index: linux-2.4.29/include/asm-um/sigcontext-generic.h =================================================================== --- linux-2.4.29.orig/include/asm-um/sigcontext-generic.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/sigcontext-generic.h 2005-05-03 22:28:14.987331792 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGCONTEXT_GENERIC_H +#define __UM_SIGCONTEXT_GENERIC_H + +#include "asm/arch/sigcontext.h" + +#endif Index: linux-2.4.29/include/asm-um/sigcontext-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/sigcontext-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/sigcontext-i386.h 2005-05-03 22:28:14.988331640 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGCONTEXT_I386_H +#define __UM_SIGCONTEXT_I386_H + +#include "asm/sigcontext-generic.h" + +#endif Index: linux-2.4.29/include/asm-um/sigcontext-ppc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/sigcontext-ppc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/sigcontext-ppc.h 2005-05-03 22:28:14.000000000 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/siginfo.h =================================================================== --- linux-2.4.29.orig/include/asm-um/siginfo.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/siginfo.h 2005-05-03 23:41:08.092518752 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SIGINFO_H +#define __UM_SIGINFO_H + +#include "asm/arch/siginfo.h" + +#endif Index: linux-2.4.29/include/asm-um/signal.h =================================================================== --- linux-2.4.29.orig/include/asm-um/signal.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/signal.h 2005-05-03 23:41:08.090519056 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/smp.h =================================================================== --- linux-2.4.29.orig/include/asm-um/smp.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/smp.h 2005-05-03 23:41:09.801258984 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/smplock.h =================================================================== --- linux-2.4.29.orig/include/asm-um/smplock.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/smplock.h 2005-05-03 23:41:09.912242112 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SMPLOCK_H +#define __UM_SMPLOCK_H + +#include "asm/arch/smplock.h" + +#endif Index: linux-2.4.29/include/asm-um/socket.h =================================================================== --- linux-2.4.29.orig/include/asm-um/socket.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/socket.h 2005-05-03 22:37:45.384618224 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SOCKET_H +#define __UM_SOCKET_H + +#include "asm/arch/socket.h" + +#endif Index: linux-2.4.29/include/asm-um/sockios.h =================================================================== --- linux-2.4.29.orig/include/asm-um/sockios.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/sockios.h 2005-05-03 22:28:14.994330728 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_SOCKIOS_H +#define __UM_SOCKIOS_H + +#include "asm/arch/sockios.h" + +#endif Index: linux-2.4.29/include/asm-um/softirq.h =================================================================== --- linux-2.4.29.orig/include/asm-um/softirq.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/softirq.h 2005-05-03 23:41:09.910242416 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/spinlock.h =================================================================== --- linux-2.4.29.orig/include/asm-um/spinlock.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/spinlock.h 2005-05-03 23:41:08.101517384 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/statfs.h =================================================================== --- linux-2.4.29.orig/include/asm-um/statfs.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/statfs.h 2005-05-03 23:41:08.104516928 +0300 @@ -0,0 +1,6 @@ +#ifndef _UM_STATFS_H +#define _UM_STATFS_H + +#include "asm/arch/statfs.h" + +#endif Index: linux-2.4.29/include/asm-um/stat.h =================================================================== --- linux-2.4.29.orig/include/asm-um/stat.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/stat.h 2005-05-03 22:28:14.997330272 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_STAT_H +#define __UM_STAT_H + +#include "asm/arch/stat.h" + +#endif Index: linux-2.4.29/include/asm-um/string.h =================================================================== --- linux-2.4.29.orig/include/asm-um/string.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/string.h 2005-05-03 22:28:14.998330120 +0300 @@ -0,0 +1,7 @@ +#ifndef __UM_STRING_H +#define __UM_STRING_H + +#include "asm/arch/string.h" +#include "asm/archparam.h" + +#endif Index: linux-2.4.29/include/asm-um/system-generic.h =================================================================== --- linux-2.4.29.orig/include/asm-um/system-generic.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/system-generic.h 2005-05-03 23:41:08.098517840 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/system-i386.h =================================================================== --- linux-2.4.29.orig/include/asm-um/system-i386.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/system-i386.h 2005-05-03 23:41:08.098517840 +0300 @@ -0,0 +1,8 @@ +#ifndef __UM_SYSTEM_I386_H +#define __UM_SYSTEM_I386_H + +#include "asm/system-generic.h" + +#define __HAVE_ARCH_CMPXCHG 1 + +#endif Index: linux-2.4.29/include/asm-um/system-ppc.h =================================================================== --- linux-2.4.29.orig/include/asm-um/system-ppc.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/system-ppc.h 2005-05-03 22:28:15.000000000 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/termbits.h =================================================================== --- linux-2.4.29.orig/include/asm-um/termbits.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/termbits.h 2005-05-03 22:37:45.506599680 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_TERMBITS_H +#define __UM_TERMBITS_H + +#include "asm/arch/termbits.h" + +#endif Index: linux-2.4.29/include/asm-um/termios.h =================================================================== --- linux-2.4.29.orig/include/asm-um/termios.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/termios.h 2005-05-03 22:37:45.512598768 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_TERMIOS_H +#define __UM_TERMIOS_H + +#include "asm/arch/termios.h" + +#endif Index: linux-2.4.29/include/asm-um/timex.h =================================================================== --- linux-2.4.29.orig/include/asm-um/timex.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/timex.h 2005-05-03 23:41:09.799259288 +0300 @@ -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 Index: linux-2.4.29/include/asm-um/tlb.h =================================================================== --- linux-2.4.29.orig/include/asm-um/tlb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/tlb.h 2005-05-03 22:28:15.000000000 +0300 @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> Index: linux-2.4.29/include/asm-um/types.h =================================================================== --- linux-2.4.29.orig/include/asm-um/types.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/types.h 2005-05-03 22:28:15.006328904 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_TYPES_H +#define __UM_TYPES_H + +#include "asm/arch/types.h" + +#endif Index: linux-2.4.29/include/asm-um/uaccess.h =================================================================== --- linux-2.4.29.orig/include/asm-um/uaccess.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/uaccess.h 2005-05-03 23:41:09.913241960 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/ucontext.h =================================================================== --- linux-2.4.29.orig/include/asm-um/ucontext.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/ucontext.h 2005-05-03 22:28:15.008328600 +0300 @@ -0,0 +1,6 @@ +#ifndef _ASM_UM_UCONTEXT_H +#define _ASM_UM_UCONTEXT_H + +#include "asm/arch/ucontext.h" + +#endif Index: linux-2.4.29/include/asm-um/unaligned.h =================================================================== --- linux-2.4.29.orig/include/asm-um/unaligned.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/unaligned.h 2005-05-03 22:28:15.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_UNALIGNED_H +#define __UM_UNALIGNED_H + +#include "asm/arch/unaligned.h" + +#endif Index: linux-2.4.29/include/asm-um/unistd.h =================================================================== --- linux-2.4.29.orig/include/asm-um/unistd.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/unistd.h 2005-05-03 23:41:11.206045424 +0300 @@ -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: + */ Index: linux-2.4.29/include/asm-um/user.h =================================================================== --- linux-2.4.29.orig/include/asm-um/user.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/user.h 2005-05-03 23:43:26.305507184 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_USER_H +#define __UM_USER_H + +#include "asm/arch/user.h" + +#endif Index: linux-2.4.29/include/asm-um/vga.h =================================================================== --- linux-2.4.29.orig/include/asm-um/vga.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/vga.h 2005-05-03 22:28:15.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_VGA_H +#define __UM_VGA_H + +#include "asm/arch/vga.h" + +#endif Index: linux-2.4.29/include/asm-um/xor.h =================================================================== --- linux-2.4.29.orig/include/asm-um/xor.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/asm-um/xor.h 2005-05-03 22:28:15.000000000 +0300 @@ -0,0 +1,6 @@ +#ifndef __UM_XOR_H +#define __UM_XOR_H + +#include "asm-generic/xor.h" + +#endif Index: linux-2.4.29/include/linux/blk.h =================================================================== --- linux-2.4.29.orig/include/linux/blk.h 2005-05-03 21:09:03.000000000 +0300 +++ linux-2.4.29/include/linux/blk.h 2005-05-03 23:41:26.547713136 +0300 @@ -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 Index: linux-2.4.29/include/linux/fs.h =================================================================== --- linux-2.4.29.orig/include/linux/fs.h 2005-05-03 21:06:01.000000000 +0300 +++ linux-2.4.29/include/linux/fs.h 2005-05-03 23:56:00.359873496 +0300 @@ -322,6 +322,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> @@ -518,7 +520,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; }; @@ -866,6 +870,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 *); Index: linux-2.4.29/include/linux/ghash.h =================================================================== --- linux-2.4.29.orig/include/linux/ghash.h 2005-05-03 21:09:50.000000000 +0300 +++ linux-2.4.29/include/linux/ghash.h 2005-05-03 22:28:15.000000000 +0300 @@ -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;\ } Index: linux-2.4.29/include/linux/hostfs_fs_i.h =================================================================== --- linux-2.4.29.orig/include/linux/hostfs_fs_i.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/linux/hostfs_fs_i.h 2005-05-03 22:28:15.053321760 +0300 @@ -0,0 +1,25 @@ +#ifndef _HOSTFS_FS_I +#define _HOSTFS_FS_I + +#include "filehandle.h" + +struct externfs_file_ops; + +struct hostfs_inode_info { + struct externfs_file_ops *ops; + struct file_handle *fh; + 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: + */ Index: linux-2.4.29/include/linux/hppfs_fs_i.h =================================================================== --- linux-2.4.29.orig/include/linux/hppfs_fs_i.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/linux/hppfs_fs_i.h 2005-05-03 22:28:15.054321608 +0300 @@ -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: + */ Index: linux-2.4.29/include/linux/kernel.h =================================================================== --- linux-2.4.29.orig/include/linux/kernel.h 2005-05-03 21:04:57.000000000 +0300 +++ linux-2.4.29/include/linux/kernel.h 2005-05-03 23:41:08.088519360 +0300 @@ -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))) #define fastcall __attribute__((regparm(3))) #else Index: linux-2.4.29/include/linux/kernel_stat.h =================================================================== --- linux-2.4.29.orig/include/linux/kernel_stat.h 2005-05-03 21:09:36.000000000 +0300 +++ linux-2.4.29/include/linux/kernel_stat.h 2005-05-03 23:41:09.913241960 +0300 @@ -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 { Index: linux-2.4.29/include/linux/mm.h =================================================================== --- linux-2.4.29.orig/include/linux/mm.h 2005-05-03 21:05:15.000000000 +0300 +++ linux-2.4.29/include/linux/mm.h 2005-05-03 23:55:59.724970016 +0300 @@ -441,6 +441,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) { /* @@ -448,7 +460,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) @@ -508,6 +520,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 @@ -555,9 +570,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, @@ -567,7 +583,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; } Index: linux-2.4.29/include/linux/proc_mm.h =================================================================== --- linux-2.4.29.orig/include/linux/proc_mm.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/include/linux/proc_mm.h 2005-05-03 23:46:00.225107848 +0300 @@ -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 Index: linux-2.4.29/include/linux/shmem_fs.h =================================================================== --- linux-2.4.29.orig/include/linux/shmem_fs.h 2005-05-03 21:09:04.000000000 +0300 +++ linux-2.4.29/include/linux/shmem_fs.h 2005-05-03 22:28:15.082317352 +0300 @@ -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; Index: linux-2.4.29/include/linux/tty.h =================================================================== --- linux-2.4.29.orig/include/linux/tty.h 2005-05-03 21:07:23.000000000 +0300 +++ linux-2.4.29/include/linux/tty.h 2005-05-03 23:41:09.901243784 +0300 @@ -310,6 +310,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 */ @@ -368,6 +371,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, @@ -434,5 +438,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 Index: linux-2.4.29/init/do_mounts.c =================================================================== --- linux-2.4.29.orig/init/do_mounts.c 2005-05-03 21:09:10.000000000 +0300 +++ linux-2.4.29/init/do_mounts.c 2005-05-03 22:28:15.000000000 +0300 @@ -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) }, Index: linux-2.4.29/kernel/panic.c =================================================================== --- linux-2.4.29.orig/kernel/panic.c 2005-05-03 21:09:35.000000000 +0300 +++ linux-2.4.29/kernel/panic.c 2005-05-03 22:28:15.000000000 +0300 @@ -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) { Index: linux-2.4.29/MAINTAINERS =================================================================== --- linux-2.4.29.orig/MAINTAINERS 2005-05-03 21:07:57.000000000 +0300 +++ linux-2.4.29/MAINTAINERS 2005-05-03 22:28:15.000000000 +0300 @@ -2120,6 +2120,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 Index: linux-2.4.29/Makefile =================================================================== --- linux-2.4.29.orig/Makefile 2005-05-03 21:08:14.000000000 +0300 +++ linux-2.4.29/Makefile 2005-05-03 22:28:15.000000000 +0300 @@ -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; \ Index: linux-2.4.29/mm/Makefile =================================================================== --- linux-2.4.29.orig/mm/Makefile 2005-05-03 21:08:06.000000000 +0300 +++ linux-2.4.29/mm/Makefile 2005-05-03 22:28:15.000000000 +0300 @@ -17,5 +17,6 @@ shmem.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_PROC_MM) += proc_mm.o include $(TOPDIR)/Rules.make Index: linux-2.4.29/mm/mmap.c =================================================================== --- linux-2.4.29.orig/mm/mmap.c 2005-05-03 21:07:59.000000000 +0300 +++ linux-2.4.29/mm/mmap.c 2005-05-03 22:28:15.000000000 +0300 @@ -391,10 +391,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; @@ -1000,6 +1001,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); /* Index: linux-2.4.29/mm/mprotect.c =================================================================== --- linux-2.4.29.orig/mm/mprotect.c 2005-05-03 21:06:44.000000000 +0300 +++ linux-2.4.29/mm/mprotect.c 2005-05-03 22:28:15.000000000 +0300 @@ -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)); +} Index: linux-2.4.29/mm/page_alloc.c =================================================================== --- linux-2.4.29.orig/mm/page_alloc.c 2005-05-03 21:05:16.000000000 +0300 +++ linux-2.4.29/mm/page_alloc.c 2005-05-03 22:28:15.000000000 +0300 @@ -116,6 +116,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 Index: linux-2.4.29/mm/proc_mm.c =================================================================== --- linux-2.4.29.orig/mm/proc_mm.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.29/mm/proc_mm.c 2005-05-03 22:28:15.000000000 +0300 @@ -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: + */ Index: linux-2.4.29/mm/shmem.c =================================================================== --- linux-2.4.29.orig/mm/shmem.c 2005-05-03 21:06:51.000000000 +0300 +++ linux-2.4.29/mm/shmem.c 2005-05-03 22:28:15.000000000 +0300 @@ -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)); } /* @@ -847,6 +862,7 @@ ops = &shmem_vm_ops; if (!S_ISREG(inode->i_mode)) return -EACCES; + UPDATE_ATIME(inode); vma->vm_ops = ops; return 0; @@ -1750,4 +1766,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, +};